Spawns a child process, waits for it, collecting stdout and stderr, and then returns. If it succeeds, the caller owns result.stdout and result.stderr memory.
pub fn run(gpa: Allocator, io: Io, options: RunOptions) RunError!RunResult
pub fn run(gpa: Allocator, io: Io, options: RunOptions) RunError!RunResult {
var child = try spawn(io, .{
.argv = options.argv,
.cwd = options.cwd,
.environ_map = options.environ_map,
.expand_arg0 = options.expand_arg0,
.progress_node = options.progress_node,
.create_no_window = options.create_no_window,
.disable_aslr = options.disable_aslr,
.stdin = .ignore,
.stdout = .pipe,
.stderr = .pipe,
});
defer child.kill(io);
var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined;
var multi_reader: Io.File.MultiReader = undefined;
multi_reader.init(gpa, io, multi_reader_buffer.toStreams(), &.{ child.stdout.?, child.stderr.? });
defer multi_reader.deinit();
const stdout_reader = multi_reader.reader(0);
const stderr_reader = multi_reader.reader(1);
while (multi_reader.fill(options.reserve_amount, options.timeout)) |_| {
if (options.stdout_limit.toInt()) |limit| {
if (stdout_reader.buffered().len > limit)
return error.StreamTooLong;
}
if (options.stderr_limit.toInt()) |limit| {
if (stderr_reader.buffered().len > limit)
return error.StreamTooLong;
}
} else |err| switch (err) {
error.EndOfStream => {},
else => |e| return e,
}
try multi_reader.checkAnyError();
const term = try child.wait(io);
const stdout_slice = try multi_reader.toOwnedSlice(0);
errdefer gpa.free(stdout_slice);
const stderr_slice = try multi_reader.toOwnedSlice(1);
errdefer gpa.free(stderr_slice);
return .{
.stdout = stdout_slice,
.stderr = stderr_slice,
.term = term,
};
}