summaryrefslogtreecommitdiff
path: root/build.zig
diff options
context:
space:
mode:
Diffstat (limited to 'build.zig')
-rw-r--r--build.zig36
1 files changed, 32 insertions, 4 deletions
diff --git a/build.zig b/build.zig
index 083be94..b9d0a18 100644
--- a/build.zig
+++ b/build.zig
@@ -1361,6 +1361,34 @@ fn readImage(step: *std.Build.Step, gpa: std.mem.Allocator, path: std.Build.Lazy
return step.fail("{s} is not a usable image: {s}", .{ p, @errorName(err) });
}
+/// Fail a step that could not open the serial port, and for the one error that is always the same
+/// mistake, say what to do about it.
+///
+/// `AccessDenied` is the first thing anyone hits: the device is owned by a group (uucp on Arch,
+/// dialout on Debian) and the account is not in it. The subtlety worth printing is the SECOND half -
+/// adding the group with `usermod -aG` does not affect any shell that is already running, because
+/// credentials are captured at login. That produces exactly this error from a user who has already
+/// "fixed" it, which is a genuinely confusing place to be.
+fn failPort(step: *std.Build.Step, port: []const u8, err: anyerror) anyerror {
+ if (err != error.AccessDenied) return step.fail("cannot open {s}: {s}", .{ port, @errorName(err) });
+ return step.fail(
+ \\cannot open {s}: AccessDenied
+ \\
+ \\ {s} is owned by a group your session is not in (uucp on Arch, dialout on Debian):
+ \\ ls -l {s}
+ \\
+ \\ If you are NOT in that group yet, join it and log in again:
+ \\ sudo usermod -aG uucp $USER
+ \\
+ \\ If `id -nG` already lists it, this shell simply predates the change - group membership
+ \\ is captured at login. Either log out and back in, or take it in this shell:
+ \\ newgrp uucp
+ \\
+ \\ Or run one command with the group, without touching this shell at all:
+ \\ sg uucp -c 'zig build ... '
+ , .{ port, port, port });
+}
+
const FlashStep = struct {
step: std.Build.Step,
bin: std.Build.LazyPath,
@@ -1402,7 +1430,7 @@ const FlashStep = struct {
defer port_lock.unlock(b.graph.io);
var port = serial.Port.open(self.port, self.baud) catch |err|
- return step.fail("cannot open {s}: {s}", .{ self.port, @errorName(err) });
+ return failPort(step, self.port, err);
defer port.close();
const t_open = port.nowMs();
@@ -1476,7 +1504,7 @@ const MonitorStep = struct {
defer port_lock.unlock(b.graph.io);
var port = serial.Port.open(self.port, .b115200) catch |err|
- return step.fail("cannot open {s}: {s}", .{ self.port, @errorName(err) });
+ return failPort(step, self.port, err);
defer port.close();
port.resetToRun(.{}) catch {};
@@ -1525,7 +1553,7 @@ const ConsoleStep = struct {
defer port_lock.unlock(b.graph.io);
console.attach(self.port, self.baud, .{}) catch |err|
- return step.fail("console on {s}: {s}", .{ self.port, @errorName(err) });
+ return failPort(step, self.port, err);
}
};
@@ -1550,7 +1578,7 @@ const ResetStep = struct {
port_lock.lockUncancelable(b.graph.io);
defer port_lock.unlock(b.graph.io);
var port = serial.Port.open(self.port, .b115200) catch |err|
- return step.fail("cannot open {s}: {s}", .{ self.port, @errorName(err) });
+ return failPort(step, self.port, err);
defer port.close();
port.resetToRun(.{}) catch |err| return step.fail("reset failed: {s}", .{@errorName(err)});
}