authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-10 20:55:11-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:09-08:00
logb042e935228db5d46271d4d3d17afeb9ba5d7ce3
treefd02941ee06e6abed96f0f1193a27ce1dfe41cc3
parent7837d975dcaa17ff22f536607c4ff6db7b697b04

std: update tty config references in the build system


13 files changed, 271 insertions(+), 294 deletions(-)

lib/compiler/build_runner.zig+99-109
......@@ -14,7 +14,6 @@ const WebServer = std.Build.WebServer;
1414const Allocator = std.mem.Allocator;
1515const fatal = std.process.fatal;
1616const Writer = std.Io.Writer;
17const tty = std.Io.tty;
1817
1918pub const root = @import("@build");
2019pub const dependencies = @import("@dependencies");
......@@ -435,9 +434,7 @@ pub fn main() !void {
435434 if (builtin.single_threaded) fatal("'--webui' is not yet supported on single-threaded hosts", .{});
436435 }
437436
438 const ttyconf = color.detectTtyConf(io);
439
440 const main_progress_node = std.Progress.start(.{
437 const main_progress_node = std.Progress.start(io, .{
441438 .disable_printing = (color == .off),
442439 });
443440 defer main_progress_node.end();
......@@ -509,8 +506,6 @@ pub fn main() !void {
509506 .error_style = error_style,
510507 .multiline_errors = multiline_errors,
511508 .summary = summary orelse if (watch or webui_listen != null) .line else .failures,
512
513 .ttyconf = ttyconf,
514509 };
515510 defer {
516511 run.memory_blocked_steps.deinit(gpa);
......@@ -524,10 +519,10 @@ pub fn main() !void {
524519
525520 prepare(arena, builder, targets.items, &run, graph.random_seed) catch |err| switch (err) {
526521 error.DependencyLoopDetected => {
527 // Perhaps in the future there could be an Advanced Options flag such as
528 // --debug-build-runner-leaks which would make this code return instead of
529 // calling exit.
530 std.debug.lockStdErr();
522 // Perhaps in the future there could be an Advanced Options flag
523 // such as --debug-build-runner-leaks which would make this code
524 // return instead of calling exit.
525 _ = std.debug.lockStderrWriter(&.{});
531526 process.exit(1);
532527 },
533528 else => |e| return e,
......@@ -545,7 +540,6 @@ pub fn main() !void {
545540 if (builtin.single_threaded) unreachable; // `fatal` above
546541 break :ws .init(.{
547542 .gpa = gpa,
548 .ttyconf = ttyconf,
549543 .graph = &graph,
550544 .all_steps = run.step_stack.keys(),
551545 .root_prog_node = main_progress_node,
......@@ -560,9 +554,9 @@ pub fn main() !void {
560554 }
561555
562556 rebuild: while (true) : (if (run.error_style.clearOnUpdate()) {
563 const bw, _ = std.debug.lockStderrWriter(&stdio_buffer_allocation);
557 const stderr = std.debug.lockStderrWriter(&stdio_buffer_allocation);
564558 defer std.debug.unlockStderrWriter();
565 try bw.writeAll("\x1B[2J\x1B[3J\x1B[H");
559 try stderr.writeAllUnescaped("\x1B[2J\x1B[3J\x1B[H");
566560 }) {
567561 if (run.web_server) |*ws| ws.startBuild();
568562
......@@ -663,9 +657,6 @@ const Run = struct {
663657 memory_blocked_steps: std.ArrayList(*Step),
664658 /// Allocated into `gpa`.
665659 step_stack: std.AutoArrayHashMapUnmanaged(*Step, void),
666 /// Similar to the `tty.Config` returned by `std.debug.lockStderrWriter`,
667 /// but also respects the '--color' flag.
668 ttyconf: tty.Config,
669660
670661 claimed_rss: usize,
671662 error_style: ErrorStyle,
......@@ -839,7 +830,6 @@ fn runStepNames(
839830 var f = std.Build.Fuzz.init(
840831 gpa,
841832 io,
842 run.ttyconf,
843833 step_stack.keys(),
844834 parent_prog_node,
845835 mode,
......@@ -866,18 +856,20 @@ fn runStepNames(
866856 .none => break :summary,
867857 }
868858
869 const w, _ = std.debug.lockStderrWriter(&stdio_buffer_allocation);
859 const stderr = std.debug.lockStderrWriter(&stdio_buffer_allocation);
870860 defer std.debug.unlockStderrWriter();
871 const ttyconf = run.ttyconf;
861
862 const w = &stderr.interface;
863 const fwm = stderr.mode;
872864
873865 const total_count = success_count + failure_count + pending_count + skipped_count;
874 ttyconf.setColor(w, .cyan) catch {};
875 ttyconf.setColor(w, .bold) catch {};
866 fwm.setColor(w, .cyan) catch {};
867 fwm.setColor(w, .bold) catch {};
876868 w.writeAll("Build Summary: ") catch {};
877 ttyconf.setColor(w, .reset) catch {};
869 fwm.setColor(w, .reset) catch {};
878870 w.print("{d}/{d} steps succeeded", .{ success_count, total_count }) catch {};
879871 {
880 ttyconf.setColor(w, .dim) catch {};
872 fwm.setColor(w, .dim) catch {};
881873 var first = true;
882874 if (skipped_count > 0) {
883875 w.print("{s}{d} skipped", .{ if (first) " (" else ", ", skipped_count }) catch {};
......@@ -888,12 +880,12 @@ fn runStepNames(
888880 first = false;
889881 }
890882 if (!first) w.writeByte(')') catch {};
891 ttyconf.setColor(w, .reset) catch {};
883 fwm.setColor(w, .reset) catch {};
892884 }
893885
894886 if (test_count > 0) {
895887 w.print("; {d}/{d} tests passed", .{ test_pass_count, test_count }) catch {};
896 ttyconf.setColor(w, .dim) catch {};
888 fwm.setColor(w, .dim) catch {};
897889 var first = true;
898890 if (test_skip_count > 0) {
899891 w.print("{s}{d} skipped", .{ if (first) " (" else ", ", test_skip_count }) catch {};
......@@ -912,7 +904,7 @@ fn runStepNames(
912904 first = false;
913905 }
914906 if (!first) w.writeByte(')') catch {};
915 ttyconf.setColor(w, .reset) catch {};
907 fwm.setColor(w, .reset) catch {};
916908 }
917909
918910 w.writeAll("\n") catch {};
......@@ -926,7 +918,7 @@ fn runStepNames(
926918 var print_node: PrintNode = .{ .parent = null };
927919 if (step_names.len == 0) {
928920 print_node.last = true;
929 printTreeStep(b, b.default_step, run, w, ttyconf, &print_node, &step_stack_copy) catch {};
921 printTreeStep(b, b.default_step, run, w, fwm, &print_node, &step_stack_copy) catch {};
930922 } else {
931923 const last_index = if (run.summary == .all) b.top_level_steps.count() else blk: {
932924 var i: usize = step_names.len;
......@@ -945,7 +937,7 @@ fn runStepNames(
945937 for (step_names, 0..) |step_name, i| {
946938 const tls = b.top_level_steps.get(step_name).?;
947939 print_node.last = i + 1 == last_index;
948 printTreeStep(b, &tls.step, run, w, ttyconf, &print_node, &step_stack_copy) catch {};
940 printTreeStep(b, &tls.step, run, w, fwm, &print_node, &step_stack_copy) catch {};
949941 }
950942 }
951943 w.writeByte('\n') catch {};
......@@ -962,7 +954,7 @@ fn runStepNames(
962954 if (run.error_style.verboseContext()) break :code 1; // failure; print build command
963955 break :code 2; // failure; do not print build command
964956 };
965 std.debug.lockStdErr();
957 _ = std.debug.lockStderrWriter(&.{});
966958 process.exit(code);
967959}
968960
......@@ -971,31 +963,31 @@ const PrintNode = struct {
971963 last: bool = false,
972964};
973965
974fn printPrefix(node: *PrintNode, stderr: *Writer, ttyconf: tty.Config) !void {
966fn printPrefix(node: *PrintNode, w: *Writer, fwm: File.Writer.Mode) !void {
975967 const parent = node.parent orelse return;
976968 if (parent.parent == null) return;
977 try printPrefix(parent, stderr, ttyconf);
969 try printPrefix(parent, w, fwm);
978970 if (parent.last) {
979 try stderr.writeAll(" ");
971 try w.writeAll(" ");
980972 } else {
981 try stderr.writeAll(switch (ttyconf) {
982 .no_color, .windows_api => "| ",
983 .escape_codes => "\x1B\x28\x30\x78\x1B\x28\x42 ", // │
973 try w.writeAll(switch (fwm) {
974 .terminal_escaped => "\x1B\x28\x30\x78\x1B\x28\x42 ", // │
975 else => "| ",
984976 });
985977 }
986978}
987979
988fn printChildNodePrefix(stderr: *Writer, ttyconf: tty.Config) !void {
989 try stderr.writeAll(switch (ttyconf) {
990 .no_color, .windows_api => "+- ",
991 .escape_codes => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
980fn printChildNodePrefix(w: *Writer, fwm: File.Writer.Mode) !void {
981 try w.writeAll(switch (fwm) {
982 .terminal_escaped => "\x1B\x28\x30\x6d\x71\x1B\x28\x42 ", // └─
983 else => "+- ",
992984 });
993985}
994986
995987fn printStepStatus(
996988 s: *Step,
997989 stderr: *Writer,
998 ttyconf: tty.Config,
990 fwm: File.Writer.Mode,
999991 run: *const Run,
1000992) !void {
1001993 switch (s.state) {
......@@ -1005,13 +997,13 @@ fn printStepStatus(
1005997 .running => unreachable,
1006998
1007999 .dependency_failure => {
1008 try ttyconf.setColor(stderr, .dim);
1000 try fwm.setColor(stderr, .dim);
10091001 try stderr.writeAll(" transitive failure\n");
1010 try ttyconf.setColor(stderr, .reset);
1002 try fwm.setColor(stderr, .reset);
10111003 },
10121004
10131005 .success => {
1014 try ttyconf.setColor(stderr, .green);
1006 try fwm.setColor(stderr, .green);
10151007 if (s.result_cached) {
10161008 try stderr.writeAll(" cached");
10171009 } else if (s.test_results.test_count > 0) {
......@@ -1019,19 +1011,19 @@ fn printStepStatus(
10191011 assert(s.test_results.test_count == pass_count + s.test_results.skip_count);
10201012 try stderr.print(" {d} pass", .{pass_count});
10211013 if (s.test_results.skip_count > 0) {
1022 try ttyconf.setColor(stderr, .reset);
1014 try fwm.setColor(stderr, .reset);
10231015 try stderr.writeAll(", ");
1024 try ttyconf.setColor(stderr, .yellow);
1016 try fwm.setColor(stderr, .yellow);
10251017 try stderr.print("{d} skip", .{s.test_results.skip_count});
10261018 }
1027 try ttyconf.setColor(stderr, .reset);
1019 try fwm.setColor(stderr, .reset);
10281020 try stderr.print(" ({d} total)", .{s.test_results.test_count});
10291021 } else {
10301022 try stderr.writeAll(" success");
10311023 }
1032 try ttyconf.setColor(stderr, .reset);
1024 try fwm.setColor(stderr, .reset);
10331025 if (s.result_duration_ns) |ns| {
1034 try ttyconf.setColor(stderr, .dim);
1026 try fwm.setColor(stderr, .dim);
10351027 if (ns >= std.time.ns_per_min) {
10361028 try stderr.print(" {d}m", .{ns / std.time.ns_per_min});
10371029 } else if (ns >= std.time.ns_per_s) {
......@@ -1043,11 +1035,11 @@ fn printStepStatus(
10431035 } else {
10441036 try stderr.print(" {d}ns", .{ns});
10451037 }
1046 try ttyconf.setColor(stderr, .reset);
1038 try fwm.setColor(stderr, .reset);
10471039 }
10481040 if (s.result_peak_rss != 0) {
10491041 const rss = s.result_peak_rss;
1050 try ttyconf.setColor(stderr, .dim);
1042 try fwm.setColor(stderr, .dim);
10511043 if (rss >= 1000_000_000) {
10521044 try stderr.print(" MaxRSS:{d}G", .{rss / 1000_000_000});
10531045 } else if (rss >= 1000_000) {
......@@ -1057,25 +1049,25 @@ fn printStepStatus(
10571049 } else {
10581050 try stderr.print(" MaxRSS:{d}B", .{rss});
10591051 }
1060 try ttyconf.setColor(stderr, .reset);
1052 try fwm.setColor(stderr, .reset);
10611053 }
10621054 try stderr.writeAll("\n");
10631055 },
10641056 .skipped, .skipped_oom => |skip| {
1065 try ttyconf.setColor(stderr, .yellow);
1057 try fwm.setColor(stderr, .yellow);
10661058 try stderr.writeAll(" skipped");
10671059 if (skip == .skipped_oom) {
10681060 try stderr.writeAll(" (not enough memory)");
1069 try ttyconf.setColor(stderr, .dim);
1061 try fwm.setColor(stderr, .dim);
10701062 try stderr.print(" upper bound of {d} exceeded runner limit ({d})", .{ s.max_rss, run.max_rss });
1071 try ttyconf.setColor(stderr, .yellow);
1063 try fwm.setColor(stderr, .yellow);
10721064 }
10731065 try stderr.writeAll("\n");
1074 try ttyconf.setColor(stderr, .reset);
1066 try fwm.setColor(stderr, .reset);
10751067 },
10761068 .failure => {
1077 try printStepFailure(s, stderr, ttyconf, false);
1078 try ttyconf.setColor(stderr, .reset);
1069 try printStepFailure(s, stderr, fwm, false);
1070 try fwm.setColor(stderr, .reset);
10791071 },
10801072 }
10811073}
......@@ -1083,48 +1075,48 @@ fn printStepStatus(
10831075fn printStepFailure(
10841076 s: *Step,
10851077 stderr: *Writer,
1086 ttyconf: tty.Config,
1078 fwm: File.Writer.Mode,
10871079 dim: bool,
10881080) !void {
10891081 if (s.result_error_bundle.errorMessageCount() > 0) {
1090 try ttyconf.setColor(stderr, .red);
1082 try fwm.setColor(stderr, .red);
10911083 try stderr.print(" {d} errors\n", .{
10921084 s.result_error_bundle.errorMessageCount(),
10931085 });
10941086 } else if (!s.test_results.isSuccess()) {
10951087 // These first values include all of the test "statuses". Every test is either passsed,
10961088 // skipped, failed, crashed, or timed out.
1097 try ttyconf.setColor(stderr, .green);
1089 try fwm.setColor(stderr, .green);
10981090 try stderr.print(" {d} pass", .{s.test_results.passCount()});
1099 try ttyconf.setColor(stderr, .reset);
1100 if (dim) try ttyconf.setColor(stderr, .dim);
1091 try fwm.setColor(stderr, .reset);
1092 if (dim) try fwm.setColor(stderr, .dim);
11011093 if (s.test_results.skip_count > 0) {
11021094 try stderr.writeAll(", ");
1103 try ttyconf.setColor(stderr, .yellow);
1095 try fwm.setColor(stderr, .yellow);
11041096 try stderr.print("{d} skip", .{s.test_results.skip_count});
1105 try ttyconf.setColor(stderr, .reset);
1106 if (dim) try ttyconf.setColor(stderr, .dim);
1097 try fwm.setColor(stderr, .reset);
1098 if (dim) try fwm.setColor(stderr, .dim);
11071099 }
11081100 if (s.test_results.fail_count > 0) {
11091101 try stderr.writeAll(", ");
1110 try ttyconf.setColor(stderr, .red);
1102 try fwm.setColor(stderr, .red);
11111103 try stderr.print("{d} fail", .{s.test_results.fail_count});
1112 try ttyconf.setColor(stderr, .reset);
1113 if (dim) try ttyconf.setColor(stderr, .dim);
1104 try fwm.setColor(stderr, .reset);
1105 if (dim) try fwm.setColor(stderr, .dim);
11141106 }
11151107 if (s.test_results.crash_count > 0) {
11161108 try stderr.writeAll(", ");
1117 try ttyconf.setColor(stderr, .red);
1109 try fwm.setColor(stderr, .red);
11181110 try stderr.print("{d} crash", .{s.test_results.crash_count});
1119 try ttyconf.setColor(stderr, .reset);
1120 if (dim) try ttyconf.setColor(stderr, .dim);
1111 try fwm.setColor(stderr, .reset);
1112 if (dim) try fwm.setColor(stderr, .dim);
11211113 }
11221114 if (s.test_results.timeout_count > 0) {
11231115 try stderr.writeAll(", ");
1124 try ttyconf.setColor(stderr, .red);
1116 try fwm.setColor(stderr, .red);
11251117 try stderr.print("{d} timeout", .{s.test_results.timeout_count});
1126 try ttyconf.setColor(stderr, .reset);
1127 if (dim) try ttyconf.setColor(stderr, .dim);
1118 try fwm.setColor(stderr, .reset);
1119 if (dim) try fwm.setColor(stderr, .dim);
11281120 }
11291121 try stderr.print(" ({d} total)", .{s.test_results.test_count});
11301122
......@@ -1134,10 +1126,10 @@ fn printStepFailure(
11341126 // 2 pass, 1 skip, 2 fail (5 total); 2 leaks
11351127 if (s.test_results.leak_count > 0) {
11361128 try stderr.writeAll("; ");
1137 try ttyconf.setColor(stderr, .red);
1129 try fwm.setColor(stderr, .red);
11381130 try stderr.print("{d} leaks", .{s.test_results.leak_count});
1139 try ttyconf.setColor(stderr, .reset);
1140 if (dim) try ttyconf.setColor(stderr, .dim);
1131 try fwm.setColor(stderr, .reset);
1132 if (dim) try fwm.setColor(stderr, .dim);
11411133 }
11421134
11431135 // It's usually not helpful to know how many error logs there were because they tend to
......@@ -1151,19 +1143,19 @@ fn printStepFailure(
11511143 };
11521144 if (show_err_logs) {
11531145 try stderr.writeAll("; ");
1154 try ttyconf.setColor(stderr, .red);
1146 try fwm.setColor(stderr, .red);
11551147 try stderr.print("{d} error logs", .{s.test_results.log_err_count});
1156 try ttyconf.setColor(stderr, .reset);
1157 if (dim) try ttyconf.setColor(stderr, .dim);
1148 try fwm.setColor(stderr, .reset);
1149 if (dim) try fwm.setColor(stderr, .dim);
11581150 }
11591151
11601152 try stderr.writeAll("\n");
11611153 } else if (s.result_error_msgs.items.len > 0) {
1162 try ttyconf.setColor(stderr, .red);
1154 try fwm.setColor(stderr, .red);
11631155 try stderr.writeAll(" failure\n");
11641156 } else {
11651157 assert(s.result_stderr.len > 0);
1166 try ttyconf.setColor(stderr, .red);
1158 try fwm.setColor(stderr, .red);
11671159 try stderr.writeAll(" stderr\n");
11681160 }
11691161}
......@@ -1173,7 +1165,7 @@ fn printTreeStep(
11731165 s: *Step,
11741166 run: *const Run,
11751167 stderr: *Writer,
1176 ttyconf: tty.Config,
1168 fwm: File.Writer.Mode,
11771169 parent_node: *PrintNode,
11781170 step_stack: *std.AutoArrayHashMapUnmanaged(*Step, void),
11791171) !void {
......@@ -1186,26 +1178,26 @@ fn printTreeStep(
11861178 .failures => s.state == .success,
11871179 };
11881180 if (skip) return;
1189 try printPrefix(parent_node, stderr, ttyconf);
1181 try printPrefix(parent_node, stderr, fwm);
11901182
11911183 if (parent_node.parent != null) {
11921184 if (parent_node.last) {
1193 try printChildNodePrefix(stderr, ttyconf);
1185 try printChildNodePrefix(stderr, fwm);
11941186 } else {
1195 try stderr.writeAll(switch (ttyconf) {
1196 .no_color, .windows_api => "+- ",
1197 .escape_codes => "\x1B\x28\x30\x74\x71\x1B\x28\x42 ", // ├─
1187 try stderr.writeAll(switch (fwm) {
1188 .terminal_escaped => "\x1B\x28\x30\x74\x71\x1B\x28\x42 ", // ├─
1189 else => "+- ",
11981190 });
11991191 }
12001192 }
12011193
1202 if (!first) try ttyconf.setColor(stderr, .dim);
1194 if (!first) try fwm.setColor(stderr, .dim);
12031195
12041196 // dep_prefix omitted here because it is redundant with the tree.
12051197 try stderr.writeAll(s.name);
12061198
12071199 if (first) {
1208 try printStepStatus(s, stderr, ttyconf, run);
1200 try printStepStatus(s, stderr, fwm, run);
12091201
12101202 const last_index = if (summary == .all) s.dependencies.items.len -| 1 else blk: {
12111203 var i: usize = s.dependencies.items.len;
......@@ -1227,7 +1219,7 @@ fn printTreeStep(
12271219 .parent = parent_node,
12281220 .last = i == last_index,
12291221 };
1230 try printTreeStep(b, dep, run, stderr, ttyconf, &print_node, step_stack);
1222 try printTreeStep(b, dep, run, stderr, fwm, &print_node, step_stack);
12311223 }
12321224 } else {
12331225 if (s.dependencies.items.len == 0) {
......@@ -1237,7 +1229,7 @@ fn printTreeStep(
12371229 s.dependencies.items.len,
12381230 });
12391231 }
1240 try ttyconf.setColor(stderr, .reset);
1232 try fwm.setColor(stderr, .reset);
12411233 }
12421234}
12431235
......@@ -1368,7 +1360,6 @@ fn workerMakeOneStep(
13681360 .progress_node = sub_prog_node,
13691361 .watch = run.watch,
13701362 .web_server = if (run.web_server) |*ws| ws else null,
1371 .ttyconf = run.ttyconf,
13721363 .unit_test_timeout_ns = run.unit_test_timeout_ns,
13731364 .gpa = gpa,
13741365 });
......@@ -1378,10 +1369,9 @@ fn workerMakeOneStep(
13781369 const show_error_msgs = s.result_error_msgs.items.len > 0;
13791370 const show_stderr = s.result_stderr.len > 0;
13801371 if (show_error_msgs or show_compile_errors or show_stderr) {
1381 const bw, _ = std.debug.lockStderrWriter(&stdio_buffer_allocation);
1372 const stderr = std.debug.lockStderrWriter(&stdio_buffer_allocation);
13821373 defer std.debug.unlockStderrWriter();
1383 const ttyconf = run.ttyconf;
1384 printErrorMessages(gpa, s, .{}, bw, ttyconf, run.error_style, run.multiline_errors) catch {};
1374 printErrorMessages(gpa, s, .{}, &stderr.interface, stderr.mode, run.error_style, run.multiline_errors) catch {};
13851375 }
13861376
13871377 handle_result: {
......@@ -1449,7 +1439,7 @@ pub fn printErrorMessages(
14491439 failing_step: *Step,
14501440 options: std.zig.ErrorBundle.RenderOptions,
14511441 stderr: *Writer,
1452 ttyconf: tty.Config,
1442 fwm: File.Writer.Mode,
14531443 error_style: ErrorStyle,
14541444 multiline_errors: MultilineErrors,
14551445) !void {
......@@ -1464,29 +1454,29 @@ pub fn printErrorMessages(
14641454 }
14651455
14661456 // Now, `step_stack` has the subtree that we want to print, in reverse order.
1467 try ttyconf.setColor(stderr, .dim);
1457 try fwm.setColor(stderr, .dim);
14681458 var indent: usize = 0;
14691459 while (step_stack.pop()) |s| : (indent += 1) {
14701460 if (indent > 0) {
14711461 try stderr.splatByteAll(' ', (indent - 1) * 3);
1472 try printChildNodePrefix(stderr, ttyconf);
1462 try printChildNodePrefix(stderr, fwm);
14731463 }
14741464
14751465 try stderr.writeAll(s.name);
14761466
14771467 if (s == failing_step) {
1478 try printStepFailure(s, stderr, ttyconf, true);
1468 try printStepFailure(s, stderr, fwm, true);
14791469 } else {
14801470 try stderr.writeAll("\n");
14811471 }
14821472 }
1483 try ttyconf.setColor(stderr, .reset);
1473 try fwm.setColor(stderr, .reset);
14841474 } else {
14851475 // Just print the failing step itself.
1486 try ttyconf.setColor(stderr, .dim);
1476 try fwm.setColor(stderr, .dim);
14871477 try stderr.writeAll(failing_step.name);
1488 try printStepFailure(failing_step, stderr, ttyconf, true);
1489 try ttyconf.setColor(stderr, .reset);
1478 try printStepFailure(failing_step, stderr, fwm, true);
1479 try fwm.setColor(stderr, .reset);
14901480 }
14911481
14921482 if (failing_step.result_stderr.len > 0) {
......@@ -1496,12 +1486,12 @@ pub fn printErrorMessages(
14961486 }
14971487 }
14981488
1499 try failing_step.result_error_bundle.renderToWriter(options, stderr, ttyconf);
1489 try failing_step.result_error_bundle.renderToWriter(options, stderr, fwm);
15001490
15011491 for (failing_step.result_error_msgs.items) |msg| {
1502 try ttyconf.setColor(stderr, .red);
1492 try fwm.setColor(stderr, .red);
15031493 try stderr.writeAll("error:");
1504 try ttyconf.setColor(stderr, .reset);
1494 try fwm.setColor(stderr, .reset);
15051495 if (std.mem.indexOfScalar(u8, msg, '\n') == null) {
15061496 try stderr.print(" {s}\n", .{msg});
15071497 } else switch (multiline_errors) {
......@@ -1519,9 +1509,9 @@ pub fn printErrorMessages(
15191509
15201510 if (error_style.verboseContext()) {
15211511 if (failing_step.result_failed_command) |cmd_str| {
1522 try ttyconf.setColor(stderr, .red);
1512 try fwm.setColor(stderr, .red);
15231513 try stderr.writeAll("failed command: ");
1524 try ttyconf.setColor(stderr, .reset);
1514 try fwm.setColor(stderr, .reset);
15251515 try stderr.writeAll(cmd_str);
15261516 try stderr.writeByte('\n');
15271517 }
lib/std/Build.zig+31-29
......@@ -5,9 +5,8 @@ const std = @import("std.zig");
55const Io = std.Io;
66const fs = std.fs;
77const mem = std.mem;
8const debug = std.debug;
98const panic = std.debug.panic;
10const assert = debug.assert;
9const assert = std.debug.assert;
1110const log = std.log;
1211const StringHashMap = std.StringHashMap;
1312const Allocator = std.mem.Allocator;
......@@ -2090,7 +2089,7 @@ pub fn dependencyFromBuildZig(
20902089 }
20912090
20922091 const full_path = b.pathFromRoot("build.zig.zon");
2093 debug.panic("'{}' is not a build.zig struct of a dependency in '{s}'", .{ build_zig, full_path });
2092 std.debug.panic("'{}' is not a build.zig struct of a dependency in '{s}'", .{ build_zig, full_path });
20942093}
20952094
20962095fn userValuesAreSame(lhs: UserValue, rhs: UserValue) bool {
......@@ -2249,9 +2248,9 @@ pub const GeneratedFile = struct {
22492248
22502249 pub fn getPath2(gen: GeneratedFile, src_builder: *Build, asking_step: ?*Step) []const u8 {
22512250 return gen.path orelse {
2252 const w, const ttyconf = debug.lockStderrWriter(&.{});
2253 dumpBadGetPathHelp(gen.step, w, ttyconf, src_builder, asking_step) catch {};
2254 debug.unlockStderrWriter();
2251 const stderr = std.debug.lockStderrWriter(&.{});
2252 dumpBadGetPathHelp(gen.step, &stderr.interface, stderr.mode, src_builder, asking_step) catch {};
2253 std.debug.unlockStderrWriter();
22552254 @panic("misconfigured build script");
22562255 };
22572256 }
......@@ -2458,9 +2457,9 @@ pub const LazyPath = union(enum) {
24582457 var file_path: Cache.Path = .{
24592458 .root_dir = Cache.Directory.cwd(),
24602459 .sub_path = gen.file.path orelse {
2461 const w, const ttyconf = debug.lockStderrWriter(&.{});
2462 dumpBadGetPathHelp(gen.file.step, w, ttyconf, src_builder, asking_step) catch {};
2463 debug.unlockStderrWriter();
2460 const stderr = std.debug.lockStderrWriter(&.{});
2461 dumpBadGetPathHelp(gen.file.step, &stderr.interface, stderr.mode, src_builder, asking_step) catch {};
2462 std.debug.unlockStderrWriter();
24642463 @panic("misconfigured build script");
24652464 },
24662465 };
......@@ -2550,37 +2549,40 @@ fn dumpBadDirnameHelp(
25502549 comptime msg: []const u8,
25512550 args: anytype,
25522551) anyerror!void {
2553 const w, const tty_config = debug.lockStderrWriter(&.{});
2554 defer debug.unlockStderrWriter();
2552 const stderr = std.debug.lockStderrWriter(&.{});
2553 defer std.debug.unlockStderrWriter();
2554
2555 const w = &stderr.interface;
2556 const fwm = stderr.mode;
25552557
25562558 try w.print(msg, args);
25572559
25582560 if (fail_step) |s| {
2559 tty_config.setColor(w, .red) catch {};
2561 fwm.setColor(w, .red) catch {};
25602562 try w.writeAll(" The step was created by this stack trace:\n");
2561 tty_config.setColor(w, .reset) catch {};
2563 fwm.setColor(w, .reset) catch {};
25622564
2563 s.dump(w, tty_config);
2565 s.dump(w, fwm);
25642566 }
25652567
25662568 if (asking_step) |as| {
2567 tty_config.setColor(w, .red) catch {};
2569 fwm.setColor(w, .red) catch {};
25682570 try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
2569 tty_config.setColor(w, .reset) catch {};
2571 fwm.setColor(w, .reset) catch {};
25702572
2571 as.dump(w, tty_config);
2573 as.dump(w, fwm);
25722574 }
25732575
2574 tty_config.setColor(w, .red) catch {};
2576 fwm.setColor(w, .red) catch {};
25752577 try w.writeAll(" Hope that helps. Proceeding to panic.\n");
2576 tty_config.setColor(w, .reset) catch {};
2578 fwm.setColor(w, .reset) catch {};
25772579}
25782580
25792581/// In this function the stderr mutex has already been locked.
25802582pub fn dumpBadGetPathHelp(
25812583 s: *Step,
2582 w: *std.Io.Writer,
2583 tty_config: std.Io.tty.Config,
2584 w: *Io.Writer,
2585 fwm: File.Writer.Mode,
25842586 src_builder: *Build,
25852587 asking_step: ?*Step,
25862588) anyerror!void {
......@@ -2594,21 +2596,21 @@ pub fn dumpBadGetPathHelp(
25942596 s.name,
25952597 });
25962598
2597 tty_config.setColor(w, .red) catch {};
2599 fwm.setColor(w, .red) catch {};
25982600 try w.writeAll(" The step was created by this stack trace:\n");
2599 tty_config.setColor(w, .reset) catch {};
2601 fwm.setColor(w, .reset) catch {};
26002602
2601 s.dump(w, tty_config);
2603 s.dump(w, fwm);
26022604 if (asking_step) |as| {
2603 tty_config.setColor(w, .red) catch {};
2605 fwm.setColor(w, .red) catch {};
26042606 try w.print(" The step '{s}' that is missing a dependency on the above step was created by this stack trace:\n", .{as.name});
2605 tty_config.setColor(w, .reset) catch {};
2607 fwm.setColor(w, .reset) catch {};
26062608
2607 as.dump(w, tty_config);
2609 as.dump(w, fwm);
26082610 }
2609 tty_config.setColor(w, .red) catch {};
2611 fwm.setColor(w, .red) catch {};
26102612 try w.writeAll(" Hope that helps. Proceeding to panic.\n");
2611 tty_config.setColor(w, .reset) catch {};
2613 fwm.setColor(w, .reset) catch {};
26122614}
26132615
26142616pub const InstallDir = union(enum) {
lib/std/Build/Fuzz.zig+8-12
......@@ -9,14 +9,12 @@ const Allocator = std.mem.Allocator;
99const log = std.log;
1010const Coverage = std.debug.Coverage;
1111const abi = Build.abi.fuzz;
12const tty = std.Io.tty;
1312
1413const Fuzz = @This();
1514const build_runner = @import("root");
1615
1716gpa: Allocator,
1817io: Io,
19ttyconf: tty.Config,
2018mode: Mode,
2119
2220/// Allocated into `gpa`.
......@@ -77,7 +75,6 @@ const CoverageMap = struct {
7775pub fn init(
7876 gpa: Allocator,
7977 io: Io,
80 ttyconf: tty.Config,
8178 all_steps: []const *Build.Step,
8279 root_prog_node: std.Progress.Node,
8380 mode: Mode,
......@@ -95,7 +92,7 @@ pub fn init(
9592 if (run.producer == null) continue;
9693 if (run.fuzz_tests.items.len == 0) continue;
9794 try steps.append(gpa, run);
98 rebuild_group.async(io, rebuildTestsWorkerRun, .{ run, gpa, ttyconf, rebuild_node });
95 rebuild_group.async(io, rebuildTestsWorkerRun, .{ run, gpa, rebuild_node });
9996 }
10097
10198 if (steps.items.len == 0) fatal("no fuzz tests found", .{});
......@@ -115,7 +112,6 @@ pub fn init(
115112 return .{
116113 .gpa = gpa,
117114 .io = io,
118 .ttyconf = ttyconf,
119115 .mode = mode,
120116 .run_steps = run_steps,
121117 .group = .init,
......@@ -154,14 +150,14 @@ pub fn deinit(fuzz: *Fuzz) void {
154150 fuzz.gpa.free(fuzz.run_steps);
155151}
156152
157fn rebuildTestsWorkerRun(run: *Step.Run, gpa: Allocator, ttyconf: tty.Config, parent_prog_node: std.Progress.Node) void {
158 rebuildTestsWorkerRunFallible(run, gpa, ttyconf, parent_prog_node) catch |err| {
153fn rebuildTestsWorkerRun(run: *Step.Run, gpa: Allocator, parent_prog_node: std.Progress.Node) void {
154 rebuildTestsWorkerRunFallible(run, gpa, parent_prog_node) catch |err| {
159155 const compile = run.producer.?;
160156 log.err("step '{s}': failed to rebuild in fuzz mode: {t}", .{ compile.step.name, err });
161157 };
162158}
163159
164fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, ttyconf: tty.Config, parent_prog_node: std.Progress.Node) !void {
160fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, parent_prog_node: std.Progress.Node) !void {
165161 const compile = run.producer.?;
166162 const prog_node = parent_prog_node.start(compile.step.name, 0);
167163 defer prog_node.end();
......@@ -174,9 +170,9 @@ fn rebuildTestsWorkerRunFallible(run: *Step.Run, gpa: Allocator, ttyconf: tty.Co
174170
175171 if (show_error_msgs or show_compile_errors or show_stderr) {
176172 var buf: [256]u8 = undefined;
177 const w, _ = std.debug.lockStderrWriter(&buf);
173 const stderr = std.debug.lockStderrWriter(&buf);
178174 defer std.debug.unlockStderrWriter();
179 build_runner.printErrorMessages(gpa, &compile.step, .{}, w, ttyconf, .verbose, .indent) catch {};
175 build_runner.printErrorMessages(gpa, &compile.step, .{}, &stderr.interface, stderr.mode, .verbose, .indent) catch {};
180176 }
181177
182178 const rebuilt_bin_path = result catch |err| switch (err) {
......@@ -200,9 +196,9 @@ fn fuzzWorkerRun(
200196 run.rerunInFuzzMode(fuzz, unit_test_index, prog_node) catch |err| switch (err) {
201197 error.MakeFailed => {
202198 var buf: [256]u8 = undefined;
203 const w, _ = std.debug.lockStderrWriter(&buf);
199 const stderr = std.debug.lockStderrWriter(&buf);
204200 defer std.debug.unlockStderrWriter();
205 build_runner.printErrorMessages(gpa, &run.step, .{}, w, fuzz.ttyconf, .verbose, .indent) catch {};
201 build_runner.printErrorMessages(gpa, &run.step, .{}, &stderr.interface, stderr.mode, .verbose, .indent) catch {};
206202 return;
207203 },
208204 else => {
lib/std/Build/Step.zig+4-5
......@@ -117,7 +117,6 @@ pub const MakeOptions = struct {
117117 // it currently breaks because `std.net.Address` doesn't work there. Work around for now.
118118 .wasm32 => void,
119119 },
120 ttyconf: std.Io.tty.Config,
121120 /// If set, this is a timeout to enforce on all individual unit tests, in nanoseconds.
122121 unit_test_timeout_ns: ?u64,
123122 /// Not to be confused with `Build.allocator`, which is an alias of `Build.graph.arena`.
......@@ -329,16 +328,16 @@ pub fn cast(step: *Step, comptime T: type) ?*T {
329328}
330329
331330/// For debugging purposes, prints identifying information about this Step.
332pub fn dump(step: *Step, w: *Io.Writer, tty_config: Io.tty.Config) void {
331pub fn dump(step: *Step, w: *Io.Writer, fwm: Io.File.Writer.Mode) void {
333332 if (step.debug_stack_trace.instruction_addresses.len > 0) {
334333 w.print("name: '{s}'. creation stack trace:\n", .{step.name}) catch {};
335 std.debug.writeStackTrace(&step.debug_stack_trace, w, tty_config) catch {};
334 std.debug.writeStackTrace(&step.debug_stack_trace, w, fwm) catch {};
336335 } else {
337336 const field = "debug_stack_frames_count";
338337 comptime assert(@hasField(Build, field));
339 tty_config.setColor(w, .yellow) catch {};
338 fwm.setColor(w, .yellow) catch {};
340339 w.print("name: '{s}'. no stack trace collected for this step, see std.Build." ++ field ++ "\n", .{step.name}) catch {};
341 tty_config.setColor(w, .reset) catch {};
340 fwm.setColor(w, .reset) catch {};
342341 }
343342}
344343
lib/std/Build/Step/Compile.zig+5-5
......@@ -926,15 +926,15 @@ fn getGeneratedFilePath(compile: *Compile, comptime tag_name: []const u8, asking
926926 const maybe_path: ?*GeneratedFile = @field(compile, tag_name);
927927
928928 const generated_file = maybe_path orelse {
929 const w, const ttyconf = std.debug.lockStderrWriter(&.{});
930 std.Build.dumpBadGetPathHelp(&compile.step, w, ttyconf, compile.step.owner, asking_step) catch {};
929 const stderr = std.debug.lockStderrWriter(&.{});
930 std.Build.dumpBadGetPathHelp(&compile.step, &stderr.interface, stderr.mode, compile.step.owner, asking_step) catch {};
931931 std.debug.unlockStderrWriter();
932932 @panic("missing emit option for " ++ tag_name);
933933 };
934934
935935 const path = generated_file.path orelse {
936 const w, const ttyconf = std.debug.lockStderrWriter(&.{});
937 std.Build.dumpBadGetPathHelp(&compile.step, w, ttyconf, compile.step.owner, asking_step) catch {};
936 const stderr = std.debug.lockStderrWriter(&.{});
937 std.Build.dumpBadGetPathHelp(&compile.step, &stderr.interface, stderr.mode, compile.step.owner, asking_step) catch {};
938938 std.debug.unlockStderrWriter();
939939 @panic(tag_name ++ " is null. Is there a missing step dependency?");
940940 };
......@@ -1904,7 +1904,7 @@ fn checkCompileErrors(compile: *Compile) !void {
19041904 try actual_eb.renderToWriter(.{
19051905 .include_reference_trace = false,
19061906 .include_source_line = false,
1907 }, &aw.writer, .no_color);
1907 }, &aw.writer, .streaming);
19081908 break :ae try aw.toOwnedSlice();
19091909 };
19101910
lib/std/Build/Step/Run.zig+33-35
......@@ -5,7 +5,7 @@ const std = @import("std");
55const Io = std.Io;
66const Build = std.Build;
77const Step = std.Build.Step;
8const fs = std.fs;
8const Dir = std.Io.Dir;
99const mem = std.mem;
1010const process = std.process;
1111const EnvMap = std.process.EnvMap;
......@@ -26,19 +26,7 @@ cwd: ?Build.LazyPath,
2626env_map: ?*EnvMap,
2727
2828/// Controls the `NO_COLOR` and `CLICOLOR_FORCE` environment variables.
29color: enum {
30 /// `CLICOLOR_FORCE` is set, and `NO_COLOR` is unset.
31 enable,
32 /// `NO_COLOR` is set, and `CLICOLOR_FORCE` is unset.
33 disable,
34 /// If the build runner is using color, equivalent to `.enable`. Otherwise, equivalent to `.disable`.
35 inherit,
36 /// If stderr is captured or checked, equivalent to `.disable`. Otherwise, equivalent to `.inherit`.
37 auto,
38 /// The build runner does not modify the `CLICOLOR_FORCE` or `NO_COLOR` environment variables.
39 /// They are treated like normal variables, so can be controlled through `setEnvironmentVariable`.
40 manual,
41} = .auto,
29color: Color = .auto,
4230
4331/// When `true` prevents `ZIG_PROGRESS` environment variable from being passed
4432/// to the child process, which otherwise would be used for the child to send
......@@ -112,6 +100,20 @@ rebuilt_executable: ?Path,
112100/// If this Run step was produced by a Compile step, it is tracked here.
113101producer: ?*Step.Compile,
114102
103pub const Color = enum {
104 /// `CLICOLOR_FORCE` is set, and `NO_COLOR` is unset.
105 enable,
106 /// `NO_COLOR` is set, and `CLICOLOR_FORCE` is unset.
107 disable,
108 /// If the build runner is using color, equivalent to `.enable`. Otherwise, equivalent to `.disable`.
109 inherit,
110 /// If stderr is captured or checked, equivalent to `.disable`. Otherwise, equivalent to `.inherit`.
111 auto,
112 /// The build runner does not modify the `CLICOLOR_FORCE` or `NO_COLOR` environment variables.
113 /// They are treated like normal variables, so can be controlled through `setEnvironmentVariable`.
114 manual,
115};
116
115117pub const StdIn = union(enum) {
116118 none,
117119 bytes: []const u8,
......@@ -565,7 +567,7 @@ pub fn addPathDir(run: *Run, search_path: []const u8) void {
565567 if (prev_path) |pp| {
566568 const new_path = b.fmt("{s}{c}{s}", .{
567569 pp,
568 if (use_wine) fs.path.delimiter_windows else fs.path.delimiter,
570 if (use_wine) Dir.path.delimiter_windows else Dir.path.delimiter,
569571 search_path,
570572 });
571573 env_map.put(key, new_path) catch @panic("OOM");
......@@ -748,7 +750,7 @@ fn checksContainStderr(checks: []const StdIo.Check) bool {
748750fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 {
749751 const b = run.step.owner;
750752 const path_str = path.toString(b.graph.arena) catch @panic("OOM");
751 if (std.fs.path.isAbsolute(path_str)) {
753 if (Dir.path.isAbsolute(path_str)) {
752754 // Absolute paths don't need changing.
753755 return path_str;
754756 }
......@@ -756,19 +758,19 @@ fn convertPathArg(run: *Run, path: Build.Cache.Path) []const u8 {
756758 const child_lazy_cwd = run.cwd orelse break :rel path_str;
757759 const child_cwd = child_lazy_cwd.getPath3(b, &run.step).toString(b.graph.arena) catch @panic("OOM");
758760 // Convert it from relative to *our* cwd, to relative to the *child's* cwd.
759 break :rel std.fs.path.relative(b.graph.arena, child_cwd, path_str) catch @panic("OOM");
761 break :rel Dir.path.relative(b.graph.arena, child_cwd, path_str) catch @panic("OOM");
760762 };
761763 // Not every path can be made relative, e.g. if the path and the child cwd are on different
762764 // disk designators on Windows. In that case, `relative` will return an absolute path which we can
763765 // just return.
764 if (std.fs.path.isAbsolute(child_cwd_rel)) {
766 if (Dir.path.isAbsolute(child_cwd_rel)) {
765767 return child_cwd_rel;
766768 }
767769 // We're not done yet. In some cases this path must be prefixed with './':
768770 // * On POSIX, the executable name cannot be a single component like 'foo'
769771 // * Some executables might treat a leading '-' like a flag, which we must avoid
770772 // There's no harm in it, so just *always* apply this prefix.
771 return std.fs.path.join(b.graph.arena, &.{ ".", child_cwd_rel }) catch @panic("OOM");
773 return Dir.path.join(b.graph.arena, &.{ ".", child_cwd_rel }) catch @panic("OOM");
772774}
773775
774776const IndexedOutput = struct {
......@@ -965,11 +967,11 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
965967 &digest,
966968 );
967969
968 const output_dir_path = "o" ++ fs.path.sep_str ++ &digest;
970 const output_dir_path = "o" ++ Dir.path.sep_str ++ &digest;
969971 for (output_placeholders.items) |placeholder| {
970972 const output_sub_path = b.pathJoin(&.{ output_dir_path, placeholder.output.basename });
971973 const output_sub_dir_path = switch (placeholder.tag) {
972 .output_file => fs.path.dirname(output_sub_path).?,
974 .output_file => Dir.path.dirname(output_sub_path).?,
973975 .output_directory => output_sub_path,
974976 else => unreachable,
975977 };
......@@ -995,13 +997,13 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
995997
996998 // We do not know the final output paths yet, use temp paths to run the command.
997999 const rand_int = std.crypto.random.int(u64);
998 const tmp_dir_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
1000 const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);
9991001
10001002 for (output_placeholders.items) |placeholder| {
10011003 const output_components = .{ tmp_dir_path, placeholder.output.basename };
10021004 const output_sub_path = b.pathJoin(&output_components);
10031005 const output_sub_dir_path = switch (placeholder.tag) {
1004 .output_file => fs.path.dirname(output_sub_path).?,
1006 .output_file => Dir.path.dirname(output_sub_path).?,
10051007 .output_directory => output_sub_path,
10061008 else => unreachable,
10071009 };
......@@ -1023,7 +1025,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
10231025
10241026 try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, options, null);
10251027
1026 const dep_file_dir = Io.Dir.cwd();
1028 const dep_file_dir = Dir.cwd();
10271029 const dep_file_basename = dep_output_file.generated_file.getPath2(b, step);
10281030 if (has_side_effects)
10291031 try man.addDepFile(dep_file_dir, dep_file_basename)
......@@ -1040,7 +1042,7 @@ fn make(step: *Step, options: Step.MakeOptions) !void {
10401042
10411043 // Rename into place
10421044 if (any_output) {
1043 const o_sub_path = "o" ++ fs.path.sep_str ++ &digest;
1045 const o_sub_path = "o" ++ Dir.path.sep_str ++ &digest;
10441046
10451047 b.cache_root.handle.rename(tmp_dir_path, b.cache_root.handle, o_sub_path, io) catch |err| {
10461048 if (err == error.PathAlreadyExists) {
......@@ -1139,12 +1141,11 @@ pub fn rerunInFuzzMode(
11391141
11401142 const has_side_effects = false;
11411143 const rand_int = std.crypto.random.int(u64);
1142 const tmp_dir_path = "tmp" ++ fs.path.sep_str ++ std.fmt.hex(rand_int);
1144 const tmp_dir_path = "tmp" ++ Dir.path.sep_str ++ std.fmt.hex(rand_int);
11431145 try runCommand(run, argv_list.items, has_side_effects, tmp_dir_path, .{
11441146 .progress_node = prog_node,
11451147 .watch = undefined, // not used by `runCommand`
11461148 .web_server = null, // only needed for time reports
1147 .ttyconf = fuzz.ttyconf,
11481149 .unit_test_timeout_ns = null, // don't time out fuzz tests for now
11491150 .gpa = fuzz.gpa,
11501151 }, .{
......@@ -1266,10 +1267,7 @@ fn runCommand(
12661267 try env_map.put("NO_COLOR", "1");
12671268 env_map.remove("CLICOLOR_FORCE");
12681269 },
1269 .inherit => switch (options.ttyconf) {
1270 .no_color, .windows_api => continue :color .disable,
1271 .escape_codes => continue :color .enable,
1272 },
1270 .inherit => {},
12731271 .auto => {
12741272 const capture_stderr = run.captured_stderr != null or switch (run.stdio) {
12751273 .check => |checks| checksContainStderr(checks.items),
......@@ -1464,7 +1462,7 @@ fn runCommand(
14641462 captured.output.generated_file.path = output_path;
14651463
14661464 const sub_path = b.pathJoin(&output_components);
1467 const sub_path_dirname = fs.path.dirname(sub_path).?;
1465 const sub_path_dirname = Dir.path.dirname(sub_path).?;
14681466 b.cache_root.handle.makePath(io, sub_path_dirname) catch |err| {
14691467 return step.fail("unable to make path '{f}{s}': {s}", .{
14701468 b.cache_root, sub_path_dirname, @errorName(err),
......@@ -1650,8 +1648,8 @@ fn spawnChildAndCollect(
16501648 if (!run.disable_zig_progress and !inherit) {
16511649 child.progress_node = options.progress_node;
16521650 }
1653 if (inherit) std.debug.lockStdErr();
1654 defer if (inherit) std.debug.unlockStdErr();
1651 if (inherit) _ = std.debug.lockStderrWriter(&.{});
1652 defer if (inherit) std.debug.unlockStderrWriter();
16551653 var timer = try std.time.Timer.start();
16561654 const res = try evalGeneric(run, &child);
16571655 run.step.result_duration_ns = timer.read();
......@@ -2277,7 +2275,7 @@ fn addPathForDynLibs(run: *Run, artifact: *Step.Compile) void {
22772275 if (compile.root_module.resolved_target.?.result.os.tag == .windows and
22782276 compile.isDynamicLibrary())
22792277 {
2280 addPathDir(run, fs.path.dirname(compile.getEmittedBin().getPath2(b, &run.step)).?);
2278 addPathDir(run, Dir.path.dirname(compile.getEmittedBin().getPath2(b, &run.step)).?);
22812279 }
22822280 }
22832281}
lib/std/Build/WebServer.zig-4
......@@ -2,7 +2,6 @@ gpa: Allocator,
22graph: *const Build.Graph,
33all_steps: []const *Build.Step,
44listen_address: net.IpAddress,
5ttyconf: Io.tty.Config,
65root_prog_node: std.Progress.Node,
76watch: bool,
87
......@@ -52,7 +51,6 @@ pub fn notifyUpdate(ws: *WebServer) void {
5251
5352pub const Options = struct {
5453 gpa: Allocator,
55 ttyconf: Io.tty.Config,
5654 graph: *const std.Build.Graph,
5755 all_steps: []const *Build.Step,
5856 root_prog_node: std.Progress.Node,
......@@ -98,7 +96,6 @@ pub fn init(opts: Options) WebServer {
9896
9997 return .{
10098 .gpa = opts.gpa,
101 .ttyconf = opts.ttyconf,
10299 .graph = opts.graph,
103100 .all_steps = all_steps,
104101 .listen_address = opts.listen_address,
......@@ -233,7 +230,6 @@ pub fn finishBuild(ws: *WebServer, opts: struct {
233230 ws.fuzz = Fuzz.init(
234231 ws.gpa,
235232 ws.graph.io,
236 ws.ttyconf,
237233 ws.all_steps,
238234 ws.root_prog_node,
239235 .{ .forever = .{ .ws = ws } },
lib/std/Io/File/Writer.zig+36-5
......@@ -99,7 +99,7 @@ pub const Mode = union(enum) {
9999
100100 pub const SetColorError = std.os.windows.SetConsoleTextAttributeError || Io.Writer.Error;
101101
102 pub fn setColor(mode: Mode, io_w: *Io.Writer, color: Color) Mode.SetColorError!void {
102 pub fn setColor(mode: Mode, io_w: *Io.Writer, color: Color) SetColorError!void {
103103 switch (mode) {
104104 .streaming, .positional, .streaming_simple, .positional_simple, .failure => return,
105105 .terminal_escaped => {
......@@ -155,6 +155,34 @@ pub const Mode = union(enum) {
155155 },
156156 }
157157 }
158
159 fn DecorateArgs(comptime Args: type) type {
160 const fields = @typeInfo(Args).@"struct".fields;
161 var new_fields: [fields.len]type = undefined;
162 for (fields, &new_fields) |old, *new| {
163 if (old.type == std.debug.FormatStackTrace) {
164 new.* = std.debug.FormatStackTrace.Decorated;
165 } else {
166 new.* = old.type;
167 }
168 }
169 return @Tuple(&new_fields);
170 }
171
172 pub fn decorateArgs(file_writer_mode: std.Io.File.Writer.Mode, args: anytype) DecorateArgs(@TypeOf(args)) {
173 var new_args: DecorateArgs(@TypeOf(args)) = undefined;
174 inline for (args, &new_args) |old, *new| {
175 if (@TypeOf(old) == std.debug.FormatStackTrace) {
176 new.* = .{
177 .stack_trace = old.stack_trace,
178 .file_writer_mode = file_writer_mode,
179 };
180 } else {
181 new.* = old;
182 }
183 }
184 return new_args;
185 }
158186};
159187
160188pub const Error = error{
......@@ -426,6 +454,8 @@ pub fn end(w: *Writer) EndError!void {
426454
427455 .streaming,
428456 .streaming_simple,
457 .terminal_escaped,
458 .terminal_winapi,
429459 .failure,
430460 => {},
431461 }
......@@ -453,10 +483,11 @@ pub const Color = enum {
453483 reset,
454484};
455485
456pub const SetColorError = Mode.SetColorError;
457
458pub fn setColor(w: *Writer, color: Color) SetColorError!void {
459 return w.mode.setColor(&w.interface, color);
486pub fn setColor(w: *Writer, color: Color) Io.Writer.Error!void {
487 return w.mode.setColor(&w.interface, color) catch |err| switch (err) {
488 error.WriteFailed => |e| return e,
489 else => |e| w.err = e,
490 };
460491}
461492
462493pub fn disableEscape(w: *Writer) Mode {
lib/std/debug.zig+1-1
......@@ -306,7 +306,7 @@ pub fn print(comptime fmt: []const u8, args: anytype) void {
306306 var buffer: [64]u8 = undefined;
307307 const stderr = lockStderrWriter(&buffer);
308308 defer unlockStderrWriter();
309 stderr.interface.print(fmt, args) catch return;
309 stderr.interface.print(fmt, stderr.mode.decorateArgs(args)) catch return;
310310 }
311311}
312312
lib/std/log.zig+1-29
......@@ -120,35 +120,7 @@ pub fn defaultLogFileWriter(
120120 }
121121 fw.interface.writeAll(": ") catch return;
122122 fw.setColor(.reset) catch {};
123 fw.interface.print(format ++ "\n", decorateArgs(args, fw.mode)) catch return;
124}
125
126fn DecorateArgs(comptime Args: type) type {
127 const fields = @typeInfo(Args).@"struct".fields;
128 var new_fields: [fields.len]type = undefined;
129 for (fields, &new_fields) |old, *new| {
130 if (old.type == std.debug.FormatStackTrace) {
131 new.* = std.debug.FormatStackTrace.Decorated;
132 } else {
133 new.* = old.type;
134 }
135 }
136 return @Tuple(&new_fields);
137}
138
139fn decorateArgs(args: anytype, file_writer_mode: std.Io.File.Writer.Mode) DecorateArgs(@TypeOf(args)) {
140 var new_args: DecorateArgs(@TypeOf(args)) = undefined;
141 inline for (args, &new_args) |old, *new| {
142 if (@TypeOf(old) == std.debug.FormatStackTrace) {
143 new.* = .{
144 .stack_trace = old.stack_trace,
145 .file_writer_mode = file_writer_mode,
146 };
147 } else {
148 new.* = old;
149 }
150 }
151 return new_args;
123 fw.interface.print(format ++ "\n", fw.mode.decorateArgs(args)) catch return;
152124}
153125
154126/// Returns a scoped logging namespace that logs all messages using the scope
lib/std/testing.zig+16-26
......@@ -354,11 +354,10 @@ test expectApproxEqRel {
354354 }
355355}
356356
357/// This function is intended to be used only in tests. When the two slices are not
358/// equal, prints diagnostics to stderr to show exactly how they are not equal (with
359/// the differences highlighted in red), then returns a test failure error.
360/// The colorized output is optional and controlled by the return of `Io.tty.Config.detect`.
361/// If your inputs are UTF-8 encoded strings, consider calling `expectEqualStrings` instead.
357/// This function is intended to be used only in tests. When the two slices are
358/// not equal, prints diagnostics to stderr to show exactly how they are not
359/// equal (with the differences highlighted in red), then returns a test
360/// failure error.
362361pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) !void {
363362 const diff_index: usize = diff_index: {
364363 const shortest = @min(expected.len, actual.len);
......@@ -369,20 +368,13 @@ pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const
369368 break :diff_index if (expected.len == actual.len) return else shortest;
370369 };
371370 if (!backend_can_print) return error.TestExpectedEqual;
372 const stderr_w, const ttyconf = std.debug.lockStderrWriter(&.{});
371 const stderr = std.debug.lockStderrWriter(&.{});
373372 defer std.debug.unlockStderrWriter();
374 failEqualSlices(T, expected, actual, diff_index, stderr_w, ttyconf) catch {};
373 failEqualSlices(T, expected, actual, diff_index, &stderr.interface, stderr.mode) catch {};
375374 return error.TestExpectedEqual;
376375}
377376
378fn failEqualSlices(
379 comptime T: type,
380 expected: []const T,
381 actual: []const T,
382 diff_index: usize,
383 w: *Io.Writer,
384 ttyconf: Io.tty.Config,
385) !void {
377fn failEqualSlices(comptime T: type, expected: []const T, actual: []const T, diff_index: usize, w: *Io.Writer, fwm: Io.File.Writer.Mode) !void {
386378 try w.print("slices differ. first difference occurs at index {d} (0x{X})\n", .{ diff_index, diff_index });
387379
388380 // TODO: Should this be configurable by the caller?
......@@ -404,12 +396,12 @@ fn failEqualSlices(
404396 var differ = if (T == u8) BytesDiffer{
405397 .expected = expected_window,
406398 .actual = actual_window,
407 .ttyconf = ttyconf,
399 .file_writer_mode = fwm,
408400 } else SliceDiffer(T){
409401 .start_index = window_start,
410402 .expected = expected_window,
411403 .actual = actual_window,
412 .ttyconf = ttyconf,
404 .file_writer_mode = fwm,
413405 };
414406
415407 // Print indexes as hex for slices of u8 since it's more likely to be binary data where
......@@ -466,7 +458,7 @@ fn SliceDiffer(comptime T: type) type {
466458 start_index: usize,
467459 expected: []const T,
468460 actual: []const T,
469 ttyconf: Io.tty.Config,
461 file_writer_mode: Io.File.Writer.Mode,
470462
471463 const Self = @This();
472464
......@@ -474,13 +466,13 @@ fn SliceDiffer(comptime T: type) type {
474466 for (self.expected, 0..) |value, i| {
475467 const full_index = self.start_index + i;
476468 const diff = if (i < self.actual.len) !std.meta.eql(self.actual[i], value) else true;
477 if (diff) try self.ttyconf.setColor(writer, .red);
469 if (diff) try self.file_writer_mode.setColor(writer, .red);
478470 if (@typeInfo(T) == .pointer) {
479471 try writer.print("[{}]{*}: {any}\n", .{ full_index, value, value });
480472 } else {
481473 try writer.print("[{}]: {any}\n", .{ full_index, value });
482474 }
483 if (diff) try self.ttyconf.setColor(writer, .reset);
475 if (diff) try self.file_writer_mode.setColor(writer, .reset);
484476 }
485477 }
486478 };
......@@ -489,7 +481,7 @@ fn SliceDiffer(comptime T: type) type {
489481const BytesDiffer = struct {
490482 expected: []const u8,
491483 actual: []const u8,
492 ttyconf: Io.tty.Config,
484 file_writer_mode: Io.File.Writer.Mode,
493485
494486 pub fn write(self: BytesDiffer, writer: *Io.Writer) !void {
495487 var expected_iterator = std.mem.window(u8, self.expected, 16, 16);
......@@ -516,7 +508,7 @@ const BytesDiffer = struct {
516508 try self.writeDiff(writer, "{c}", .{byte}, diff);
517509 } else {
518510 // TODO: remove this `if` when https://github.com/ziglang/zig/issues/7600 is fixed
519 if (self.ttyconf == .windows_api) {
511 if (self.file_writer_mode == .terminal_winapi) {
520512 try self.writeDiff(writer, ".", .{}, diff);
521513 continue;
522514 }
......@@ -538,9 +530,9 @@ const BytesDiffer = struct {
538530 }
539531
540532 fn writeDiff(self: BytesDiffer, writer: *Io.Writer, comptime fmt: []const u8, args: anytype, diff: bool) !void {
541 if (diff) try self.ttyconf.setColor(writer, .red);
533 if (diff) try self.file_writer_mode.setColor(writer, .red);
542534 try writer.print(fmt, args);
543 if (diff) try self.ttyconf.setColor(writer, .reset);
535 if (diff) try self.file_writer_mode.setColor(writer, .reset);
544536 }
545537};
546538
......@@ -1162,7 +1154,6 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime
11621154 } else |err| switch (err) {
11631155 error.OutOfMemory => {
11641156 if (failing_allocator_inst.allocated_bytes != failing_allocator_inst.freed_bytes) {
1165 const tty_config: Io.tty.Config = .detect(.stderr());
11661157 print(
11671158 "\nfail_index: {d}/{d}\nallocated bytes: {d}\nfreed bytes: {d}\nallocations: {d}\ndeallocations: {d}\nallocation that was made to fail: {f}",
11681159 .{
......@@ -1174,7 +1165,6 @@ pub fn checkAllAllocationFailures(backing_allocator: std.mem.Allocator, comptime
11741165 failing_allocator_inst.deallocations,
11751166 std.debug.FormatStackTrace{
11761167 .stack_trace = failing_allocator_inst.getStackTrace(),
1177 .tty_config = tty_config,
11781168 },
11791169 },
11801170 );
lib/std/zig.zig+6-6
......@@ -53,18 +53,18 @@ pub const Color = enum {
5353 /// Assume stderr is a terminal.
5454 on,
5555
56 pub fn getTtyConf(color: Color, detected: Io.tty.Config) Io.tty.Config {
56 pub fn getTtyConf(color: Color, detected: Io.File.Writer.Mode) Io.File.Writer.Mode {
5757 return switch (color) {
5858 .auto => detected,
59 .on => .escape_codes,
60 .off => .no_color,
59 .on => .terminal_escaped,
60 .off => .streaming,
6161 };
6262 }
63 pub fn detectTtyConf(color: Color, io: Io) Io.tty.Config {
63 pub fn detectTtyConf(color: Color, io: Io) Io.File.Writer.Mode {
6464 return switch (color) {
6565 .auto => .detect(io, .stderr()),
66 .on => .escape_codes,
67 .off => .no_color,
66 .on => .terminal_escaped,
67 .off => .streaming,
6868 };
6969 }
7070};
lib/std/zig/ErrorBundle.zig+31-28
......@@ -164,15 +164,20 @@ pub const RenderOptions = struct {
164164
165165pub fn renderToStdErr(eb: ErrorBundle, options: RenderOptions, color: std.zig.Color) void {
166166 var buffer: [256]u8 = undefined;
167 const w, const ttyconf = std.debug.lockStderrWriter(&buffer);
167 const stderr = std.debug.lockStderrWriter(&buffer);
168168 defer std.debug.unlockStderrWriter();
169 renderToWriter(eb, options, w, color.getTtyConf(ttyconf)) catch return;
169 renderToWriter(eb, options, &stderr.interface, color.getTtyConf(stderr.mode)) catch return;
170170}
171171
172pub fn renderToWriter(eb: ErrorBundle, options: RenderOptions, w: *Writer, ttyconf: Io.tty.Config) (Writer.Error || std.posix.UnexpectedError)!void {
172pub fn renderToWriter(
173 eb: ErrorBundle,
174 options: RenderOptions,
175 w: *Writer,
176 fwm: Io.File.Writer.Mode,
177) Io.File.Writer.Mode.SetColorError!void {
173178 if (eb.extra.len == 0) return;
174179 for (eb.getMessages()) |err_msg| {
175 try renderErrorMessageToWriter(eb, options, err_msg, w, ttyconf, "error", .red, 0);
180 try renderErrorMessageToWriter(eb, options, err_msg, w, fwm, "error", .red, 0);
176181 }
177182
178183 if (options.include_log_text) {
......@@ -189,18 +194,18 @@ fn renderErrorMessageToWriter(
189194 options: RenderOptions,
190195 err_msg_index: MessageIndex,
191196 w: *Writer,
192 ttyconf: Io.tty.Config,
197 fwm: Io.File.Writer.Mode,
193198 kind: []const u8,
194 color: Io.tty.Color,
199 color: Io.File.Writer.Color,
195200 indent: usize,
196) (Writer.Error || std.posix.UnexpectedError)!void {
201) Io.File.Writer.Mode.SetColorError!void {
197202 const err_msg = eb.getErrorMessage(err_msg_index);
198203 if (err_msg.src_loc != .none) {
199204 const src = eb.extraData(SourceLocation, @intFromEnum(err_msg.src_loc));
200205 var prefix: Writer.Discarding = .init(&.{});
201206 try w.splatByteAll(' ', indent);
202207 prefix.count += indent;
203 try ttyconf.setColor(w, .bold);
208 try fwm.setColor(w, .bold);
204209 try w.print("{s}:{d}:{d}: ", .{
205210 eb.nullTerminatedString(src.data.src_path),
206211 src.data.line + 1,
......@@ -211,7 +216,7 @@ fn renderErrorMessageToWriter(
211216 src.data.line + 1,
212217 src.data.column + 1,
213218 });
214 try ttyconf.setColor(w, color);
219 try fwm.setColor(w, color);
215220 try w.writeAll(kind);
216221 prefix.count += kind.len;
217222 try w.writeAll(": ");
......@@ -219,17 +224,17 @@ fn renderErrorMessageToWriter(
219224 // This is the length of the part before the error message:
220225 // e.g. "file.zig:4:5: error: "
221226 const prefix_len: usize = @intCast(prefix.count);
222 try ttyconf.setColor(w, .reset);
223 try ttyconf.setColor(w, .bold);
227 try fwm.setColor(w, .reset);
228 try fwm.setColor(w, .bold);
224229 if (err_msg.count == 1) {
225230 try writeMsg(eb, err_msg, w, prefix_len);
226231 try w.writeByte('\n');
227232 } else {
228233 try writeMsg(eb, err_msg, w, prefix_len);
229 try ttyconf.setColor(w, .dim);
234 try fwm.setColor(w, .dim);
230235 try w.print(" ({d} times)\n", .{err_msg.count});
231236 }
232 try ttyconf.setColor(w, .reset);
237 try fwm.setColor(w, .reset);
233238 if (src.data.source_line != 0 and options.include_source_line) {
234239 const line = eb.nullTerminatedString(src.data.source_line);
235240 for (line) |b| switch (b) {
......@@ -242,19 +247,19 @@ fn renderErrorMessageToWriter(
242247 // -1 since span.main includes the caret
243248 const after_caret = src.data.span_end -| src.data.span_main -| 1;
244249 try w.splatByteAll(' ', src.data.column - before_caret);
245 try ttyconf.setColor(w, .green);
250 try fwm.setColor(w, .green);
246251 try w.splatByteAll('~', before_caret);
247252 try w.writeByte('^');
248253 try w.splatByteAll('~', after_caret);
249254 try w.writeByte('\n');
250 try ttyconf.setColor(w, .reset);
255 try fwm.setColor(w, .reset);
251256 }
252257 for (eb.getNotes(err_msg_index)) |note| {
253 try renderErrorMessageToWriter(eb, options, note, w, ttyconf, "note", .cyan, indent);
258 try renderErrorMessageToWriter(eb, options, note, w, fwm, "note", .cyan, indent);
254259 }
255260 if (src.data.reference_trace_len > 0 and options.include_reference_trace) {
256 try ttyconf.setColor(w, .reset);
257 try ttyconf.setColor(w, .dim);
261 try fwm.setColor(w, .reset);
262 try fwm.setColor(w, .dim);
258263 try w.print("referenced by:\n", .{});
259264 var ref_index = src.end;
260265 for (0..src.data.reference_trace_len) |_| {
......@@ -281,25 +286,25 @@ fn renderErrorMessageToWriter(
281286 );
282287 }
283288 }
284 try ttyconf.setColor(w, .reset);
289 try fwm.setColor(w, .reset);
285290 }
286291 } else {
287 try ttyconf.setColor(w, color);
292 try fwm.setColor(w, color);
288293 try w.splatByteAll(' ', indent);
289294 try w.writeAll(kind);
290295 try w.writeAll(": ");
291 try ttyconf.setColor(w, .reset);
296 try fwm.setColor(w, .reset);
292297 const msg = eb.nullTerminatedString(err_msg.msg);
293298 if (err_msg.count == 1) {
294299 try w.print("{s}\n", .{msg});
295300 } else {
296301 try w.print("{s}", .{msg});
297 try ttyconf.setColor(w, .dim);
302 try fwm.setColor(w, .dim);
298303 try w.print(" ({d} times)\n", .{err_msg.count});
299304 }
300 try ttyconf.setColor(w, .reset);
305 try fwm.setColor(w, .reset);
301306 for (eb.getNotes(err_msg_index)) |note| {
302 try renderErrorMessageToWriter(eb, options, note, w, ttyconf, "note", .cyan, indent + 4);
307 try renderErrorMessageToWriter(eb, options, note, w, fwm, "note", .cyan, indent + 4);
303308 }
304309 }
305310}
......@@ -806,12 +811,10 @@ pub const Wip = struct {
806811 };
807812 defer bundle.deinit(std.testing.allocator);
808813
809 const ttyconf: Io.tty.Config = .no_color;
810
811814 var bundle_buf: Writer.Allocating = .init(std.testing.allocator);
812815 const bundle_bw = &bundle_buf.interface;
813816 defer bundle_buf.deinit();
814 try bundle.renderToWriter(.{ .ttyconf = ttyconf }, bundle_bw);
817 try bundle.renderToWriter(bundle_bw);
815818
816819 var copy = copy: {
817820 var wip: ErrorBundle.Wip = undefined;
......@@ -827,7 +830,7 @@ pub const Wip = struct {
827830 var copy_buf: Writer.Allocating = .init(std.testing.allocator);
828831 const copy_bw = &copy_buf.interface;
829832 defer copy_buf.deinit();
830 try copy.renderToWriter(.{ .ttyconf = ttyconf }, copy_bw);
833 try copy.renderToWriter(copy_bw);
831834
832835 try std.testing.expectEqualStrings(bundle_bw.written(), copy_bw.written());
833836 }