| ... | ... | @@ -261,7 +261,6 @@ pub fn main() !void { |
| 261 | 261 | |
| 262 | 262 | var progress: std.Progress = .{}; |
| 263 | 263 | const main_progress_node = progress.start("", 0); |
| 264 | | defer main_progress_node.end(); |
| 265 | 264 | |
| 266 | 265 | builder.debug_log_scopes = debug_log_scopes.items; |
| 267 | 266 | builder.resolveInstallPrefix(install_prefix, dir_list); |
| ... | ... | @@ -323,6 +322,8 @@ fn runStepNames( |
| 323 | 322 | defer thread_pool.deinit(); |
| 324 | 323 | |
| 325 | 324 | { |
| 325 | defer parent_prog_node.end(); |
| 326 | |
| 326 | 327 | var step_prog = parent_prog_node.start("run steps", step_stack.items.len); |
| 327 | 328 | defer step_prog.end(); |
| 328 | 329 | |
| ... | ... | @@ -347,20 +348,28 @@ fn runStepNames( |
| 347 | 348 | var success_count: usize = 0; |
| 348 | 349 | var failure_count: usize = 0; |
| 349 | 350 | var pending_count: usize = 0; |
| 351 | var total_compile_errors: usize = 0; |
| 350 | 352 | |
| 351 | 353 | for (step_stack.items) |s| { |
| 352 | 354 | switch (s.state) { |
| 353 | 355 | .precheck_unstarted => unreachable, |
| 354 | 356 | .precheck_started => unreachable, |
| 355 | 357 | .running => unreachable, |
| 356 | | // precheck_done is equivalent to dependency_failure in the case of |
| 357 | | // transitive dependencies. For example: |
| 358 | | // A -> B -> C (failure) |
| 359 | | // B will be marked as dependency_failure, while A may never be queued, and thus |
| 360 | | // remain in the initial state of precheck_done. |
| 361 | | .dependency_failure, .precheck_done => pending_count += 1, |
| 358 | .precheck_done => { |
| 359 | // precheck_done is equivalent to dependency_failure in the case of |
| 360 | // transitive dependencies. For example: |
| 361 | // A -> B -> C (failure) |
| 362 | // B will be marked as dependency_failure, while A may never be queued, and thus |
| 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 | 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 | 380 | const stderr = std.io.getStdErr(); |
| 372 | 381 | |
| 373 | 382 | const total_count = success_count + failure_count + pending_count; |
| 374 | | stderr.writer().print("build summary: {d}/{d} steps succeeded; {d} failed\n", .{ |
| 375 | | success_count, total_count, failure_count, |
| 383 | ttyconf.setColor(stderr, .Cyan) catch {}; |
| 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 | 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 | 403 | if (failure_count == 0) return cleanExit(); |
| 379 | 404 | |
| 380 | | for (step_stack.items) |s| switch (s.state) { |
| 381 | | .failure => { |
| 382 | | // TODO print the dep prefix too |
| 383 | | ttyconf.setColor(stderr, .Bold) catch break; |
| 384 | | stderr.writeAll(s.name) catch break; |
| 385 | | ttyconf.setColor(stderr, .Reset) catch break; |
| 405 | // Finally, render compile errors at the bottom of the terminal. |
| 406 | if (total_compile_errors > 0) { |
| 407 | for (step_stack.items) |s| { |
| 408 | if (s.result_error_bundle.errorMessageCount() > 0) { |
| 409 | s.result_error_bundle.renderToStdErr(ttyconf); |
| 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 | 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 | 477 | s.result_error_bundle.errorMessageCount(), |
| 390 | | }) catch break; |
| 391 | | s.result_error_bundle.renderToStdErr(ttyconf); |
| 478 | }); |
| 392 | 479 | } else { |
| 393 | | stderr.writer().print(": {d} error messages (printed above)\n", .{ |
| 394 | | s.result_error_msgs.items.len, |
| 395 | | }) catch break; |
| 480 | try stderr.writeAll(" failure\n"); |
| 396 | 481 | } |
| 482 | try ttyconf.setColor(stderr, .Reset); |
| 397 | 483 | }, |
| 398 | | else => continue, |
| 399 | | }; |
| 484 | } |
| 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 | 495 | fn checkForDependencyLoop( |