mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
fix build runner
This commit is contained in:
parent
ec3b5f0c74
commit
cce32bd1d5
8 changed files with 253 additions and 250 deletions
|
|
@ -12,6 +12,7 @@ const Watch = std.Build.Watch;
|
|||
const Fuzz = std.Build.Fuzz;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const fatal = std.process.fatal;
|
||||
const Writer = std.io.Writer;
|
||||
const runner = @This();
|
||||
|
||||
pub const root = @import("@build");
|
||||
|
|
@ -330,7 +331,7 @@ pub fn main() !void {
|
|||
}
|
||||
}
|
||||
|
||||
const stderr = std.fs.File.stderr();
|
||||
const stderr: std.fs.File = .stderr();
|
||||
const ttyconf = get_tty_conf(color, stderr);
|
||||
switch (ttyconf) {
|
||||
.no_color => try graph.env_map.put("NO_COLOR", "1"),
|
||||
|
|
@ -378,13 +379,19 @@ pub fn main() !void {
|
|||
|
||||
validateSystemLibraryOptions(builder);
|
||||
|
||||
const stdout_writer = std.fs.File.stdout().deprecatedWriter();
|
||||
if (help_menu) {
|
||||
var w = initStdoutWriter();
|
||||
printUsage(builder, w) catch return stdout_writer_allocation.err.?;
|
||||
w.flush() catch return stdout_writer_allocation.err.?;
|
||||
return;
|
||||
}
|
||||
|
||||
if (help_menu)
|
||||
return usage(builder, stdout_writer);
|
||||
|
||||
if (steps_menu)
|
||||
return steps(builder, stdout_writer);
|
||||
if (steps_menu) {
|
||||
var w = initStdoutWriter();
|
||||
printSteps(builder, w) catch return stdout_writer_allocation.err.?;
|
||||
w.flush() catch return stdout_writer_allocation.err.?;
|
||||
return;
|
||||
}
|
||||
|
||||
var run: Run = .{
|
||||
.max_rss = max_rss,
|
||||
|
|
@ -696,24 +703,21 @@ fn runStepNames(
|
|||
const ttyconf = run.ttyconf;
|
||||
|
||||
if (run.summary != .none) {
|
||||
std.debug.lockStdErr();
|
||||
defer std.debug.unlockStdErr();
|
||||
const stderr = run.stderr;
|
||||
const w = std.debug.lockStderrWriter(&stdio_buffer_allocation);
|
||||
defer std.debug.unlockStderrWriter();
|
||||
|
||||
const total_count = success_count + failure_count + pending_count + skipped_count;
|
||||
ttyconf.setColor(stderr, .cyan) catch {};
|
||||
stderr.writeAll("Build Summary:") catch {};
|
||||
ttyconf.setColor(stderr, .reset) catch {};
|
||||
stderr.deprecatedWriter().print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
|
||||
if (skipped_count > 0) stderr.deprecatedWriter().print("; {d} skipped", .{skipped_count}) catch {};
|
||||
if (failure_count > 0) stderr.deprecatedWriter().print("; {d} failed", .{failure_count}) catch {};
|
||||
ttyconf.setColor(w, .cyan) catch {};
|
||||
w.writeAll("Build Summary:") catch {};
|
||||
ttyconf.setColor(w, .reset) catch {};
|
||||
w.print(" {d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
|
||||
if (skipped_count > 0) w.print("; {d} skipped", .{skipped_count}) catch {};
|
||||
if (failure_count > 0) w.print("; {d} failed", .{failure_count}) catch {};
|
||||
|
||||
if (test_count > 0) stderr.deprecatedWriter().print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
|
||||
if (test_skip_count > 0) stderr.deprecatedWriter().print("; {d} skipped", .{test_skip_count}) catch {};
|
||||
if (test_fail_count > 0) stderr.deprecatedWriter().print("; {d} failed", .{test_fail_count}) catch {};
|
||||
if (test_leak_count > 0) stderr.deprecatedWriter().print("; {d} leaked", .{test_leak_count}) catch {};
|
||||
|
||||
stderr.writeAll("\n") catch {};
|
||||
if (test_count > 0) w.print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
|
||||
if (test_skip_count > 0) w.print("; {d} skipped", .{test_skip_count}) catch {};
|
||||
if (test_fail_count > 0) w.print("; {d} failed", .{test_fail_count}) catch {};
|
||||
if (test_leak_count > 0) w.print("; {d} leaked", .{test_leak_count}) catch {};
|
||||
|
||||
// Print a fancy tree with build results.
|
||||
var step_stack_copy = try step_stack.clone(gpa);
|
||||
|
|
@ -722,7 +726,7 @@ fn runStepNames(
|
|||
var print_node: PrintNode = .{ .parent = null };
|
||||
if (step_names.len == 0) {
|
||||
print_node.last = true;
|
||||
printTreeStep(b, b.default_step, run, stderr, ttyconf, &print_node, &step_stack_copy) catch {};
|
||||
printTreeStep(b, b.default_step, run, w, ttyconf, &print_node, &step_stack_copy) catch {};
|
||||
} else {
|
||||
const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: {
|
||||
var i: usize = step_names.len;
|
||||
|
|
@ -741,9 +745,10 @@ fn runStepNames(
|
|||
for (step_names, 0..) |step_name, i| {
|
||||
const tls = b.top_level_steps.get(step_name).?;
|
||||
print_node.last = i + 1 == last_index;
|
||||
printTreeStep(b, &tls.step, run, stderr, ttyconf, &print_node, &step_stack_copy) catch {};
|
||||
printTreeStep(b, &tls.step, run, w, ttyconf, &print_node, &step_stack_copy) catch {};
|
||||
}
|
||||
}
|
||||
w.writeByte('\n') catch {};
|
||||
}
|
||||
|
||||
if (failure_count == 0) {
|
||||
|
|
@ -775,7 +780,7 @@ const PrintNode = struct {
|
|||
last: bool = false,
|
||||
};
|
||||
|
||||
fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void {
|
||||
fn printPrefix(node: *PrintNode, stderr: *Writer, ttyconf: std.io.tty.Config) !void {
|
||||
const parent = node.parent orelse return;
|
||||
if (parent.parent == null) return;
|
||||
try printPrefix(parent, stderr, ttyconf);
|
||||
|
|
@ -789,7 +794,7 @@ fn printPrefix(node: *PrintNode, stderr: File, ttyconf: std.io.tty.Config) !void
|
|||
}
|
||||
}
|
||||
|
||||
fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void {
|
||||
fn printChildNodePrefix(stderr: *Writer, ttyconf: std.io.tty.Config) !void {
|
||||
try stderr.writeAll(switch (ttyconf) {
|
||||
.no_color, .windows_api => "+- ",
|
||||
.escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
|
||||
|
|
@ -798,7 +803,7 @@ fn printChildNodePrefix(stderr: File, ttyconf: std.io.tty.Config) !void {
|
|||
|
||||
fn printStepStatus(
|
||||
s: *Step,
|
||||
stderr: File,
|
||||
stderr: *Writer,
|
||||
ttyconf: std.io.tty.Config,
|
||||
run: *const Run,
|
||||
) !void {
|
||||
|
|
@ -820,10 +825,10 @@ fn printStepStatus(
|
|||
try stderr.writeAll(" cached");
|
||||
} else if (s.test_results.test_count > 0) {
|
||||
const pass_count = s.test_results.passCount();
|
||||
try stderr.deprecatedWriter().print(" {d} passed", .{pass_count});
|
||||
try stderr.print(" {d} passed", .{pass_count});
|
||||
if (s.test_results.skip_count > 0) {
|
||||
try ttyconf.setColor(stderr, .yellow);
|
||||
try stderr.deprecatedWriter().print(" {d} skipped", .{s.test_results.skip_count});
|
||||
try stderr.print(" {d} skipped", .{s.test_results.skip_count});
|
||||
}
|
||||
} else {
|
||||
try stderr.writeAll(" success");
|
||||
|
|
@ -832,15 +837,15 @@ fn printStepStatus(
|
|||
if (s.result_duration_ns) |ns| {
|
||||
try ttyconf.setColor(stderr, .dim);
|
||||
if (ns >= std.time.ns_per_min) {
|
||||
try stderr.deprecatedWriter().print(" {d}m", .{ns / std.time.ns_per_min});
|
||||
try stderr.print(" {d}m", .{ns / std.time.ns_per_min});
|
||||
} else if (ns >= std.time.ns_per_s) {
|
||||
try stderr.deprecatedWriter().print(" {d}s", .{ns / std.time.ns_per_s});
|
||||
try stderr.print(" {d}s", .{ns / std.time.ns_per_s});
|
||||
} else if (ns >= std.time.ns_per_ms) {
|
||||
try stderr.deprecatedWriter().print(" {d}ms", .{ns / std.time.ns_per_ms});
|
||||
try stderr.print(" {d}ms", .{ns / std.time.ns_per_ms});
|
||||
} else if (ns >= std.time.ns_per_us) {
|
||||
try stderr.deprecatedWriter().print(" {d}us", .{ns / std.time.ns_per_us});
|
||||
try stderr.print(" {d}us", .{ns / std.time.ns_per_us});
|
||||
} else {
|
||||
try stderr.deprecatedWriter().print(" {d}ns", .{ns});
|
||||
try stderr.print(" {d}ns", .{ns});
|
||||
}
|
||||
try ttyconf.setColor(stderr, .reset);
|
||||
}
|
||||
|
|
@ -848,13 +853,13 @@ fn printStepStatus(
|
|||
const rss = s.result_peak_rss;
|
||||
try ttyconf.setColor(stderr, .dim);
|
||||
if (rss >= 1000_000_000) {
|
||||
try stderr.deprecatedWriter().print(" MaxRSS:{d}G", .{rss / 1000_000_000});
|
||||
try stderr.print(" MaxRSS:{d}G", .{rss / 1000_000_000});
|
||||
} else if (rss >= 1000_000) {
|
||||
try stderr.deprecatedWriter().print(" MaxRSS:{d}M", .{rss / 1000_000});
|
||||
try stderr.print(" MaxRSS:{d}M", .{rss / 1000_000});
|
||||
} else if (rss >= 1000) {
|
||||
try stderr.deprecatedWriter().print(" MaxRSS:{d}K", .{rss / 1000});
|
||||
try stderr.print(" MaxRSS:{d}K", .{rss / 1000});
|
||||
} else {
|
||||
try stderr.deprecatedWriter().print(" MaxRSS:{d}B", .{rss});
|
||||
try stderr.print(" MaxRSS:{d}B", .{rss});
|
||||
}
|
||||
try ttyconf.setColor(stderr, .reset);
|
||||
}
|
||||
|
|
@ -866,7 +871,7 @@ fn printStepStatus(
|
|||
if (skip == .skipped_oom) {
|
||||
try stderr.writeAll(" (not enough memory)");
|
||||
try ttyconf.setColor(stderr, .dim);
|
||||
try stderr.deprecatedWriter().print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
|
||||
try stderr.print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
|
||||
try ttyconf.setColor(stderr, .yellow);
|
||||
}
|
||||
try stderr.writeAll("\n");
|
||||
|
|
@ -878,23 +883,23 @@ fn printStepStatus(
|
|||
|
||||
fn printStepFailure(
|
||||
s: *Step,
|
||||
stderr: File,
|
||||
stderr: *Writer,
|
||||
ttyconf: std.io.tty.Config,
|
||||
) !void {
|
||||
if (s.result_error_bundle.errorMessageCount() > 0) {
|
||||
try ttyconf.setColor(stderr, .red);
|
||||
try stderr.deprecatedWriter().print(" {d} errors\n", .{
|
||||
try stderr.print(" {d} errors\n", .{
|
||||
s.result_error_bundle.errorMessageCount(),
|
||||
});
|
||||
try ttyconf.setColor(stderr, .reset);
|
||||
} else if (!s.test_results.isSuccess()) {
|
||||
try stderr.deprecatedWriter().print(" {d}/{d} passed", .{
|
||||
try stderr.print(" {d}/{d} passed", .{
|
||||
s.test_results.passCount(), s.test_results.test_count,
|
||||
});
|
||||
if (s.test_results.fail_count > 0) {
|
||||
try stderr.writeAll(", ");
|
||||
try ttyconf.setColor(stderr, .red);
|
||||
try stderr.deprecatedWriter().print("{d} failed", .{
|
||||
try stderr.print("{d} failed", .{
|
||||
s.test_results.fail_count,
|
||||
});
|
||||
try ttyconf.setColor(stderr, .reset);
|
||||
|
|
@ -902,7 +907,7 @@ fn printStepFailure(
|
|||
if (s.test_results.skip_count > 0) {
|
||||
try stderr.writeAll(", ");
|
||||
try ttyconf.setColor(stderr, .yellow);
|
||||
try stderr.deprecatedWriter().print("{d} skipped", .{
|
||||
try stderr.print("{d} skipped", .{
|
||||
s.test_results.skip_count,
|
||||
});
|
||||
try ttyconf.setColor(stderr, .reset);
|
||||
|
|
@ -910,7 +915,7 @@ fn printStepFailure(
|
|||
if (s.test_results.leak_count > 0) {
|
||||
try stderr.writeAll(", ");
|
||||
try ttyconf.setColor(stderr, .red);
|
||||
try stderr.deprecatedWriter().print("{d} leaked", .{
|
||||
try stderr.print("{d} leaked", .{
|
||||
s.test_results.leak_count,
|
||||
});
|
||||
try ttyconf.setColor(stderr, .reset);
|
||||
|
|
@ -932,7 +937,7 @@ fn printTreeStep(
|
|||
b: *std.Build,
|
||||
s: *Step,
|
||||
run: *const Run,
|
||||
stderr: File,
|
||||
stderr: *Writer,
|
||||
ttyconf: std.io.tty.Config,
|
||||
parent_node: *PrintNode,
|
||||
step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
|
||||
|
|
@ -992,7 +997,7 @@ fn printTreeStep(
|
|||
if (s.dependencies.items.len == 0) {
|
||||
try stderr.writeAll(" (reused)\n");
|
||||
} else {
|
||||
try stderr.deprecatedWriter().print(" (+{d} more reused dependencies)\n", .{
|
||||
try stderr.print(" (+{d} more reused dependencies)\n", .{
|
||||
s.dependencies.items.len,
|
||||
});
|
||||
}
|
||||
|
|
@ -1129,11 +1134,11 @@ fn workerMakeOneStep(
|
|||
const show_stderr = s.result_stderr.len > 0;
|
||||
|
||||
if (show_error_msgs or show_compile_errors or show_stderr) {
|
||||
std.debug.lockStdErr();
|
||||
defer std.debug.unlockStdErr();
|
||||
const bw = std.debug.lockStderrWriter(&stdio_buffer_allocation);
|
||||
defer std.debug.unlockStderrWriter();
|
||||
|
||||
const gpa = b.allocator;
|
||||
printErrorMessages(gpa, s, .{ .ttyconf = run.ttyconf }, run.stderr, run.prominent_compile_errors) catch {};
|
||||
printErrorMessages(gpa, s, .{ .ttyconf = run.ttyconf }, bw, run.prominent_compile_errors) catch {};
|
||||
}
|
||||
|
||||
handle_result: {
|
||||
|
|
@ -1190,7 +1195,7 @@ pub fn printErrorMessages(
|
|||
gpa: Allocator,
|
||||
failing_step: *Step,
|
||||
options: std.zig.ErrorBundle.RenderOptions,
|
||||
stderr: File,
|
||||
stderr: *Writer,
|
||||
prominent_compile_errors: bool,
|
||||
) !void {
|
||||
// Provide context for where these error messages are coming from by
|
||||
|
|
@ -1209,7 +1214,7 @@ pub fn printErrorMessages(
|
|||
var indent: usize = 0;
|
||||
while (step_stack.pop()) |s| : (indent += 1) {
|
||||
if (indent > 0) {
|
||||
try stderr.deprecatedWriter().writeByteNTimes(' ', (indent - 1) * 3);
|
||||
try stderr.splatByteAll(' ', (indent - 1) * 3);
|
||||
try printChildNodePrefix(stderr, ttyconf);
|
||||
}
|
||||
|
||||
|
|
@ -1231,7 +1236,7 @@ pub fn printErrorMessages(
|
|||
}
|
||||
|
||||
if (!prominent_compile_errors and failing_step.result_error_bundle.errorMessageCount() > 0) {
|
||||
try failing_step.result_error_bundle.renderToWriter(options, stderr.deprecatedWriter());
|
||||
try failing_step.result_error_bundle.renderToWriter(options, stderr);
|
||||
}
|
||||
|
||||
for (failing_step.result_error_msgs.items) |msg| {
|
||||
|
|
@ -1243,27 +1248,27 @@ pub fn printErrorMessages(
|
|||
}
|
||||
}
|
||||
|
||||
fn steps(builder: *std.Build, out_stream: anytype) !void {
|
||||
fn printSteps(builder: *std.Build, w: *Writer) !void {
|
||||
const allocator = builder.allocator;
|
||||
for (builder.top_level_steps.values()) |top_level_step| {
|
||||
const name = if (&top_level_step.step == builder.default_step)
|
||||
try fmt.allocPrint(allocator, "{s} (default)", .{top_level_step.step.name})
|
||||
else
|
||||
top_level_step.step.name;
|
||||
try out_stream.print(" {s:<28} {s}\n", .{ name, top_level_step.description });
|
||||
try w.print(" {s:<28} {s}\n", .{ name, top_level_step.description });
|
||||
}
|
||||
}
|
||||
|
||||
fn usage(b: *std.Build, out_stream: anytype) !void {
|
||||
try out_stream.print(
|
||||
fn printUsage(b: *std.Build, w: *Writer) !void {
|
||||
try w.print(
|
||||
\\Usage: {s} build [steps] [options]
|
||||
\\
|
||||
\\Steps:
|
||||
\\
|
||||
, .{b.graph.zig_exe});
|
||||
try steps(b, out_stream);
|
||||
try printSteps(b, w);
|
||||
|
||||
try out_stream.writeAll(
|
||||
try w.writeAll(
|
||||
\\
|
||||
\\General Options:
|
||||
\\ -p, --prefix [path] Where to install files (default: zig-out)
|
||||
|
|
@ -1319,25 +1324,25 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
|
|||
|
||||
const arena = b.allocator;
|
||||
if (b.available_options_list.items.len == 0) {
|
||||
try out_stream.print(" (none)\n", .{});
|
||||
try w.print(" (none)\n", .{});
|
||||
} else {
|
||||
for (b.available_options_list.items) |option| {
|
||||
const name = try fmt.allocPrint(arena, " -D{s}=[{s}]", .{
|
||||
option.name,
|
||||
@tagName(option.type_id),
|
||||
});
|
||||
try out_stream.print("{s:<30} {s}\n", .{ name, option.description });
|
||||
try w.print("{s:<30} {s}\n", .{ name, option.description });
|
||||
if (option.enum_options) |enum_options| {
|
||||
const padding = " " ** 33;
|
||||
try out_stream.writeAll(padding ++ "Supported Values:\n");
|
||||
try w.writeAll(padding ++ "Supported Values:\n");
|
||||
for (enum_options) |enum_option| {
|
||||
try out_stream.print(padding ++ " {s}\n", .{enum_option});
|
||||
try w.print(padding ++ " {s}\n", .{enum_option});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try out_stream.writeAll(
|
||||
try w.writeAll(
|
||||
\\
|
||||
\\System Integration Options:
|
||||
\\ --search-prefix [path] Add a path to look for binaries, libraries, headers
|
||||
|
|
@ -1352,7 +1357,7 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
|
|||
\\
|
||||
);
|
||||
if (b.graph.system_library_options.entries.len == 0) {
|
||||
try out_stream.writeAll(" (none) -\n");
|
||||
try w.writeAll(" (none) -\n");
|
||||
} else {
|
||||
for (b.graph.system_library_options.keys(), b.graph.system_library_options.values()) |k, v| {
|
||||
const status = switch (v) {
|
||||
|
|
@ -1360,11 +1365,11 @@ fn usage(b: *std.Build, out_stream: anytype) !void {
|
|||
.declared_disabled => "no",
|
||||
.user_enabled, .user_disabled => unreachable, // already emitted error
|
||||
};
|
||||
try out_stream.print(" {s:<43} {s}\n", .{ k, status });
|
||||
try w.print(" {s:<43} {s}\n", .{ k, status });
|
||||
}
|
||||
}
|
||||
|
||||
try out_stream.writeAll(
|
||||
try w.writeAll(
|
||||
\\
|
||||
\\Advanced Options:
|
||||
\\ -freference-trace[=num] How many lines of reference trace should be shown per compile error
|
||||
|
|
@ -1544,3 +1549,11 @@ fn createModuleDependenciesForStep(step: *Step) Allocator.Error!void {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
var stdio_buffer_allocation: [256]u8 = undefined;
|
||||
var stdout_writer_allocation: std.fs.File.Writer = undefined;
|
||||
|
||||
fn initStdoutWriter() *Writer {
|
||||
stdout_writer_allocation = std.fs.File.stdout().writerStreaming(&stdio_buffer_allocation);
|
||||
return &stdout_writer_allocation.interface;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -284,7 +284,7 @@ pub fn create(
|
|||
.h_dir = undefined,
|
||||
.dest_dir = graph.env_map.get("DESTDIR"),
|
||||
.install_tls = .{
|
||||
.step = Step.init(.{
|
||||
.step = .init(.{
|
||||
.id = TopLevelStep.base_id,
|
||||
.name = "install",
|
||||
.owner = b,
|
||||
|
|
@ -292,7 +292,7 @@ pub fn create(
|
|||
.description = "Copy build artifacts to prefix path",
|
||||
},
|
||||
.uninstall_tls = .{
|
||||
.step = Step.init(.{
|
||||
.step = .init(.{
|
||||
.id = TopLevelStep.base_id,
|
||||
.name = "uninstall",
|
||||
.owner = b,
|
||||
|
|
@ -342,7 +342,7 @@ fn createChildOnly(
|
|||
.graph = parent.graph,
|
||||
.allocator = allocator,
|
||||
.install_tls = .{
|
||||
.step = Step.init(.{
|
||||
.step = .init(.{
|
||||
.id = TopLevelStep.base_id,
|
||||
.name = "install",
|
||||
.owner = child,
|
||||
|
|
@ -350,7 +350,7 @@ fn createChildOnly(
|
|||
.description = "Copy build artifacts to prefix path",
|
||||
},
|
||||
.uninstall_tls = .{
|
||||
.step = Step.init(.{
|
||||
.step = .init(.{
|
||||
.id = TopLevelStep.base_id,
|
||||
.name = "uninstall",
|
||||
.owner = child,
|
||||
|
|
@ -1525,7 +1525,7 @@ pub fn option(b: *Build, comptime T: type, name_raw: []const u8, description_raw
|
|||
pub fn step(b: *Build, name: []const u8, description: []const u8) *Step {
|
||||
const step_info = b.allocator.create(TopLevelStep) catch @panic("OOM");
|
||||
step_info.* = .{
|
||||
.step = Step.init(.{
|
||||
.step = .init(.{
|
||||
.id = TopLevelStep.base_id,
|
||||
.name = name,
|
||||
.owner = b,
|
||||
|
|
@ -1824,13 +1824,13 @@ pub fn validateUserInputDidItFail(b: *Build) bool {
|
|||
return b.invalid_user_input;
|
||||
}
|
||||
|
||||
fn allocPrintCmd(ally: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) error{OutOfMemory}![]u8 {
|
||||
var buf = ArrayList(u8).init(ally);
|
||||
if (opt_cwd) |cwd| try buf.writer().print("cd {s} && ", .{cwd});
|
||||
fn allocPrintCmd(gpa: Allocator, opt_cwd: ?[]const u8, argv: []const []const u8) error{OutOfMemory}![]u8 {
|
||||
var buf: std.ArrayListUnmanaged(u8) = .empty;
|
||||
if (opt_cwd) |cwd| try buf.print(gpa, "cd {s} && ", .{cwd});
|
||||
for (argv) |arg| {
|
||||
try buf.writer().print("{s} ", .{arg});
|
||||
try buf.print(gpa, "{s} ", .{arg});
|
||||
}
|
||||
return buf.toOwnedSlice();
|
||||
return buf.toOwnedSlice(gpa);
|
||||
}
|
||||
|
||||
fn printCmd(ally: Allocator, cwd: ?[]const u8, argv: []const []const u8) void {
|
||||
|
|
@ -2466,10 +2466,9 @@ pub const GeneratedFile = struct {
|
|||
|
||||
pub fn getPath2(gen: GeneratedFile, src_builder: *Build, asking_step: ?*Step) []const u8 {
|
||||
return gen.path orelse {
|
||||
std.debug.lockStdErr();
|
||||
const stderr = std.fs.File.stderr();
|
||||
dumpBadGetPathHelp(gen.step, stderr, src_builder, asking_step) catch {};
|
||||
std.debug.unlockStdErr();
|
||||
const w = debug.lockStderrWriter(&.{});
|
||||
dumpBadGetPathHelp(gen.step, w, .detect(.stderr()), src_builder, asking_step) catch {};
|
||||
debug.unlockStderrWriter();
|
||||
@panic("misconfigured build script");
|
||||
};
|
||||
}
|
||||
|
|
@ -2676,10 +2675,9 @@ pub const LazyPath = union(enum) {
|
|||
var file_path: Cache.Path = .{
|
||||
.root_dir = Cache.Directory.cwd(),
|
||||
.sub_path = gen.file.path orelse {
|
||||
std.debug.lockStdErr();
|
||||
const stderr: fs.File = .stderr();
|
||||
dumpBadGetPathHelp(gen.file.step, stderr, src_builder, asking_step) catch {};
|
||||
std.debug.unlockStdErr();
|
||||
const w = debug.lockStderrWriter(&.{});
|
||||
dumpBadGetPathHelp(gen.file.step, w, .detect(.stderr()), src_builder, asking_step) catch {};
|
||||
debug.unlockStderrWriter();
|
||||
@panic("misconfigured build script");
|
||||
},
|
||||
};
|
||||
|
|
@ -2766,44 +2764,42 @@ fn dumpBadDirnameHelp(
|
|||
comptime msg: []const u8,
|
||||
args: anytype,
|
||||
) anyerror!void {
|
||||
debug.lockStdErr();
|
||||
defer debug.unlockStdErr();
|
||||
const w = debug.lockStderrWriter(&.{});
|
||||
defer debug.unlockStderrWriter();
|
||||
|
||||
const stderr: fs.File = .stderr();
|
||||
const w = stderr.deprecatedWriter();
|
||||
try w.print(msg, args);
|
||||
|
||||
const tty_config = std.io.tty.detectConfig(stderr);
|
||||
const tty_config = std.io.tty.detectConfig(.stderr());
|
||||
|
||||
if (fail_step) |s| {
|
||||
tty_config.setColor(w, .red) catch {};
|
||||
try stderr.writeAll(" The step was created by this stack trace:\n");
|
||||
try w.writeAll(" The step was created by this stack trace:\n");
|
||||
tty_config.setColor(w, .reset) catch {};
|
||||
|
||||
s.dump(stderr);
|
||||
s.dump(w, tty_config);
|
||||
}
|
||||
|
||||
if (asking_step) |as| {
|
||||
tty_config.setColor(w, .red) catch {};
|
||||
try stderr.deprecatedWriter().print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
|
||||
try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
|
||||
tty_config.setColor(w, .reset) catch {};
|
||||
|
||||
as.dump(stderr);
|
||||
as.dump(w, tty_config);
|
||||
}
|
||||
|
||||
tty_config.setColor(w, .red) catch {};
|
||||
try stderr.writeAll(" Hope that helps. Proceeding to panic.\n");
|
||||
try w.writeAll(" Hope that helps. Proceeding to panic.\n");
|
||||
tty_config.setColor(w, .reset) catch {};
|
||||
}
|
||||
|
||||
/// In this function the stderr mutex has already been locked.
|
||||
pub fn dumpBadGetPathHelp(
|
||||
s: *Step,
|
||||
stderr: fs.File,
|
||||
w: *std.io.Writer,
|
||||
tty_config: std.io.tty.Config,
|
||||
src_builder: *Build,
|
||||
asking_step: ?*Step,
|
||||
) anyerror!void {
|
||||
const w = stderr.deprecatedWriter();
|
||||
try w.print(
|
||||
\\getPath() was called on a GeneratedFile that wasn't built yet.
|
||||
\\ source package path: {s}
|
||||
|
|
@ -2814,21 +2810,20 @@ pub fn dumpBadGetPathHelp(
|
|||
s.name,
|
||||
});
|
||||
|
||||
const tty_config = std.io.tty.detectConfig(stderr);
|
||||
tty_config.setColor(w, .red) catch {};
|
||||
try stderr.writeAll(" The step was created by this stack trace:\n");
|
||||
try w.writeAll(" The step was created by this stack trace:\n");
|
||||
tty_config.setColor(w, .reset) catch {};
|
||||
|
||||
s.dump(stderr);
|
||||
s.dump(w, tty_config);
|
||||
if (asking_step) |as| {
|
||||
tty_config.setColor(w, .red) catch {};
|
||||
try stderr.deprecatedWriter().print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
|
||||
try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
|
||||
tty_config.setColor(w, .reset) catch {};
|
||||
|
||||
as.dump(stderr);
|
||||
as.dump(w, tty_config);
|
||||
}
|
||||
tty_config.setColor(w, .red) catch {};
|
||||
try stderr.writeAll(" Hope that helps. Proceeding to panic.\n");
|
||||
try w.writeAll(" Hope that helps. Proceeding to panic.\n");
|
||||
tty_config.setColor(w, .reset) catch {};
|
||||
}
|
||||
|
||||
|
|
@ -2866,11 +2861,6 @@ pub fn makeTempPath(b: *Build) []const u8 {
|
|||
return result_path;
|
||||
}
|
||||
|
||||
/// Deprecated; use `std.fmt.hex` instead.
|
||||
pub fn hex64(x: u64) [16]u8 {
|
||||
return std.fmt.hex(x);
|
||||
}
|
||||
|
||||
/// A pair of target query and fully resolved target.
|
||||
/// This type is generally required by build system API that need to be given a
|
||||
/// target. The query is kept because the Zig toolchain needs to know which parts
|
||||
|
|
|
|||
|
|
@ -112,7 +112,6 @@ fn rebuildTestsWorkerRun(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog
|
|||
|
||||
fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, parent_prog_node: std.Progress.Node) !void {
|
||||
const gpa = run.step.owner.allocator;
|
||||
const stderr = std.fs.File.stderr();
|
||||
|
||||
const compile = run.producer.?;
|
||||
const prog_node = parent_prog_node.start(compile.step.name, 0);
|
||||
|
|
@ -125,9 +124,10 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, ttyconf: std.io.tty.Config, par
|
|||
const show_stderr = compile.step.result_stderr.len > 0;
|
||||
|
||||
if (show_error_msgs or show_compile_errors or show_stderr) {
|
||||
std.debug.lockStdErr();
|
||||
defer std.debug.unlockStdErr();
|
||||
build_runner.printErrorMessages(gpa, &compile.step, .{ .ttyconf = ttyconf }, stderr, false) catch {};
|
||||
var buf: [256]u8 = undefined;
|
||||
const w = std.debug.lockStderrWriter(&buf);
|
||||
defer std.debug.unlockStderrWriter();
|
||||
build_runner.printErrorMessages(gpa, &compile.step, .{ .ttyconf = ttyconf }, w, false) catch {};
|
||||
}
|
||||
|
||||
const rebuilt_bin_path = result catch |err| switch (err) {
|
||||
|
|
@ -152,10 +152,10 @@ fn fuzzWorkerRun(
|
|||
|
||||
run.rerunInFuzzMode(web_server, unit_test_index, prog_node) catch |err| switch (err) {
|
||||
error.MakeFailed => {
|
||||
const stderr = std.fs.File.stderr();
|
||||
std.debug.lockStdErr();
|
||||
defer std.debug.unlockStdErr();
|
||||
build_runner.printErrorMessages(gpa, &run.step, .{ .ttyconf = ttyconf }, stderr, false) catch {};
|
||||
var buf: [256]u8 = undefined;
|
||||
const w = std.debug.lockStderrWriter(&buf);
|
||||
defer std.debug.unlockStderrWriter();
|
||||
build_runner.printErrorMessages(gpa, &run.step, .{ .ttyconf = ttyconf }, w, false) catch {};
|
||||
return;
|
||||
},
|
||||
else => {
|
||||
|
|
|
|||
|
|
@ -286,10 +286,7 @@ pub fn cast(step: *Step, comptime T: type) ?*T {
|
|||
}
|
||||
|
||||
/// For debugging purposes, prints identifying information about this Step.
|
||||
pub fn dump(step: *Step, file: std.fs.File) void {
|
||||
var fw = file.writer(&.{});
|
||||
const w = &fw.interface;
|
||||
const tty_config = std.io.tty.detectConfig(file);
|
||||
pub fn dump(step: *Step, w: *std.io.Writer, tty_config: std.io.tty.Config) void {
|
||||
const debug_info = std.debug.getSelfDebugInfo() catch |err| {
|
||||
w.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{
|
||||
@errorName(err),
|
||||
|
|
|
|||
|
|
@ -409,7 +409,7 @@ pub fn create(owner: *std.Build, options: Options) *Compile {
|
|||
.linkage = options.linkage,
|
||||
.kind = options.kind,
|
||||
.name = name,
|
||||
.step = Step.init(.{
|
||||
.step = .init(.{
|
||||
.id = base_id,
|
||||
.name = step_name,
|
||||
.owner = owner,
|
||||
|
|
@ -1017,20 +1017,16 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking
|
|||
const maybe_path: ?*GeneratedFile = @field(compile, tag_name);
|
||||
|
||||
const generated_file = maybe_path orelse {
|
||||
std.debug.lockStdErr();
|
||||
const stderr: fs.File = .stderr();
|
||||
|
||||
std.Build.dumpBadGetPathHelp(&compile.step, stderr, compile.step.owner, asking_step) catch {};
|
||||
|
||||
const w = std.debug.lockStderrWriter(&.{});
|
||||
std.Build.dumpBadGetPathHelp(&compile.step, w, .detect(.stderr()), compile.step.owner, asking_step) catch {};
|
||||
std.debug.unlockStderrWriter();
|
||||
@panic("missing emit option for " ++ tag_name);
|
||||
};
|
||||
|
||||
const path = generated_file.path orelse {
|
||||
std.debug.lockStdErr();
|
||||
const stderr: fs.File = .stderr();
|
||||
|
||||
std.Build.dumpBadGetPathHelp(&compile.step, stderr, compile.step.owner, asking_step) catch {};
|
||||
|
||||
const w = std.debug.lockStderrWriter(&.{});
|
||||
std.Build.dumpBadGetPathHelp(&compile.step, w, .detect(.stderr()), compile.step.owner, asking_step) catch {};
|
||||
std.debug.unlockStderrWriter();
|
||||
@panic(tag_name ++ " is null. Is there a missing step dependency?");
|
||||
};
|
||||
|
||||
|
|
@ -1768,12 +1764,12 @@ fn getZigArgs(compile: *Compile, fuzz: bool) ![][]const u8 {
|
|||
for (arg, 0..) |c, arg_idx| {
|
||||
if (c == '\\' or c == '"') {
|
||||
// Slow path for arguments that need to be escaped. We'll need to allocate and copy
|
||||
var escaped = try ArrayList(u8).initCapacity(arena, arg.len + 1);
|
||||
const writer = escaped.writer();
|
||||
try writer.writeAll(arg[0..arg_idx]);
|
||||
var escaped: std.ArrayListUnmanaged(u8) = .empty;
|
||||
try escaped.ensureTotalCapacityPrecise(arena, arg.len + 1);
|
||||
try escaped.appendSlice(arena, arg[0..arg_idx]);
|
||||
for (arg[arg_idx..]) |to_escape| {
|
||||
if (to_escape == '\\' or to_escape == '"') try writer.writeByte('\\');
|
||||
try writer.writeByte(to_escape);
|
||||
if (to_escape == '\\' or to_escape == '"') try escaped.append(arena, '\\');
|
||||
try escaped.append(arena, to_escape);
|
||||
}
|
||||
escaped_args.appendAssumeCapacity(escaped.items);
|
||||
continue :arg_blk;
|
||||
|
|
@ -1963,20 +1959,23 @@ fn addFlag(args: *ArrayList([]const u8), comptime name: []const u8, opt: ?bool)
|
|||
fn checkCompileErrors(compile: *Compile) !void {
|
||||
// Clear this field so that it does not get printed by the build runner.
|
||||
const actual_eb = compile.step.result_error_bundle;
|
||||
compile.step.result_error_bundle = std.zig.ErrorBundle.empty;
|
||||
compile.step.result_error_bundle = .empty;
|
||||
|
||||
const arena = compile.step.owner.allocator;
|
||||
|
||||
var actual_errors_list = std.ArrayList(u8).init(arena);
|
||||
const actual_errors = ae: {
|
||||
var aw: std.io.Writer.Allocating = .init(arena);
|
||||
defer aw.deinit();
|
||||
try actual_eb.renderToWriter(.{
|
||||
.ttyconf = .no_color,
|
||||
.include_reference_trace = false,
|
||||
.include_source_line = false,
|
||||
}, actual_errors_list.writer());
|
||||
const actual_errors = try actual_errors_list.toOwnedSlice();
|
||||
}, &aw.writer);
|
||||
break :ae try aw.toOwnedSlice();
|
||||
};
|
||||
|
||||
// Render the expected lines into a string that we can compare verbatim.
|
||||
var expected_generated = std.ArrayList(u8).init(arena);
|
||||
var expected_generated: std.ArrayListUnmanaged(u8) = .empty;
|
||||
const expect_errors = compile.expect_errors.?;
|
||||
|
||||
var actual_line_it = mem.splitScalar(u8, actual_errors, '\n');
|
||||
|
|
@ -2035,17 +2034,17 @@ fn checkCompileErrors(compile: *Compile) !void {
|
|||
.exact => |expect_lines| {
|
||||
for (expect_lines) |expect_line| {
|
||||
const actual_line = actual_line_it.next() orelse {
|
||||
try expected_generated.appendSlice(expect_line);
|
||||
try expected_generated.append('\n');
|
||||
try expected_generated.appendSlice(arena, expect_line);
|
||||
try expected_generated.append(arena, '\n');
|
||||
continue;
|
||||
};
|
||||
if (matchCompileError(actual_line, expect_line)) {
|
||||
try expected_generated.appendSlice(actual_line);
|
||||
try expected_generated.append('\n');
|
||||
try expected_generated.appendSlice(arena, actual_line);
|
||||
try expected_generated.append(arena, '\n');
|
||||
continue;
|
||||
}
|
||||
try expected_generated.appendSlice(expect_line);
|
||||
try expected_generated.append('\n');
|
||||
try expected_generated.appendSlice(arena, expect_line);
|
||||
try expected_generated.append(arena, '\n');
|
||||
}
|
||||
|
||||
if (mem.eql(u8, expected_generated.items, actual_errors)) return;
|
||||
|
|
|
|||
|
|
@ -1725,10 +1725,6 @@ pub const Writer = struct {
|
|||
iovecs[len] = .{ .base = splat_buffer.ptr, .len = remaining_splat };
|
||||
len += 1;
|
||||
}
|
||||
return std.posix.writev(handle, iovecs[0..len]) catch |err| {
|
||||
w.err = err;
|
||||
return error.WriteFailed;
|
||||
};
|
||||
},
|
||||
else => for (0..splat - 1) |_| {
|
||||
if (iovecs.len - len == 0) break;
|
||||
|
|
|
|||
|
|
@ -5,36 +5,9 @@ const process = std.process;
|
|||
const windows = std.os.windows;
|
||||
const native_os = builtin.os.tag;
|
||||
|
||||
/// Detect suitable TTY configuration options for the given file (commonly stdout/stderr).
|
||||
/// This includes feature checks for ANSI escape codes and the Windows console API, as well as
|
||||
/// respecting the `NO_COLOR` and `CLICOLOR_FORCE` environment variables to override the default.
|
||||
/// Will attempt to enable ANSI escape code support if necessary/possible.
|
||||
/// Deprecated in favor of `Config.detect`.
|
||||
pub fn detectConfig(file: File) Config {
|
||||
const force_color: ?bool = if (builtin.os.tag == .wasi)
|
||||
null // wasi does not support environment variables
|
||||
else if (process.hasNonEmptyEnvVarConstant("NO_COLOR"))
|
||||
false
|
||||
else if (process.hasNonEmptyEnvVarConstant("CLICOLOR_FORCE"))
|
||||
true
|
||||
else
|
||||
null;
|
||||
|
||||
if (force_color == false) return .no_color;
|
||||
|
||||
if (file.getOrEnableAnsiEscapeSupport()) return .escape_codes;
|
||||
|
||||
if (native_os == .windows and file.isTty()) {
|
||||
var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
|
||||
if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) == windows.FALSE) {
|
||||
return if (force_color == true) .escape_codes else .no_color;
|
||||
}
|
||||
return .{ .windows_api = .{
|
||||
.handle = file.handle,
|
||||
.reset_attributes = info.wAttributes,
|
||||
} };
|
||||
}
|
||||
|
||||
return if (force_color == true) .escape_codes else .no_color;
|
||||
return .detect(file);
|
||||
}
|
||||
|
||||
pub const Color = enum {
|
||||
|
|
@ -66,6 +39,38 @@ pub const Config = union(enum) {
|
|||
escape_codes,
|
||||
windows_api: if (native_os == .windows) WindowsContext else void,
|
||||
|
||||
/// Detect suitable TTY configuration options for the given file (commonly stdout/stderr).
|
||||
/// This includes feature checks for ANSI escape codes and the Windows console API, as well as
|
||||
/// respecting the `NO_COLOR` and `CLICOLOR_FORCE` environment variables to override the default.
|
||||
/// Will attempt to enable ANSI escape code support if necessary/possible.
|
||||
pub fn detect(file: File) Config {
|
||||
const force_color: ?bool = if (builtin.os.tag == .wasi)
|
||||
null // wasi does not support environment variables
|
||||
else if (process.hasNonEmptyEnvVarConstant("NO_COLOR"))
|
||||
false
|
||||
else if (process.hasNonEmptyEnvVarConstant("CLICOLOR_FORCE"))
|
||||
true
|
||||
else
|
||||
null;
|
||||
|
||||
if (force_color == false) return .no_color;
|
||||
|
||||
if (file.getOrEnableAnsiEscapeSupport()) return .escape_codes;
|
||||
|
||||
if (native_os == .windows and file.isTty()) {
|
||||
var info: windows.CONSOLE_SCREEN_BUFFER_INFO = undefined;
|
||||
if (windows.kernel32.GetConsoleScreenBufferInfo(file.handle, &info) == windows.FALSE) {
|
||||
return if (force_color == true) .escape_codes else .no_color;
|
||||
}
|
||||
return .{ .windows_api = .{
|
||||
.handle = file.handle,
|
||||
.reset_attributes = info.wAttributes,
|
||||
} };
|
||||
}
|
||||
|
||||
return if (force_color == true) .escape_codes else .no_color;
|
||||
}
|
||||
|
||||
pub const WindowsContext = struct {
|
||||
handle: File.Handle,
|
||||
reset_attributes: u16,
|
||||
|
|
@ -123,6 +128,7 @@ pub const Config = union(enum) {
|
|||
.dim => windows.FOREGROUND_INTENSITY,
|
||||
.reset => ctx.reset_attributes,
|
||||
};
|
||||
try w.flush();
|
||||
try windows.SetConsoleTextAttribute(ctx.handle, attributes);
|
||||
} else {
|
||||
unreachable;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ const std = @import("std");
|
|||
const ErrorBundle = @This();
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const Writer = std.io.Writer;
|
||||
|
||||
string_bytes: []const u8,
|
||||
/// The first thing in this array is an `ErrorMessageList`.
|
||||
|
|
@ -162,23 +163,23 @@ pub const RenderOptions = struct {
|
|||
};
|
||||
|
||||
pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions) void {
|
||||
std.debug.lockStdErr();
|
||||
defer std.debug.unlockStdErr();
|
||||
const stderr: std.fs.File = .stderr();
|
||||
return renderToWriter(eb, options, stderr.deprecatedWriter()) catch return;
|
||||
var buffer: [256]u8 = undefined;
|
||||
const w = std.debug.lockStderrWriter(&buffer);
|
||||
defer std.debug.unlockStderrWriter();
|
||||
renderToWriter(eb, options, w) catch return;
|
||||
}
|
||||
|
||||
pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, writer: anytype) anyerror!void {
|
||||
pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, w: *Writer) (Writer.Error || std.posix.UnexpectedError)!void {
|
||||
if (eb.extra.len == 0) return;
|
||||
for (eb.getMessages()) |err_msg| {
|
||||
try renderErrorMessageToWriter(eb, options, err_msg, writer, "error", .red, 0);
|
||||
try renderErrorMessageToWriter(eb, options, err_msg, w, "error", .red, 0);
|
||||
}
|
||||
|
||||
if (options.include_log_text) {
|
||||
const log_text = eb.getCompileLogOutput();
|
||||
if (log_text.len != 0) {
|
||||
try writer.writeAll("\nCompile Log Output:\n");
|
||||
try writer.writeAll(log_text);
|
||||
try w.writeAll("\nCompile Log Output:\n");
|
||||
try w.writeAll(log_text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -187,74 +188,73 @@ fn renderErrorMessageToWriter(
|
|||
eb: ErrorBundle,
|
||||
options: RenderOptions,
|
||||
err_msg_index: MessageIndex,
|
||||
stderr: anytype,
|
||||
w: *Writer,
|
||||
kind: []const u8,
|
||||
color: std.io.tty.Color,
|
||||
indent: usize,
|
||||
) anyerror!void {
|
||||
) (Writer.Error || std.posix.UnexpectedError)!void {
|
||||
const ttyconf = options.ttyconf;
|
||||
var counting_writer = std.io.countingWriter(stderr);
|
||||
const counting_stderr = counting_writer.writer();
|
||||
const err_msg = eb.getErrorMessage(err_msg_index);
|
||||
const prefix_start = w.count;
|
||||
if (err_msg.src_loc != .none) {
|
||||
const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
|
||||
try counting_stderr.writeByteNTimes(' ', indent);
|
||||
try ttyconf.setColor(stderr, .bold);
|
||||
try counting_stderr.print("{s}:{d}:{d}: ", .{
|
||||
try w.splatByteAll(' ', indent);
|
||||
try ttyconf.setColor(w, .bold);
|
||||
try w.print("{s}:{d}:{d}: ", .{
|
||||
eb.nullTerminatedString(src.data.src_path),
|
||||
src.data.line + 1,
|
||||
src.data.column + 1,
|
||||
});
|
||||
try ttyconf.setColor(stderr, color);
|
||||
try counting_stderr.writeAll(kind);
|
||||
try counting_stderr.writeAll(": ");
|
||||
try ttyconf.setColor(w, color);
|
||||
try w.writeAll(kind);
|
||||
try w.writeAll(": ");
|
||||
// This is the length of the part before the error message:
|
||||
// e.g. "file.zig:4:5: error: "
|
||||
const prefix_len: usize = @intCast(counting_stderr.context.bytes_written);
|
||||
try ttyconf.setColor(stderr, .reset);
|
||||
try ttyconf.setColor(stderr, .bold);
|
||||
const prefix_len = w.count - prefix_start;
|
||||
try ttyconf.setColor(w, .reset);
|
||||
try ttyconf.setColor(w, .bold);
|
||||
if (err_msg.count == 1) {
|
||||
try writeMsg(eb, err_msg, stderr, prefix_len);
|
||||
try stderr.writeByte('\n');
|
||||
try writeMsg(eb, err_msg, w, prefix_len);
|
||||
try w.writeByte('\n');
|
||||
} else {
|
||||
try writeMsg(eb, err_msg, stderr, prefix_len);
|
||||
try ttyconf.setColor(stderr, .dim);
|
||||
try stderr.print(" ({d} times)\n", .{err_msg.count});
|
||||
try writeMsg(eb, err_msg, w, prefix_len);
|
||||
try ttyconf.setColor(w, .dim);
|
||||
try w.print(" ({d} times)\n", .{err_msg.count});
|
||||
}
|
||||
try ttyconf.setColor(stderr, .reset);
|
||||
try ttyconf.setColor(w, .reset);
|
||||
if (src.data.source_line != 0 and options.include_source_line) {
|
||||
const line = eb.nullTerminatedString(src.data.source_line);
|
||||
for (line) |b| switch (b) {
|
||||
'\t' => try stderr.writeByte(' '),
|
||||
else => try stderr.writeByte(b),
|
||||
'\t' => try w.writeByte(' '),
|
||||
else => try w.writeByte(b),
|
||||
};
|
||||
try stderr.writeByte('\n');
|
||||
try w.writeByte('\n');
|
||||
// TODO basic unicode code point monospace width
|
||||
const before_caret = src.data.span_main - src.data.span_start;
|
||||
// -1 since span.main includes the caret
|
||||
const after_caret = src.data.span_end -| src.data.span_main -| 1;
|
||||
try stderr.writeByteNTimes(' ', src.data.column - before_caret);
|
||||
try ttyconf.setColor(stderr, .green);
|
||||
try stderr.writeByteNTimes('~', before_caret);
|
||||
try stderr.writeByte('^');
|
||||
try stderr.writeByteNTimes('~', after_caret);
|
||||
try stderr.writeByte('\n');
|
||||
try ttyconf.setColor(stderr, .reset);
|
||||
try w.splatByteAll(' ', src.data.column - before_caret);
|
||||
try ttyconf.setColor(w, .green);
|
||||
try w.splatByteAll('~', before_caret);
|
||||
try w.writeByte('^');
|
||||
try w.splatByteAll('~', after_caret);
|
||||
try w.writeByte('\n');
|
||||
try ttyconf.setColor(w, .reset);
|
||||
}
|
||||
for (eb.getNotes(err_msg_index)) |note| {
|
||||
try renderErrorMessageToWriter(eb, options, note, stderr, "note", .cyan, indent);
|
||||
try renderErrorMessageToWriter(eb, options, note, w, "note", .cyan, indent);
|
||||
}
|
||||
if (src.data.reference_trace_len > 0 and options.include_reference_trace) {
|
||||
try ttyconf.setColor(stderr, .reset);
|
||||
try ttyconf.setColor(stderr, .dim);
|
||||
try stderr.print("referenced by:\n", .{});
|
||||
try ttyconf.setColor(w, .reset);
|
||||
try ttyconf.setColor(w, .dim);
|
||||
try w.print("referenced by:\n", .{});
|
||||
var ref_index = src.end;
|
||||
for (0..src.data.reference_trace_len) |_| {
|
||||
const ref_trace = eb.extraData(ReferenceTrace, ref_index);
|
||||
ref_index = ref_trace.end;
|
||||
if (ref_trace.data.src_loc != .none) {
|
||||
const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);
|
||||
try stderr.print(" {s}: {s}:{d}:{d}\n", .{
|
||||
try w.print(" {s}: {s}:{d}:{d}\n", .{
|
||||
eb.nullTerminatedString(ref_trace.data.decl_name),
|
||||
eb.nullTerminatedString(ref_src.src_path),
|
||||
ref_src.line + 1,
|
||||
|
|
@ -262,36 +262,36 @@ fn renderErrorMessageToWriter(
|
|||
});
|
||||
} else if (ref_trace.data.decl_name != 0) {
|
||||
const count = ref_trace.data.decl_name;
|
||||
try stderr.print(
|
||||
try w.print(
|
||||
" {d} reference(s) hidden; use '-freference-trace={d}' to see all references\n",
|
||||
.{ count, count + src.data.reference_trace_len - 1 },
|
||||
);
|
||||
} else {
|
||||
try stderr.print(
|
||||
try w.print(
|
||||
" remaining reference traces hidden; use '-freference-trace' to see all reference traces\n",
|
||||
.{},
|
||||
);
|
||||
}
|
||||
}
|
||||
try ttyconf.setColor(stderr, .reset);
|
||||
try ttyconf.setColor(w, .reset);
|
||||
}
|
||||
} else {
|
||||
try ttyconf.setColor(stderr, color);
|
||||
try stderr.writeByteNTimes(' ', indent);
|
||||
try stderr.writeAll(kind);
|
||||
try stderr.writeAll(": ");
|
||||
try ttyconf.setColor(stderr, .reset);
|
||||
try ttyconf.setColor(w, color);
|
||||
try w.splatByteAll(' ', indent);
|
||||
try w.writeAll(kind);
|
||||
try w.writeAll(": ");
|
||||
try ttyconf.setColor(w, .reset);
|
||||
const msg = eb.nullTerminatedString(err_msg.msg);
|
||||
if (err_msg.count == 1) {
|
||||
try stderr.print("{s}\n", .{msg});
|
||||
try w.print("{s}\n", .{msg});
|
||||
} else {
|
||||
try stderr.print("{s}", .{msg});
|
||||
try ttyconf.setColor(stderr, .dim);
|
||||
try stderr.print(" ({d} times)\n", .{err_msg.count});
|
||||
try w.print("{s}", .{msg});
|
||||
try ttyconf.setColor(w, .dim);
|
||||
try w.print(" ({d} times)\n", .{err_msg.count});
|
||||
}
|
||||
try ttyconf.setColor(stderr, .reset);
|
||||
try ttyconf.setColor(w, .reset);
|
||||
for (eb.getNotes(err_msg_index)) |note| {
|
||||
try renderErrorMessageToWriter(eb, options, note, stderr, "note", .cyan, indent + 4);
|
||||
try renderErrorMessageToWriter(eb, options, note, w, "note", .cyan, indent + 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -300,13 +300,13 @@ fn renderErrorMessageToWriter(
|
|||
/// to allow for long, good-looking error messages.
|
||||
///
|
||||
/// This is used to split the message in `@compileError("hello\nworld")` for example.
|
||||
fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, stderr: anytype, indent: usize) !void {
|
||||
fn writeMsg(eb: ErrorBundle, err_msg: ErrorMessage, w: *Writer, indent: usize) !void {
|
||||
var lines = std.mem.splitScalar(u8, eb.nullTerminatedString(err_msg.msg), '\n');
|
||||
while (lines.next()) |line| {
|
||||
try stderr.writeAll(line);
|
||||
try w.writeAll(line);
|
||||
if (lines.index == null) break;
|
||||
try stderr.writeByte('\n');
|
||||
try stderr.writeByteNTimes(' ', indent);
|
||||
try w.writeByte('\n');
|
||||
try w.splatByteAll(' ', indent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -398,7 +398,7 @@ pub const Wip = struct {
|
|||
pub fn printString(wip: *Wip, comptime fmt: []const u8, args: anytype) Allocator.Error!String {
|
||||
const gpa = wip.gpa;
|
||||
const index: String = @intCast(wip.string_bytes.items.len);
|
||||
try wip.string_bytes.writer(gpa).print(fmt, args);
|
||||
try wip.string_bytes.print(gpa, fmt, args);
|
||||
try wip.string_bytes.append(gpa, 0);
|
||||
return index;
|
||||
}
|
||||
|
|
@ -788,9 +788,10 @@ pub const Wip = struct {
|
|||
|
||||
const ttyconf: std.io.tty.Config = .no_color;
|
||||
|
||||
var bundle_buf = std.ArrayList(u8).init(std.testing.allocator);
|
||||
var bundle_buf: std.io.Writer.Allocating = .init(std.testing.allocator);
|
||||
const bundle_bw = &bundle_buf.interface;
|
||||
defer bundle_buf.deinit();
|
||||
try bundle.renderToWriter(.{ .ttyconf = ttyconf }, bundle_buf.writer());
|
||||
try bundle.renderToWriter(.{ .ttyconf = ttyconf }, bundle_bw);
|
||||
|
||||
var copy = copy: {
|
||||
var wip: ErrorBundle.Wip = undefined;
|
||||
|
|
@ -803,10 +804,11 @@ pub const Wip = struct {
|
|||
};
|
||||
defer copy.deinit(std.testing.allocator);
|
||||
|
||||
var copy_buf = std.ArrayList(u8).init(std.testing.allocator);
|
||||
var copy_buf: std.io.Writer.Allocating = .init(std.testing.allocator);
|
||||
const copy_bw = ©_buf.interface;
|
||||
defer copy_buf.deinit();
|
||||
try copy.renderToWriter(.{ .ttyconf = ttyconf }, copy_buf.writer());
|
||||
try copy.renderToWriter(.{ .ttyconf = ttyconf }, copy_bw);
|
||||
|
||||
try std.testing.expectEqualStrings(bundle_buf.items, copy_buf.items);
|
||||
try std.testing.expectEqualStrings(bundle_bw.getWritten(), copy_bw.getWritten());
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue