app: Use std.process.Child instead of POSIX calls

This commit is contained in:
pablo 2023-04-10 08:59:17 +02:00 committed by Stephen Gutekanst
parent e620d8f759
commit 5d06c618f1

View file

@ -34,13 +34,15 @@ const Status = union(enum) {
}; };
pub fn run(self: *Builder) !void { pub fn run(self: *Builder) !void {
var child = try self.runZigBuild(.Inherit);
switch (try child.wait()) {
.Exited => |code| {
if (code != 0) std.os.exit(code);
},
else => std.os.exit(1),
}
if (self.serve) { if (self.serve) {
const child_pid = try std.os.fork();
if (child_pid == 0) try self.exec();
const wait_res = std.os.waitpid(child_pid, 0);
if (wait_res.status != 0) std.os.exit(1);
var out_dir = std.fs.cwd().openIterableDir(out_dir_path, .{}) catch |err| { var out_dir = std.fs.cwd().openIterableDir(out_dir_path, .{}) catch |err| {
std.log.err("cannot open '{s}': {s}", .{ out_dir_path, @errorName(err) }); std.log.err("cannot open '{s}': {s}", .{ out_dir_path, @errorName(err) });
std.os.exit(1); std.os.exit(1);
@ -88,48 +90,46 @@ pub fn run(self: *Builder) !void {
const conn = try server.accept(); const conn = try server.accept();
try pool.spawn(handleConn, .{ self, conn }); try pool.spawn(handleConn, .{ self, conn });
} }
} else {
try self.exec();
} }
} }
fn exec(self: Builder) !void { fn runZigBuild(self: Builder, stderr_behavior: std.process.Child.StdIo) !std.process.Child {
var arena = std.heap.ArenaAllocator.init(allocator); var args_arena = std.heap.ArenaAllocator.init(allocator);
defer arena.deinit(); defer args_arena.deinit();
const argv = try self.buildArgs(arena.allocator());
return std.os.execvpeZ( const args = try self.buildArgs(args_arena.allocator());
argv[0].?,
@ptrCast([*:null]const ?[*:0]const u8, argv), var child = std.process.Child.init(args, allocator);
@ptrCast([*:null]const ?[*:0]const u8, std.os.environ.ptr), child.stderr_behavior = stderr_behavior;
);
try child.spawn();
return child;
} }
fn buildArgs(self: Builder, arena: std.mem.Allocator) ![*:null]const ?[*:0]const u8 { fn buildArgs(self: Builder, arena: std.mem.Allocator) ![]const []const u8 {
var argv = std.ArrayList(?[*:0]const u8).init(arena); var argv = std.ArrayList([]const u8).init(arena);
try argv.ensureTotalCapacity(self.steps.len + self.zig_build_args.len + 7); try argv.ensureTotalCapacity(self.steps.len + self.zig_build_args.len + 6);
argv.appendAssumeCapacity(try arena.dupeZ(u8, self.zig_path)); argv.appendAssumeCapacity(try arena.dupe(u8, self.zig_path));
argv.appendAssumeCapacity("build"); argv.appendAssumeCapacity("build");
for (self.steps) |step| { for (self.steps) |step| {
argv.appendAssumeCapacity(try arena.dupeZ(u8, step)); argv.appendAssumeCapacity(try arena.dupe(u8, step));
} }
argv.appendAssumeCapacity("--color"); argv.appendAssumeCapacity("--color");
argv.appendAssumeCapacity("on"); argv.appendAssumeCapacity("on");
argv.appendAssumeCapacity(try std.fmt.allocPrintZ(arena, "-Doptimize={s}", .{@tagName(self.optimize)})); argv.appendAssumeCapacity(try std.fmt.allocPrint(arena, "-Doptimize={s}", .{@tagName(self.optimize)}));
if (self.target) |target| { if (self.target) |target| {
argv.appendAssumeCapacity(try std.fmt.allocPrintZ(arena, "-Dtarget={s}", .{try target.toZigTriple()})); argv.appendAssumeCapacity(try std.fmt.allocPrint(arena, "-Dtarget={s}", .{try target.toZigTriple()}));
} }
for (self.zig_build_args) |arg| { for (self.zig_build_args) |arg| {
argv.appendAssumeCapacity(try arena.dupeZ(u8, arg)); argv.appendAssumeCapacity(try arena.dupe(u8, arg));
} }
argv.appendAssumeCapacity(null); return try argv.toOwnedSlice();
return @ptrCast([*:null]const ?[*:0]const u8, try argv.toOwnedSlice());
} }
fn watch(self: *Builder) void { fn watch(self: *Builder) void {
@ -319,40 +319,29 @@ fn notify(self: *Builder, stream: std.net.Stream) void {
fn compile(self: *Builder) void { fn compile(self: *Builder) void {
std.log.info("building...", .{}); std.log.info("building...", .{});
var pipes = std.os.pipe() catch unreachable; var child = self.runZigBuild(.Pipe) catch unreachable;
const child_pid = std.os.fork() catch unreachable;
if (child_pid == 0) { const stderr = child.stderr.?.reader().readAllAlloc(
std.os.close(pipes[0]); allocator,
std.os.dup2(pipes[1], std.os.STDERR_FILENO) catch @panic("OOM"); std.math.maxInt(usize),
std.os.close(pipes[1]); ) catch @panic("OOM");
return self.exec() catch unreachable;
}
std.os.close(pipes[1]);
const wait_result = std.os.waitpid(child_pid, 0);
const stderr_file = std.fs.File{ .handle = pipes[0] };
const stderr = stderr_file.reader().readAllAlloc(allocator, std.math.maxInt(usize)) catch @panic("OOM");
std.io.getStdErr().writeAll(stderr) catch unreachable; std.io.getStdErr().writeAll(stderr) catch unreachable;
switch (wait_result.status) { const term = child.wait() catch unreachable;
0 => { if (term == .Exited and term.Exited == 0) {
allocator.free(stderr); allocator.free(stderr);
self.status = .built; self.status = .built;
std.log.info("built", .{}); std.log.info("built", .{});
}, } else if (term == .Exited and term.Exited == 1) {
1 => { std.log.warn("compile error", .{});
std.log.warn("compile error", .{}); self.status = .{ .compile_error = stderr };
self.status = .{ .compile_error = stderr }; } else {
}, allocator.free(stderr);
else => { self.status = .stopped;
allocator.free(stderr); std.log.warn("the build process has stopped unexpectedly", .{});
self.status = .stopped;
std.log.warn("the build process has stopped unexpectedly", .{});
},
} }
for (self.subscribers.items) |sub| { for (self.subscribers.items) |sub| {
self.notify(sub); self.notify(sub);
} }