mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
std.Build: separate errors from failed commands
Recording the command in a separate field will give the build runner more freedom to choose how and when the command should be printed.
This commit is contained in:
parent
e4456d03f3
commit
a388a8e5a7
5 changed files with 71 additions and 99 deletions
|
|
@ -1443,6 +1443,14 @@ pub fn printErrorMessages(
|
||||||
}
|
}
|
||||||
try stderr.writeAll("\n");
|
try stderr.writeAll("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (failing_step.result_failed_command) |cmd_str| {
|
||||||
|
try ttyconf.setColor(stderr, .red);
|
||||||
|
try stderr.writeAll("failed command: ");
|
||||||
|
try ttyconf.setColor(stderr, .reset);
|
||||||
|
try stderr.writeAll(cmd_str);
|
||||||
|
try stderr.writeByte('\n');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn printSteps(builder: *std.Build, w: *Writer) !void {
|
fn printSteps(builder: *std.Build, w: *Writer) !void {
|
||||||
|
|
|
||||||
|
|
@ -1594,20 +1594,6 @@ pub fn validateUserInputDidItFail(b: *Build) bool {
|
||||||
return b.invalid_user_input;
|
return b.invalid_user_input;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocPrintCmd(gpa: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) error{OutOfMemory}![]u8 {
|
|
||||||
var buf: ArrayList(u8) = .empty;
|
|
||||||
if (opt_cwd) |cwd| try buf.print(gpa, "cd {s} && ", .{cwd});
|
|
||||||
for (argv) |arg| {
|
|
||||||
try buf.print(gpa, "{s} ", .{arg});
|
|
||||||
}
|
|
||||||
return buf.toOwnedSlice(gpa);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn printCmd(ally: Allocator, cwd: ?[]const u8, argv: []const []const u8) void {
|
|
||||||
const text = allocPrintCmd(ally, cwd, argv) catch @panic("OOM");
|
|
||||||
std.debug.print("{s}\n", .{text});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This creates the install step and adds it to the dependencies of the
|
/// This creates the install step and adds it to the dependencies of the
|
||||||
/// top-level install step, using all the default options.
|
/// top-level install step, using all the default options.
|
||||||
/// See `addInstallArtifact` for a more flexible function.
|
/// See `addInstallArtifact` for a more flexible function.
|
||||||
|
|
@ -1857,14 +1843,14 @@ pub fn runAllowFail(
|
||||||
pub fn run(b: *Build, argv: []const []const u8) []u8 {
|
pub fn run(b: *Build, argv: []const []const u8) []u8 {
|
||||||
if (!process.can_spawn) {
|
if (!process.can_spawn) {
|
||||||
std.debug.print("unable to spawn the following command: cannot spawn child process\n{s}\n", .{
|
std.debug.print("unable to spawn the following command: cannot spawn child process\n{s}\n", .{
|
||||||
try allocPrintCmd(b.allocator, null, argv),
|
try Step.allocPrintCmd(b.allocator, null, argv),
|
||||||
});
|
});
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var code: u8 = undefined;
|
var code: u8 = undefined;
|
||||||
return b.runAllowFail(argv, &code, .Inherit) catch |err| {
|
return b.runAllowFail(argv, &code, .Inherit) catch |err| {
|
||||||
const printed_cmd = allocPrintCmd(b.allocator, null, argv) catch @panic("OOM");
|
const printed_cmd = Step.allocPrintCmd(b.allocator, null, argv) catch @panic("OOM");
|
||||||
std.debug.print("unable to spawn the following command: {s}\n{s}\n", .{
|
std.debug.print("unable to spawn the following command: {s}\n{s}\n", .{
|
||||||
@errorName(err), printed_cmd,
|
@errorName(err), printed_cmd,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,9 @@ result_cached: bool,
|
||||||
result_duration_ns: ?u64,
|
result_duration_ns: ?u64,
|
||||||
/// 0 means unavailable or not reported.
|
/// 0 means unavailable or not reported.
|
||||||
result_peak_rss: usize,
|
result_peak_rss: usize,
|
||||||
|
/// If the step is failed and this field is populated, this is the command which failed.
|
||||||
|
/// This field may be populated even if the step succeeded.
|
||||||
|
result_failed_command: ?[]const u8,
|
||||||
test_results: TestResults,
|
test_results: TestResults,
|
||||||
|
|
||||||
/// The return address associated with creation of this step that can be useful
|
/// The return address associated with creation of this step that can be useful
|
||||||
|
|
@ -257,6 +260,7 @@ pub fn init(options: StepOptions) Step {
|
||||||
.result_cached = false,
|
.result_cached = false,
|
||||||
.result_duration_ns = null,
|
.result_duration_ns = null,
|
||||||
.result_peak_rss = 0,
|
.result_peak_rss = 0,
|
||||||
|
.result_failed_command = null,
|
||||||
.test_results = .{},
|
.test_results = .{},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -336,20 +340,20 @@ pub fn dump(step: *Step, w: *std.Io.Writer, tty_config: std.Io.tty.Config) void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn evalChildProcess(s: *Step, argv: []const []const u8) ![]u8 {
|
/// Populates `s.result_failed_command`.
|
||||||
const run_result = try captureChildProcess(s, std.Progress.Node.none, argv);
|
|
||||||
try handleChildProcessTerm(s, run_result.term, null, argv);
|
|
||||||
return run_result.stdout;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn captureChildProcess(
|
pub fn captureChildProcess(
|
||||||
s: *Step,
|
s: *Step,
|
||||||
|
gpa: Allocator,
|
||||||
progress_node: std.Progress.Node,
|
progress_node: std.Progress.Node,
|
||||||
argv: []const []const u8,
|
argv: []const []const u8,
|
||||||
) !std.process.Child.RunResult {
|
) !std.process.Child.RunResult {
|
||||||
const arena = s.owner.allocator;
|
const arena = s.owner.allocator;
|
||||||
|
|
||||||
try handleChildProcUnsupported(s, null, argv);
|
// If an error occurs, it's happened in this command:
|
||||||
|
assert(s.result_failed_command == null);
|
||||||
|
s.result_failed_command = try allocPrintCmd(gpa, null, argv);
|
||||||
|
|
||||||
|
try handleChildProcUnsupported(s);
|
||||||
try handleVerbose(s.owner, null, argv);
|
try handleVerbose(s.owner, null, argv);
|
||||||
|
|
||||||
const result = std.process.Child.run(.{
|
const result = std.process.Child.run(.{
|
||||||
|
|
@ -386,6 +390,7 @@ pub const ZigProcess = struct {
|
||||||
|
|
||||||
/// Assumes that argv contains `--listen=-` and that the process being spawned
|
/// Assumes that argv contains `--listen=-` and that the process being spawned
|
||||||
/// is the zig compiler - the same version that compiled the build runner.
|
/// is the zig compiler - the same version that compiled the build runner.
|
||||||
|
/// Populates `s.result_failed_command`.
|
||||||
pub fn evalZigProcess(
|
pub fn evalZigProcess(
|
||||||
s: *Step,
|
s: *Step,
|
||||||
argv: []const []const u8,
|
argv: []const []const u8,
|
||||||
|
|
@ -394,6 +399,10 @@ pub fn evalZigProcess(
|
||||||
web_server: ?*Build.WebServer,
|
web_server: ?*Build.WebServer,
|
||||||
gpa: Allocator,
|
gpa: Allocator,
|
||||||
) !?Path {
|
) !?Path {
|
||||||
|
// If an error occurs, it's happened in this command:
|
||||||
|
assert(s.result_failed_command == null);
|
||||||
|
s.result_failed_command = try allocPrintCmd(gpa, null, argv);
|
||||||
|
|
||||||
if (s.getZigProcess()) |zp| update: {
|
if (s.getZigProcess()) |zp| update: {
|
||||||
assert(watch);
|
assert(watch);
|
||||||
if (std.Progress.have_ipc) if (zp.progress_ipc_fd) |fd| prog_node.setIpcFd(fd);
|
if (std.Progress.have_ipc) if (zp.progress_ipc_fd) |fd| prog_node.setIpcFd(fd);
|
||||||
|
|
@ -410,8 +419,9 @@ pub fn evalZigProcess(
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (s.result_error_bundle.errorMessageCount() > 0)
|
if (s.result_error_bundle.errorMessageCount() > 0) {
|
||||||
return s.fail("{d} compilation errors", .{s.result_error_bundle.errorMessageCount()});
|
return s.fail("{d} compilation errors", .{s.result_error_bundle.errorMessageCount()});
|
||||||
|
}
|
||||||
|
|
||||||
if (s.result_error_msgs.items.len > 0 and result == null) {
|
if (s.result_error_msgs.items.len > 0 and result == null) {
|
||||||
// Crash detected.
|
// Crash detected.
|
||||||
|
|
@ -420,7 +430,7 @@ pub fn evalZigProcess(
|
||||||
};
|
};
|
||||||
s.result_peak_rss = zp.child.resource_usage_statistics.getMaxRss() orelse 0;
|
s.result_peak_rss = zp.child.resource_usage_statistics.getMaxRss() orelse 0;
|
||||||
s.clearZigProcess(gpa);
|
s.clearZigProcess(gpa);
|
||||||
try handleChildProcessTerm(s, term, null, argv);
|
try handleChildProcessTerm(s, term);
|
||||||
return error.MakeFailed;
|
return error.MakeFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -430,7 +440,7 @@ pub fn evalZigProcess(
|
||||||
const b = s.owner;
|
const b = s.owner;
|
||||||
const arena = b.allocator;
|
const arena = b.allocator;
|
||||||
|
|
||||||
try handleChildProcUnsupported(s, null, argv);
|
try handleChildProcUnsupported(s);
|
||||||
try handleVerbose(s.owner, null, argv);
|
try handleVerbose(s.owner, null, argv);
|
||||||
|
|
||||||
var child = std.process.Child.init(argv, arena);
|
var child = std.process.Child.init(argv, arena);
|
||||||
|
|
@ -484,16 +494,11 @@ pub fn evalZigProcess(
|
||||||
else => {},
|
else => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
try handleChildProcessTerm(s, term, null, argv);
|
try handleChildProcessTerm(s, term);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is intentionally printed for failure on the first build but not for
|
|
||||||
// subsequent rebuilds.
|
|
||||||
if (s.result_error_bundle.errorMessageCount() > 0) {
|
if (s.result_error_bundle.errorMessageCount() > 0) {
|
||||||
return s.fail("the following command failed with {d} compilation errors:\n{s}", .{
|
return s.fail("{d} compilation errors", .{s.result_error_bundle.errorMessageCount()});
|
||||||
s.result_error_bundle.errorMessageCount(),
|
|
||||||
try allocPrintCmd(arena, null, argv),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -696,54 +701,38 @@ pub fn handleVerbose2(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn handleChildProcUnsupported(
|
/// Asserts that the caller has already populated `s.result_failed_command`.
|
||||||
s: *Step,
|
pub inline fn handleChildProcUnsupported(s: *Step) error{ OutOfMemory, MakeFailed }!void {
|
||||||
opt_cwd: ?[]const u8,
|
|
||||||
argv: []const []const u8,
|
|
||||||
) error{ OutOfMemory, MakeFailed }!void {
|
|
||||||
if (!std.process.can_spawn) {
|
if (!std.process.can_spawn) {
|
||||||
return s.fail(
|
return s.fail("unable to spawn process: host cannot spawn child processes", .{});
|
||||||
"unable to execute the following command: host cannot spawn child processes\n{s}",
|
|
||||||
.{try allocPrintCmd(s.owner.allocator, opt_cwd, argv)},
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handleChildProcessTerm(
|
/// Asserts that the caller has already populated `s.result_failed_command`.
|
||||||
s: *Step,
|
pub fn handleChildProcessTerm(s: *Step, term: std.process.Child.Term) error{ MakeFailed, OutOfMemory }!void {
|
||||||
term: std.process.Child.Term,
|
assert(s.result_failed_command != null);
|
||||||
opt_cwd: ?[]const u8,
|
|
||||||
argv: []const []const u8,
|
|
||||||
) error{ MakeFailed, OutOfMemory }!void {
|
|
||||||
const arena = s.owner.allocator;
|
|
||||||
switch (term) {
|
switch (term) {
|
||||||
.Exited => |code| {
|
.Exited => |code| {
|
||||||
if (code != 0) {
|
if (code != 0) {
|
||||||
return s.fail(
|
return s.fail("process exited with error code {d}", .{code});
|
||||||
"the following command exited with error code {d}:\n{s}",
|
|
||||||
.{ code, try allocPrintCmd(arena, opt_cwd, argv) },
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.Signal, .Stopped, .Unknown => {
|
.Signal, .Stopped, .Unknown => {
|
||||||
return s.fail(
|
return s.fail("process terminated unexpectedly", .{});
|
||||||
"the following command terminated unexpectedly:\n{s}",
|
|
||||||
.{try allocPrintCmd(arena, opt_cwd, argv)},
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocPrintCmd(
|
pub fn allocPrintCmd(
|
||||||
arena: Allocator,
|
gpa: Allocator,
|
||||||
opt_cwd: ?[]const u8,
|
opt_cwd: ?[]const u8,
|
||||||
argv: []const []const u8,
|
argv: []const []const u8,
|
||||||
) Allocator.Error![]u8 {
|
) Allocator.Error![]u8 {
|
||||||
return allocPrintCmd2(arena, opt_cwd, null, argv);
|
return allocPrintCmd2(gpa, opt_cwd, null, argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocPrintCmd2(
|
pub fn allocPrintCmd2(
|
||||||
arena: Allocator,
|
gpa: Allocator,
|
||||||
opt_cwd: ?[]const u8,
|
opt_cwd: ?[]const u8,
|
||||||
opt_env: ?*const std.process.EnvMap,
|
opt_env: ?*const std.process.EnvMap,
|
||||||
argv: []const []const u8,
|
argv: []const []const u8,
|
||||||
|
|
@ -783,11 +772,13 @@ pub fn allocPrintCmd2(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var aw: std.Io.Writer.Allocating = .init(arena);
|
var aw: std.Io.Writer.Allocating = .init(gpa);
|
||||||
|
defer aw.deinit();
|
||||||
const writer = &aw.writer;
|
const writer = &aw.writer;
|
||||||
if (opt_cwd) |cwd| writer.print("cd {s} && ", .{cwd}) catch return error.OutOfMemory;
|
if (opt_cwd) |cwd| writer.print("cd {s} && ", .{cwd}) catch return error.OutOfMemory;
|
||||||
if (opt_env) |env| {
|
if (opt_env) |env| {
|
||||||
const process_env_map = std.process.getEnvMap(arena) catch std.process.EnvMap.init(arena);
|
var process_env_map = std.process.getEnvMap(gpa) catch std.process.EnvMap.init(gpa);
|
||||||
|
defer process_env_map.deinit();
|
||||||
var it = env.iterator();
|
var it = env.iterator();
|
||||||
while (it.next()) |entry| {
|
while (it.next()) |entry| {
|
||||||
const key = entry.key_ptr.*;
|
const key = entry.key_ptr.*;
|
||||||
|
|
@ -973,11 +964,14 @@ fn addWatchInputFromPath(step: *Step, path: Build.Cache.Path, basename: []const
|
||||||
pub fn reset(step: *Step, gpa: Allocator) void {
|
pub fn reset(step: *Step, gpa: Allocator) void {
|
||||||
assert(step.state == .precheck_done);
|
assert(step.state == .precheck_done);
|
||||||
|
|
||||||
|
if (step.result_failed_command) |cmd| gpa.free(cmd);
|
||||||
|
|
||||||
step.result_error_msgs.clearRetainingCapacity();
|
step.result_error_msgs.clearRetainingCapacity();
|
||||||
step.result_stderr = "";
|
step.result_stderr = "";
|
||||||
step.result_cached = false;
|
step.result_cached = false;
|
||||||
step.result_duration_ns = null;
|
step.result_duration_ns = null;
|
||||||
step.result_peak_rss = 0;
|
step.result_peak_rss = 0;
|
||||||
|
step.result_failed_command = null;
|
||||||
step.test_results = .{};
|
step.test_results = .{};
|
||||||
|
|
||||||
step.result_error_bundle.deinit(gpa);
|
step.result_error_bundle.deinit(gpa);
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
|
||||||
argv.appendAssumeCapacity(b.pathFromRoot(p));
|
argv.appendAssumeCapacity(b.pathFromRoot(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
const run_result = try step.captureChildProcess(prog_node, argv.items);
|
const run_result = try step.captureChildProcess(options.gpa, prog_node, argv.items);
|
||||||
if (fmt.check) switch (run_result.term) {
|
if (fmt.check) switch (run_result.term) {
|
||||||
.Exited => |code| if (code != 0 and run_result.stdout.len != 0) {
|
.Exited => |code| if (code != 0 and run_result.stdout.len != 0) {
|
||||||
var it = std.mem.tokenizeScalar(u8, run_result.stdout, '\n');
|
var it = std.mem.tokenizeScalar(u8, run_result.stdout, '\n');
|
||||||
|
|
@ -77,5 +77,5 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
|
||||||
},
|
},
|
||||||
else => {},
|
else => {},
|
||||||
};
|
};
|
||||||
try step.handleChildProcessTerm(run_result.term, null, argv.items);
|
try step.handleChildProcessTerm(run_result.term);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1212,10 +1212,11 @@ fn runCommand(
|
||||||
const step = &run.step;
|
const step = &run.step;
|
||||||
const b = step.owner;
|
const b = step.owner;
|
||||||
const arena = b.allocator;
|
const arena = b.allocator;
|
||||||
|
const gpa = options.gpa;
|
||||||
|
|
||||||
const cwd: ?[]const u8 = if (run.cwd) |lazy_cwd| lazy_cwd.getPath2(b, step) else null;
|
const cwd: ?[]const u8 = if (run.cwd) |lazy_cwd| lazy_cwd.getPath2(b, step) else null;
|
||||||
|
|
||||||
try step.handleChildProcUnsupported(cwd, argv);
|
try step.handleChildProcUnsupported();
|
||||||
try Step.handleVerbose2(step.owner, cwd, run.env_map, argv);
|
try Step.handleVerbose2(step.owner, cwd, run.env_map, argv);
|
||||||
|
|
||||||
const allow_skip = switch (run.stdio) {
|
const allow_skip = switch (run.stdio) {
|
||||||
|
|
@ -1365,6 +1366,8 @@ fn runCommand(
|
||||||
run.addPathForDynLibs(exe);
|
run.addPathForDynLibs(exe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpa.free(step.result_failed_command.?);
|
||||||
|
step.result_failed_command = null;
|
||||||
try Step.handleVerbose2(step.owner, cwd, run.env_map, interp_argv.items);
|
try Step.handleVerbose2(step.owner, cwd, run.env_map, interp_argv.items);
|
||||||
|
|
||||||
break :term spawnChildAndCollect(run, interp_argv.items, env_map, has_side_effects, options, fuzz_context) catch |e| {
|
break :term spawnChildAndCollect(run, interp_argv.items, env_map, has_side_effects, options, fuzz_context) catch |e| {
|
||||||
|
|
@ -1380,18 +1383,11 @@ fn runCommand(
|
||||||
return step.fail("failed to spawn and capture stdio from {s}: {s}", .{ argv[0], @errorName(err) });
|
return step.fail("failed to spawn and capture stdio from {s}: {s}", .{ argv[0], @errorName(err) });
|
||||||
};
|
};
|
||||||
|
|
||||||
const final_argv = if (interp_argv.items.len == 0) argv else interp_argv.items;
|
|
||||||
|
|
||||||
const generic_result = opt_generic_result orelse {
|
const generic_result = opt_generic_result orelse {
|
||||||
assert(run.stdio == .zig_test);
|
assert(run.stdio == .zig_test);
|
||||||
// Specific errors have already been reported. All we need to do is detect those and
|
// Specific errors have already been reported, and test results are populated. All we need
|
||||||
// report the general "test failed" error, which includes the command argv.
|
// to do is report step failure if any test failed.
|
||||||
if (!step.test_results.isSuccess() or step.result_error_msgs.items.len > 0) {
|
if (!step.test_results.isSuccess()) return error.MakeFailed;
|
||||||
return step.fail(
|
|
||||||
"the following test command failed:\n{s}",
|
|
||||||
.{try Step.allocPrintCmd(arena, cwd, final_argv)},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -1445,93 +1441,77 @@ fn runCommand(
|
||||||
.expect_stderr_exact => |expected_bytes| {
|
.expect_stderr_exact => |expected_bytes| {
|
||||||
if (!mem.eql(u8, expected_bytes, generic_result.stderr.?)) {
|
if (!mem.eql(u8, expected_bytes, generic_result.stderr.?)) {
|
||||||
return step.fail(
|
return step.fail(
|
||||||
\\
|
|
||||||
\\========= expected this stderr: =========
|
\\========= expected this stderr: =========
|
||||||
\\{s}
|
\\{s}
|
||||||
\\========= but found: ====================
|
\\========= but found: ====================
|
||||||
\\{s}
|
\\{s}
|
||||||
\\========= from the following command: ===
|
|
||||||
\\{s}
|
|
||||||
, .{
|
, .{
|
||||||
expected_bytes,
|
expected_bytes,
|
||||||
generic_result.stderr.?,
|
generic_result.stderr.?,
|
||||||
try Step.allocPrintCmd(arena, cwd, final_argv),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.expect_stderr_match => |match| {
|
.expect_stderr_match => |match| {
|
||||||
if (mem.indexOf(u8, generic_result.stderr.?, match) == null) {
|
if (mem.indexOf(u8, generic_result.stderr.?, match) == null) {
|
||||||
return step.fail(
|
return step.fail(
|
||||||
\\
|
|
||||||
\\========= expected to find in stderr: =========
|
\\========= expected to find in stderr: =========
|
||||||
\\{s}
|
\\{s}
|
||||||
\\========= but stderr does not contain it: =====
|
\\========= but stderr does not contain it: =====
|
||||||
\\{s}
|
\\{s}
|
||||||
\\========= from the following command: =========
|
|
||||||
\\{s}
|
|
||||||
, .{
|
, .{
|
||||||
match,
|
match,
|
||||||
generic_result.stderr.?,
|
generic_result.stderr.?,
|
||||||
try Step.allocPrintCmd(arena, cwd, final_argv),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.expect_stdout_exact => |expected_bytes| {
|
.expect_stdout_exact => |expected_bytes| {
|
||||||
if (!mem.eql(u8, expected_bytes, generic_result.stdout.?)) {
|
if (!mem.eql(u8, expected_bytes, generic_result.stdout.?)) {
|
||||||
return step.fail(
|
return step.fail(
|
||||||
\\
|
|
||||||
\\========= expected this stdout: =========
|
\\========= expected this stdout: =========
|
||||||
\\{s}
|
\\{s}
|
||||||
\\========= but found: ====================
|
\\========= but found: ====================
|
||||||
\\{s}
|
\\{s}
|
||||||
\\========= from the following command: ===
|
|
||||||
\\{s}
|
|
||||||
, .{
|
, .{
|
||||||
expected_bytes,
|
expected_bytes,
|
||||||
generic_result.stdout.?,
|
generic_result.stdout.?,
|
||||||
try Step.allocPrintCmd(arena, cwd, final_argv),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.expect_stdout_match => |match| {
|
.expect_stdout_match => |match| {
|
||||||
if (mem.indexOf(u8, generic_result.stdout.?, match) == null) {
|
if (mem.indexOf(u8, generic_result.stdout.?, match) == null) {
|
||||||
return step.fail(
|
return step.fail(
|
||||||
\\
|
|
||||||
\\========= expected to find in stdout: =========
|
\\========= expected to find in stdout: =========
|
||||||
\\{s}
|
\\{s}
|
||||||
\\========= but stdout does not contain it: =====
|
\\========= but stdout does not contain it: =====
|
||||||
\\{s}
|
\\{s}
|
||||||
\\========= from the following command: =========
|
|
||||||
\\{s}
|
|
||||||
, .{
|
, .{
|
||||||
match,
|
match,
|
||||||
generic_result.stdout.?,
|
generic_result.stdout.?,
|
||||||
try Step.allocPrintCmd(arena, cwd, final_argv),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.expect_term => |expected_term| {
|
.expect_term => |expected_term| {
|
||||||
if (!termMatches(expected_term, generic_result.term)) {
|
if (!termMatches(expected_term, generic_result.term)) {
|
||||||
return step.fail("the following command {f} (expected {f}):\n{s}", .{
|
return step.fail("process {f} (expected {f})", .{
|
||||||
fmtTerm(generic_result.term),
|
fmtTerm(generic_result.term),
|
||||||
fmtTerm(expected_term),
|
fmtTerm(expected_term),
|
||||||
try Step.allocPrintCmd(arena, cwd, final_argv),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
// On failure, print stderr if captured.
|
// On failure, report captured stderr like normal standard error output.
|
||||||
const bad_exit = switch (generic_result.term) {
|
const bad_exit = switch (generic_result.term) {
|
||||||
.Exited => |code| code != 0,
|
.Exited => |code| code != 0,
|
||||||
.Signal, .Stopped, .Unknown => true,
|
.Signal, .Stopped, .Unknown => true,
|
||||||
};
|
};
|
||||||
|
if (bad_exit) {
|
||||||
|
if (generic_result.stderr) |bytes| {
|
||||||
|
run.step.result_stderr = bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (bad_exit) if (generic_result.stderr) |err| {
|
try step.handleChildProcessTerm(generic_result.term);
|
||||||
try step.addError("stderr:\n{s}", .{err});
|
|
||||||
};
|
|
||||||
|
|
||||||
try step.handleChildProcessTerm(generic_result.term, cwd, final_argv);
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1594,6 +1574,10 @@ fn spawnChildAndCollect(
|
||||||
child.stdin_behavior = .Pipe;
|
child.stdin_behavior = .Pipe;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If an error occurs, it's caused by this command:
|
||||||
|
assert(run.step.result_failed_command == null);
|
||||||
|
run.step.result_failed_command = try Step.allocPrintCmd(options.gpa, child.cwd, argv);
|
||||||
|
|
||||||
if (run.stdio == .zig_test) {
|
if (run.stdio == .zig_test) {
|
||||||
var timer = try std.time.Timer.start();
|
var timer = try std.time.Timer.start();
|
||||||
const res = try evalZigTest(run, &child, options, fuzz_context);
|
const res = try evalZigTest(run, &child, options, fuzz_context);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue