| ... | @@ -261,7 +261,6 @@ pub fn main() !void { | ... | @@ -261,7 +261,6 @@ pub fn main() !void { |
| 261 | | 261 | |
| 262 | var progress: std.Progress = .{}; | 262 | var progress: std.Progress = .{}; |
| 263 | const main_progress_node = progress.start("", 0); | 263 | const main_progress_node = progress.start("", 0); |
| 264 | defer main_progress_node.end(); | | |
| 265 | | 264 | |
| 266 | builder.debug_log_scopes = debug_log_scopes.items; | 265 | builder.debug_log_scopes = debug_log_scopes.items; |
| 267 | builder.resolveInstallPrefix(install_prefix, dir_list); | 266 | builder.resolveInstallPrefix(install_prefix, dir_list); |
| ... | @@ -323,6 +322,8 @@ fn runStepNames( | ... | @@ -323,6 +322,8 @@ fn runStepNames( |
| 323 | defer thread_pool.deinit(); | 322 | defer thread_pool.deinit(); |
| 324 | | 323 | |
| 325 | { | 324 | { |
| | 325 | defer parent_prog_node.end(); |
| | 326 | |
| 326 | var step_prog = parent_prog_node.start("run steps", step_stack.items.len); | 327 | var step_prog = parent_prog_node.start("run steps", step_stack.items.len); |
| 327 | defer step_prog.end(); | 328 | defer step_prog.end(); |
| 328 | | 329 | |
| ... | @@ -347,20 +348,28 @@ fn runStepNames( | ... | @@ -347,20 +348,28 @@ fn runStepNames( |
| 347 | var success_count: usize = 0; | 348 | var success_count: usize = 0; |
| 348 | var failure_count: usize = 0; | 349 | var failure_count: usize = 0; |
| 349 | var pending_count: usize = 0; | 350 | var pending_count: usize = 0; |
| | 351 | var total_compile_errors: usize = 0; |
| 350 | | 352 | |
| 351 | for (step_stack.items) |s| { | 353 | for (step_stack.items) |s| { |
| 352 | switch (s.state) { | 354 | switch (s.state) { |
| 353 | .precheck_unstarted => unreachable, | 355 | .precheck_unstarted => unreachable, |
| 354 | .precheck_started => unreachable, | 356 | .precheck_started => unreachable, |
| 355 | .running => unreachable, | 357 | .running => unreachable, |
| 356 | // precheck_done is equivalent to dependency_failure in the case of | 358 | .precheck_done => { |
| 357 | // transitive dependencies. For example: | 359 | // precheck_done is equivalent to dependency_failure in the case of |
| 358 | // A -> B -> C (failure) | 360 | // transitive dependencies. For example: |
| 359 | // B will be marked as dependency_failure, while A may never be queued, and thus | 361 | // A -> B -> C (failure) |
| 360 | // remain in the initial state of precheck_done. | 362 | // B will be marked as dependency_failure, while A may never be queued, and thus |
| 361 | .dependency_failure, .precheck_done => pending_count += 1, | 363 | // remain in the initial state of precheck_done. |
| | 364 | s.state = .dependency_failure; |
| | 365 | pending_count += 1; |
| | 366 | }, |
| | 367 | .dependency_failure => pending_count += 1, |
| 362 | .success => success_count += 1, | 368 | .success => success_count += 1, |
| 363 | .failure => failure_count += 1, | 369 | .failure => { |
| | 370 | failure_count += 1; |
| | 371 | total_compile_errors += s.result_error_bundle.errorMessageCount(); |
| | 372 | }, |
| 364 | } | 373 | } |
| 365 | } | 374 | } |
| 366 | | 375 | |
| ... | @@ -371,34 +380,116 @@ fn runStepNames( | ... | @@ -371,34 +380,116 @@ fn runStepNames( |
| 371 | const stderr = std.io.getStdErr(); | 380 | const stderr = std.io.getStdErr(); |
| 372 | | 381 | |
| 373 | const total_count = success_count + failure_count + pending_count; | 382 | const total_count = success_count + failure_count + pending_count; |
| 374 | stderr.writer().print("build summary: {d}/{d} steps succeeded; {d} failed\n", .{ | 383 | ttyconf.setColor(stderr, .Cyan) catch {}; |
| 375 | success_count, total_count, failure_count, | 384 | stderr.writeAll("Build Summary: ") catch {}; |
| | 385 | ttyconf.setColor(stderr, .Reset) catch {}; |
| | 386 | stderr.writer().print("{d}/{d} steps succeeded; {d} failed; {d} total compile errors\n", .{ |
| | 387 | success_count, total_count, failure_count, total_compile_errors, |
| 376 | }) catch {}; | 388 | }) catch {}; |
| 377 | | 389 | |
| | 390 | // Print a fancy tree with build results. |
| | 391 | var print_node: PrintNode = .{ .parent = null }; |
| | 392 | if (step_names.len == 0) { |
| | 393 | print_node.last = true; |
| | 394 | printTreeStep(b, b.default_step, stderr, ttyconf, &print_node) catch {}; |
| | 395 | } else { |
| | 396 | for (step_names, 0..) |step_name, i| { |
| | 397 | const tls = b.top_level_steps.get(step_name).?; |
| | 398 | print_node.last = i + 1 == b.top_level_steps.count(); |
| | 399 | printTreeStep(b, &tls.step, stderr, ttyconf, &print_node) catch {}; |
| | 400 | } |
| | 401 | } |
| | 402 | |
| 378 | if (failure_count == 0) return cleanExit(); | 403 | if (failure_count == 0) return cleanExit(); |
| 379 | | 404 | |
| 380 | for (step_stack.items) |s| switch (s.state) { | 405 | // Finally, render compile errors at the bottom of the terminal. |
| 381 | .failure => { | 406 | if (total_compile_errors > 0) { |
| 382 | // TODO print the dep prefix too | 407 | for (step_stack.items) |s| { |
| 383 | ttyconf.setColor(stderr, .Bold) catch break; | 408 | if (s.result_error_bundle.errorMessageCount() > 0) { |
| 384 | stderr.writeAll(s.name) catch break; | 409 | s.result_error_bundle.renderToStdErr(ttyconf); |
| 385 | ttyconf.setColor(stderr, .Reset) catch break; | 410 | } |
| | 411 | } |
| | 412 | |
| | 413 | // Signal to parent process that we have printed compile errors. The |
| | 414 | // parent process may choose to omit the "following command failed" |
| | 415 | // line in this case. |
| | 416 | process.exit(2); |
| | 417 | } |
| 386 | | 418 | |
| | 419 | process.exit(1); |
| | 420 | } |
| | 421 | |
| | 422 | const PrintNode = struct { |
| | 423 | parent: ?*PrintNode, |
| | 424 | last: bool = false, |
| | 425 | }; |
| | 426 | |
| | 427 | fn printTreeStep( |
| | 428 | b: *std.Build, |
| | 429 | s: *Step, |
| | 430 | stderr: std.fs.File, |
| | 431 | ttyconf: std.debug.TTY.Config, |
| | 432 | parent_node: *PrintNode, |
| | 433 | ) !void { |
| | 434 | var opt_node: ?*PrintNode = parent_node.parent; |
| | 435 | while (opt_node) |n| : (opt_node = n.parent) { |
| | 436 | if (n.parent == null) break; |
| | 437 | if (n.last) { |
| | 438 | try stderr.writeAll(" "); |
| | 439 | } else { |
| | 440 | try stderr.writeAll("│ "); |
| | 441 | } |
| | 442 | } |
| | 443 | |
| | 444 | if (parent_node.parent != null) { |
| | 445 | if (parent_node.last) { |
| | 446 | try stderr.writeAll("└─ "); |
| | 447 | } else { |
| | 448 | try stderr.writeAll("├─ "); |
| | 449 | } |
| | 450 | } |
| | 451 | |
| | 452 | // TODO print the dep prefix too? |
| | 453 | try stderr.writeAll(s.name); |
| | 454 | |
| | 455 | switch (s.state) { |
| | 456 | .precheck_unstarted => unreachable, |
| | 457 | .precheck_started => unreachable, |
| | 458 | .precheck_done => unreachable, |
| | 459 | .running => unreachable, |
| | 460 | |
| | 461 | .dependency_failure => { |
| | 462 | try ttyconf.setColor(stderr, .Dim); |
| | 463 | try stderr.writeAll(" transitive failure\n"); |
| | 464 | try ttyconf.setColor(stderr, .Reset); |
| | 465 | }, |
| | 466 | |
| | 467 | .success => { |
| | 468 | try ttyconf.setColor(stderr, .Green); |
| | 469 | try stderr.writeAll(" success\n"); |
| | 470 | try ttyconf.setColor(stderr, .Reset); |
| | 471 | }, |
| | 472 | |
| | 473 | .failure => { |
| | 474 | try ttyconf.setColor(stderr, .Red); |
| 387 | if (s.result_error_bundle.errorMessageCount() > 0) { | 475 | if (s.result_error_bundle.errorMessageCount() > 0) { |
| 388 | stderr.writer().print(": {d} compilation errors:\n", .{ | 476 | try stderr.writer().print(" {d} errors\n", .{ |
| 389 | s.result_error_bundle.errorMessageCount(), | 477 | s.result_error_bundle.errorMessageCount(), |
| 390 | }) catch break; | 478 | }); |
| 391 | s.result_error_bundle.renderToStdErr(ttyconf); | | |
| 392 | } else { | 479 | } else { |
| 393 | stderr.writer().print(": {d} error messages (printed above)\n", .{ | 480 | try stderr.writeAll(" failure\n"); |
| 394 | s.result_error_msgs.items.len, | | |
| 395 | }) catch break; | | |
| 396 | } | 481 | } |
| | 482 | try ttyconf.setColor(stderr, .Reset); |
| 397 | }, | 483 | }, |
| 398 | else => continue, | 484 | } |
| 399 | }; | | |
| 400 | | 485 | |
| 401 | process.exit(1); | 486 | for (s.dependencies.items, 0..) |dep, i| { |
| | 487 | var print_node: PrintNode = .{ |
| | 488 | .parent = parent_node, |
| | 489 | .last = i == s.dependencies.items.len - 1, |
| | 490 | }; |
| | 491 | try printTreeStep(b, dep, stderr, ttyconf, &print_node); |
| | 492 | } |
| 402 | } | 493 | } |
| 403 | | 494 | |
| 404 | fn checkForDependencyLoop( | 495 | fn checkForDependencyLoop( |