Commit 7d5bce56e1

Andrew Kelley <andrew@ziglang.org>
2023-03-10 07:56:12
build runner: print to stderr in dumb terminals
Terminal progress is suppressed and instead there is an explicit handling of printing to stderr, one line per step make() function call. The output looks very similar to Ninja. A future commit should add a -q to quiet the output.
1 parent 097bcca
Changed files (1)
lib/build_runner.zig
@@ -278,8 +278,12 @@ pub fn main() !void {
         .windows_api => {},
     }
 
-    var progress: std.Progress = .{ .dont_print_on_dumb = true };
+    var progress: std.Progress = .{};
     const main_progress_node = progress.start("", 0);
+    if (ttyconf == .no_color) {
+        progress.timer = null;
+        progress.terminal = null;
+    }
 
     builder.debug_log_scopes = debug_log_scopes.items;
     builder.resolveInstallPrefix(install_prefix, dir_list);
@@ -302,6 +306,9 @@ pub fn main() !void {
         .enable_summary = enable_summary,
         .ttyconf = ttyconf,
         .stderr = stderr,
+
+        .step_index = 0,
+        .step_count = undefined,
     };
 
     if (run.max_rss == 0) {
@@ -332,6 +339,9 @@ const Run = struct {
     enable_summary: ?bool,
     ttyconf: std.debug.TTY.Config,
     stderr: std.fs.File,
+
+    step_count: usize,
+    step_index: usize,
 };
 
 fn runStepNames(
@@ -395,7 +405,8 @@ fn runStepNames(
     {
         defer parent_prog_node.end();
 
-        var step_prog = parent_prog_node.start("run steps", step_stack.count());
+        run.step_count = step_stack.count();
+        var step_prog = parent_prog_node.start("run steps", run.step_count);
         defer step_prog.end();
 
         var wait_group: std.Thread.WaitGroup = .{};
@@ -739,10 +750,27 @@ fn workerMakeOneStep(
     sub_prog_node.activate();
     defer sub_prog_node.end();
 
-    // I suspect we will want to pass `b` to make() in a future modification.
-    // For example, CompileStep does some sus things with modifying the saved
-    // *Build object in install header steps that might be able to be removed
-    // by passing the *Build object through the make() functions.
+    const stderr = run.stderr;
+    const ttyconf = run.ttyconf;
+
+    // If we are unable to print a fancy terminal progress bar, then we resort
+    // to 1 line printed to stderr for each step, similar to Ninja.
+    if (ttyconf == .no_color) {
+        var buf: [120]u8 = undefined;
+        const step_index = @atomicRmw(usize, &run.step_index, .Add, 1, .Monotonic);
+        const text = std.fmt.bufPrint(&buf, "[{d}/{d}] Making {s}{s}\n", .{
+            step_index + 1, run.step_count, s.owner.dep_prefix, s.name,
+        }) catch |err| switch (err) {
+            error.NoSpaceLeft => blk: {
+                buf[buf.len - 4 ..].* = "...\n".*;
+                break :blk &buf;
+            },
+        };
+        std.debug.getStderrMutex().lock();
+        defer std.debug.getStderrMutex().unlock();
+        stderr.writeAll(text) catch {};
+    }
+
     const make_result = s.make(&sub_prog_node);
 
     // No matter the result, we want to display error/warning messages.
@@ -750,9 +778,6 @@ fn workerMakeOneStep(
         sub_prog_node.context.lock_stderr();
         defer sub_prog_node.context.unlock_stderr();
 
-        const stderr = run.stderr;
-        const ttyconf = run.ttyconf;
-
         for (s.result_error_msgs.items) |msg| {
             // Sometimes it feels like you just can't catch a break. Finally,
             // with Zig, you can.