Uses arena to allocate the result.
fn evalGeneric(
arena: Allocator,
run_index: Configuration.Step.Index,
maker: *Maker,
spawn_options: process.SpawnOptions,
) !EvalGenericResult
fn evalGeneric(
arena: Allocator,
run_index: Configuration.Step.Index,
maker: *Maker,
spawn_options: process.SpawnOptions,
) !EvalGenericResult {
const graph = maker.graph;
const io = graph.io;
const conf = &maker.scanned_config.configuration;
const conf_step = run_index.ptr(conf);
const conf_run = conf_step.extended.get(conf.extra).run;
const step = maker.stepByIndex(run_index);
var child = try process.spawn(io, spawn_options);
defer child.kill(io);
switch (conf_run.stdin.u) {
.bytes => |bytes| {
child.stdin.?.writeStreamingAll(io, bytes.slice(conf)) catch |err| {
return step.fail(maker, "failed to write stdin: {t}", .{err});
};
child.stdin.?.close(io);
child.stdin = null;
},
.lazy_path => |lazy_path| {
const path = try maker.resolveLazyPathIndex(arena, lazy_path, run_index);
const file = path.root_dir.handle.openFile(io, path.subPathOrDot(), .{}) catch |err| {
return step.fail(maker, "failed to open stdin file: {t}", .{err});
};
defer file.close(io);
// TODO https://github.com/ziglang/zig/issues/23955
var read_buffer: [1024]u8 = undefined;
var file_reader = file.reader(io, &read_buffer);
var write_buffer: [1024]u8 = undefined;
var stdin_writer = child.stdin.?.writerStreaming(io, &write_buffer);
_ = stdin_writer.interface.sendFileAll(&file_reader, .unlimited) catch |err| switch (err) {
error.ReadFailed => return step.fail(maker, "failed to read from {f}: {t}", .{
path, file_reader.err.?,
}),
error.WriteFailed => return step.fail(maker, "failed to write to stdin: {t}", .{
stdin_writer.err.?,
}),
};
stdin_writer.interface.flush() catch |err| switch (err) {
error.WriteFailed => return step.fail(maker, "failed to write to stdin: {t}", .{
stdin_writer.err.?,
}),
};
child.stdin.?.close(io);
child.stdin = null;
},
.none => {},
}
var stdout_bytes: ?[]const u8 = null;
var stderr_bytes: ?[]const u8 = null;
if (child.stdout) |stdout| {
if (child.stderr) |stderr| {
var multi_reader_buffer: Io.File.MultiReader.Buffer(2) = undefined;
var multi_reader: Io.File.MultiReader = undefined;
multi_reader.init(arena, io, multi_reader_buffer.toStreams(), &.{ stdout, stderr });
const stdout_reader = multi_reader.reader(0);
const stderr_reader = multi_reader.reader(1);
while (multi_reader.fill(64, .none)) |_| {
if (conf_run.stdio_limit.value) |limit| {
if (stdout_reader.buffered().len > limit)
return error.StdoutStreamTooLong;
if (stderr_reader.buffered().len > limit)
return error.StderrStreamTooLong;
}
} else |err| switch (err) {
error.Timeout => unreachable,
error.EndOfStream => {},
else => |e| return e,
}
try multi_reader.checkAnyError();
stdout_bytes = multi_reader.reader(0).buffered();
stderr_bytes = multi_reader.reader(1).buffered();
} else {
var stdout_reader = stdout.readerStreaming(io, &.{});
const stdio_limit: Io.Limit = if (conf_run.stdio_limit.value) |x| .limited64(x) else .unlimited;
stdout_bytes = stdout_reader.interface.allocRemaining(arena, stdio_limit) catch |err| switch (err) {
error.OutOfMemory => |e| return e,
error.ReadFailed => return stdout_reader.err.?,
error.StreamTooLong => return error.StdoutStreamTooLong,
};
}
} else if (child.stderr) |stderr| {
var stderr_reader = stderr.readerStreaming(io, &.{});
const stdio_limit: Io.Limit = if (conf_run.stdio_limit.value) |x| .limited64(x) else .unlimited;
stderr_bytes = stderr_reader.interface.allocRemaining(arena, stdio_limit) catch |err| switch (err) {
error.OutOfMemory => |e| return e,
error.ReadFailed => return stderr_reader.err.?,
error.StreamTooLong => return error.StderrStreamTooLong,
};
}
if (stderr_bytes) |bytes| if (bytes.len > 0) {
// Treat stderr as an error message.
const stderr_is_diagnostic = conf_run.captured_stderr.value == null and switch (conf_run.flags.stdio) {
.check => !checksContainStderr(&conf_run),
else => true,
};
if (stderr_is_diagnostic) {
try step.setResultStderr(maker.gpa, bytes);
}
};
step.result_peak_rss = child.resource_usage_statistics.getMaxRss() orelse 0;
return .{
.term = try child.wait(io),
.stdout = stdout_bytes,
.stderr = stderr_bytes,
};
}