feat: return all subprocess errors as term messages
This commit is contained in:
parent
e44e6ed306
commit
9df7beb192
2 changed files with 48 additions and 42 deletions
|
@ -130,18 +130,15 @@ const Proc = struct {
|
|||
fn start(self: *Proc) tp.result {
|
||||
errdefer self.deinit();
|
||||
|
||||
self.child.spawn() catch |e| {
|
||||
try self.parent.send(.{ self.tag, "term", e, 1 });
|
||||
return tp.exit_normal();
|
||||
};
|
||||
self.child.spawn() catch |e| return self.handle_error(e);
|
||||
_ = self.args.reset(.free_all);
|
||||
|
||||
if (self.child.stdin_behavior == .Pipe)
|
||||
self.fd_stdin = tp.file_descriptor.init("stdin", self.child.stdin.?.handle) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
self.fd_stdout = tp.file_descriptor.init("stdout", self.child.stdout.?.handle) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
self.fd_stderr = tp.file_descriptor.init("stderr", self.child.stderr.?.handle) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
if (self.fd_stdout) |fd_stdout| fd_stdout.wait_read() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
if (self.fd_stderr) |fd_stderr| fd_stderr.wait_read() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
self.fd_stdin = tp.file_descriptor.init("stdin", self.child.stdin.?.handle) catch |e| return self.handle_error(e);
|
||||
self.fd_stdout = tp.file_descriptor.init("stdout", self.child.stdout.?.handle) catch |e| return self.handle_error(e);
|
||||
self.fd_stderr = tp.file_descriptor.init("stderr", self.child.stderr.?.handle) catch |e| return self.handle_error(e);
|
||||
if (self.fd_stdout) |fd_stdout| fd_stdout.wait_read() catch |e| return self.handle_error(e);
|
||||
if (self.fd_stderr) |fd_stderr| fd_stderr.wait_read() catch |e| return self.handle_error(e);
|
||||
|
||||
tp.receive(&self.receiver);
|
||||
}
|
||||
|
@ -153,22 +150,22 @@ const Proc = struct {
|
|||
var err_msg: []u8 = "";
|
||||
if (try m.match(.{ "fd", "stdout", "read_ready" })) {
|
||||
try self.dispatch_stdout();
|
||||
if (self.fd_stdout) |fd_stdout| fd_stdout.wait_read() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
if (self.fd_stdout) |fd_stdout| fd_stdout.wait_read() catch |e| return self.handle_error(e);
|
||||
} else if (try m.match(.{ "fd", "stderr", "read_ready" })) {
|
||||
try self.dispatch_stderr();
|
||||
if (self.fd_stderr) |fd_stderr| fd_stderr.wait_read() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
if (self.fd_stderr) |fd_stderr| fd_stderr.wait_read() catch |e| return self.handle_error(e);
|
||||
} else if (try m.match(.{ "fd", "stdin", "write_ready" })) {
|
||||
if (self.stdin_buffer.items.len > 0) {
|
||||
if (self.child.stdin) |stdin| {
|
||||
const written = stdin.write(self.stdin_buffer.items) catch |e| switch (e) {
|
||||
error.WouldBlock => {
|
||||
if (self.fd_stdin) |fd_stdin| {
|
||||
fd_stdin.wait_write() catch |e_| return tp.exit_error(e_, @errorReturnTrace());
|
||||
fd_stdin.wait_write() catch |e_| return self.handle_error(e_);
|
||||
self.write_pending = true;
|
||||
return;
|
||||
} else return tp.exit_error(error.WouldBlock, @errorReturnTrace());
|
||||
} else return self.handle_error(error.WouldBlock);
|
||||
},
|
||||
else => return tp.exit_error(e, @errorReturnTrace()),
|
||||
else => return self.handle_error(e),
|
||||
};
|
||||
self.write_pending = false;
|
||||
defer {
|
||||
|
@ -181,7 +178,7 @@ const Proc = struct {
|
|||
std.mem.copyForwards(u8, self.stdin_buffer.items, self.stdin_buffer.items[written..]);
|
||||
self.stdin_buffer.items.len = self.stdin_buffer.items.len - written;
|
||||
if (self.fd_stdin) |fd_stdin| {
|
||||
fd_stdin.wait_write() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
fd_stdin.wait_write() catch |e| return self.handle_error(e);
|
||||
self.write_pending = true;
|
||||
}
|
||||
}
|
||||
|
@ -189,8 +186,8 @@ const Proc = struct {
|
|||
}
|
||||
} else if (try m.match(.{ "stdin", tp.extract(&bytes) })) {
|
||||
if (self.fd_stdin) |fd_stdin| {
|
||||
self.stdin_buffer.appendSlice(bytes) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
fd_stdin.wait_write() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
self.stdin_buffer.appendSlice(bytes) catch |e| return self.handle_error(e);
|
||||
fd_stdin.wait_write() catch |e| return self.handle_error(e);
|
||||
self.write_pending = true;
|
||||
}
|
||||
} else if (try m.match(.{"stdin_close"})) {
|
||||
|
@ -210,10 +207,11 @@ const Proc = struct {
|
|||
self.child.stderr = null;
|
||||
}
|
||||
} else if (try m.match(.{"term"})) {
|
||||
const term_ = self.child.kill() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
const term_ = self.child.kill() catch |e| return self.handle_error(e);
|
||||
return self.handle_term(term_);
|
||||
} else if (try m.match(.{ "fd", tp.any, "read_error", tp.extract(&err), tp.extract(&err_msg) })) {
|
||||
return tp.exit(err_msg);
|
||||
try self.parent.send(.{ self.tag, "term", err_msg, 1 });
|
||||
return tp.exit_normal();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -227,10 +225,10 @@ const Proc = struct {
|
|||
|
||||
fn dispatch_stdout(self: *Proc) tp.result {
|
||||
var buffer: [max_chunk_size]u8 = undefined;
|
||||
const stdout = self.child.stdout orelse return tp.exit("cannot read closed stdout");
|
||||
const stdout = self.child.stdout orelse return self.handle_error(error.ReadNoStdout);
|
||||
const bytes = stdout.read(&buffer) catch |e| switch (e) {
|
||||
error.WouldBlock => return,
|
||||
else => return tp.exit_error(e, @errorReturnTrace()),
|
||||
else => return self.handle_error(e),
|
||||
};
|
||||
if (bytes == 0)
|
||||
return self.handle_terminate();
|
||||
|
@ -239,21 +237,21 @@ const Proc = struct {
|
|||
|
||||
fn dispatch_stderr(self: *Proc) tp.result {
|
||||
var buffer: [max_chunk_size]u8 = undefined;
|
||||
const stderr = self.child.stderr orelse return tp.exit("cannot read closed stderr");
|
||||
const stderr = self.child.stderr orelse return self.handle_error(error.ReadNoStderr);
|
||||
const bytes = stderr.read(&buffer) catch |e| switch (e) {
|
||||
error.WouldBlock => return,
|
||||
else => return tp.exit_error(e, @errorReturnTrace()),
|
||||
else => return self.handle_error(e),
|
||||
};
|
||||
if (bytes == 0)
|
||||
return;
|
||||
try self.parent.send(.{ self.tag, "stderr", buffer[0..bytes] });
|
||||
}
|
||||
|
||||
fn handle_terminate(self: *Proc) tp.result {
|
||||
return self.handle_term(self.child.wait() catch |e| return tp.exit_error(e, @errorReturnTrace()));
|
||||
fn handle_terminate(self: *Proc) error{Exit} {
|
||||
return self.handle_term(self.child.wait() catch |e| return self.handle_error(e));
|
||||
}
|
||||
|
||||
fn handle_term(self: *Proc, term_: std.process.Child.Term) tp.result {
|
||||
fn handle_term(self: *Proc, term_: std.process.Child.Term) error{Exit} {
|
||||
(switch (term_) {
|
||||
.Exited => |val| self.parent.send(.{ self.tag, "term", "exited", val }),
|
||||
.Signal => |val| self.parent.send(.{ self.tag, "term", "signal", val }),
|
||||
|
@ -262,4 +260,9 @@ const Proc = struct {
|
|||
}) catch {};
|
||||
return tp.exit_normal();
|
||||
}
|
||||
|
||||
fn handle_error(self: *Proc, e: anyerror) error{Exit} {
|
||||
try self.parent.send(.{ self.tag, "term", e, 1 });
|
||||
return tp.exit_normal();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -123,16 +123,13 @@ const Proc = struct {
|
|||
fn start(self: *Proc) tp.result {
|
||||
errdefer self.deinit();
|
||||
|
||||
self.child.spawn() catch |e| {
|
||||
try self.parent.send(.{ self.tag, "term", e, 1 });
|
||||
return tp.exit_normal();
|
||||
};
|
||||
self.child.spawn() catch |e| return self.handle_error(e);
|
||||
_ = self.args.reset(.free_all);
|
||||
|
||||
self.stream_stdout = tp.file_stream.init("stdout", self.child.stdout.?.handle) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
self.stream_stderr = tp.file_stream.init("stderr", self.child.stderr.?.handle) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
if (self.stream_stdout) |stream| stream.start_read() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
if (self.stream_stderr) |stream| stream.start_read() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
self.stream_stdout = tp.file_stream.init("stdout", self.child.stdout.?.handle) catch |e| return self.handle_error(e);
|
||||
self.stream_stderr = tp.file_stream.init("stderr", self.child.stderr.?.handle) catch |e| return self.handle_error(e);
|
||||
if (self.stream_stdout) |stream| stream.start_read() catch |e| return self.handle_error(e);
|
||||
if (self.stream_stderr) |stream| stream.start_read() catch |e| return self.handle_error(e);
|
||||
|
||||
tp.receive(&self.receiver);
|
||||
}
|
||||
|
@ -145,10 +142,10 @@ const Proc = struct {
|
|||
var err_msg: []u8 = "";
|
||||
if (try m.match(.{ "stream", "stdout", "read_complete", tp.extract(&bytes) })) {
|
||||
try self.dispatch_stdout(bytes);
|
||||
if (self.stream_stdout) |stream| stream.start_read() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
if (self.stream_stdout) |stream| stream.start_read() catch |e| return self.handle_error(e);
|
||||
} else if (try m.match(.{ "stream", "stderr", "read_complete", tp.extract(&bytes) })) {
|
||||
try self.dispatch_stderr(bytes);
|
||||
if (self.stream_stderr) |stream| stream.start_read() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
if (self.stream_stderr) |stream| stream.start_read() catch |e| return self.handle_error(e);
|
||||
} else if (try m.match(.{ "stdin", tp.extract(&bytes) })) {
|
||||
try self.start_write(bytes);
|
||||
} else if (try m.match(.{"stdin_close"})) {
|
||||
|
@ -164,7 +161,7 @@ const Proc = struct {
|
|||
self.child.stderr = null;
|
||||
}
|
||||
} else if (try m.match(.{"term"})) {
|
||||
const term_ = self.child.kill() catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
const term_ = self.child.kill() catch |e| return self.handle_error(e);
|
||||
return self.handle_term(term_);
|
||||
} else if (try m.match(.{ "stream", "stdout", "read_error", 109, tp.extract(&err_msg) })) {
|
||||
// stdout closed
|
||||
|
@ -174,13 +171,14 @@ const Proc = struct {
|
|||
// stderr closed
|
||||
self.child.stderr = null;
|
||||
} else if (try m.match(.{ "stream", tp.extract(&stream_name), "read_error", tp.extract(&err), tp.extract(&err_msg) })) {
|
||||
return tp.exit_fmt("{s} read_error: {s}", .{ stream_name, err_msg });
|
||||
try self.parent.send(.{ self.tag, "term", err_msg, 1 });
|
||||
return tp.exit_normal();
|
||||
}
|
||||
}
|
||||
|
||||
fn start_write(self: *Proc, bytes: []const u8) tp.result {
|
||||
if (self.child.stdin) |stdin|
|
||||
stdin.writeAll(bytes) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||
stdin.writeAll(bytes) catch |e| return self.handle_error(e);
|
||||
}
|
||||
|
||||
fn stdin_close(self: *Proc) void {
|
||||
|
@ -203,11 +201,11 @@ const Proc = struct {
|
|||
try self.parent.send(.{ self.tag, "stderr", bytes });
|
||||
}
|
||||
|
||||
fn handle_terminate(self: *Proc) tp.result {
|
||||
return self.handle_term(self.child.wait() catch |e| return tp.exit_error(e, @errorReturnTrace()));
|
||||
fn handle_terminate(self: *Proc) error{Exit} {
|
||||
return self.handle_term(self.child.wait() catch |e| return self.handle_error(e));
|
||||
}
|
||||
|
||||
fn handle_term(self: *Proc, term_: std.process.Child.Term) tp.result {
|
||||
fn handle_term(self: *Proc, term_: std.process.Child.Term) error{Exit} {
|
||||
(switch (term_) {
|
||||
.Exited => |val| self.parent.send(.{ self.tag, "term", "exited", val }),
|
||||
.Signal => |val| self.parent.send(.{ self.tag, "term", "signal", val }),
|
||||
|
@ -216,4 +214,9 @@ const Proc = struct {
|
|||
}) catch {};
|
||||
return tp.exit_normal();
|
||||
}
|
||||
|
||||
fn handle_error(self: *Proc, e: anyerror) error{Exit} {
|
||||
try self.parent.send(.{ self.tag, "term", e, 1 });
|
||||
return tp.exit_normal();
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue