this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 687 lines 24 kB view raw
1#!/usr/bin/env bash 2# build-trivial.sh — Attempt to build trivial Nix derivations inside Darling 3# 4# This script exercises Phase 4.1 of the plan: building progressively more 5# complex derivations inside a Darling prefix to validate that the full Nix 6# build pipeline works (posix_spawn → sandbox-exec → builder → store). 7# 8# Usage: 9# ./scripts/build-trivial.sh [OPTIONS] 10# 11# Options: 12# --prefix <path> Darling prefix path (default: ~/.darling or $DPREFIX) 13# --level <N> Run only derivation level N (1-5, default: all) 14# --keep Don't garbage-collect built derivations 15# --verbose Show full nix-build output 16# --debug Pass -vvvv --debug to nix-build (very verbose) 17# --help Show this help message 18# 19# Derivation Levels: 20# 1 — Echo to $out (no deps, /bin/bash only) 21# 2 — Multi-line builder script writing to $out 22# 3 — Derivation that reads and transforms input files 23# 4 — Derivation with a dependency on another derivation 24# 5 — Fetch a file from the binary cache (requires network) 25# 26# Exit codes: 27# 0 — all attempted levels passed 28# 1 — one or more levels failed 29# 2 — infrastructure error 30# 31# See: plan/06-phase4-building.md (Task 4.1) 32 33set -euo pipefail 34 35SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 36 37# ── Defaults ──────────────────────────────────────────────────────────────── 38 39DARLING_PREFIX="${DPREFIX:-$HOME/.darling}" 40SELECTED_LEVEL="" 41KEEP_BUILDS=0 42VERBOSE=0 43DEBUG=0 44 45# ── Colors ────────────────────────────────────────────────────────────────── 46 47if [ -t 1 ]; then 48 RED='\033[0;31m' 49 GREEN='\033[0;32m' 50 YELLOW='\033[0;33m' 51 BLUE='\033[0;34m' 52 BOLD='\033[1m' 53 DIM='\033[2m' 54 RESET='\033[0m' 55else 56 RED='' GREEN='' YELLOW='' BLUE='' BOLD='' DIM='' RESET='' 57fi 58 59# ── Helpers ───────────────────────────────────────────────────────────────── 60 61log() { echo -e "${GREEN}[build-trivial]${RESET} $*"; } 62warn() { echo -e "${YELLOW}[build-trivial] WARNING:${RESET} $*" >&2; } 63err() { echo -e "${RED}[build-trivial] ERROR:${RESET} $*" >&2; } 64fatal() { err "$@"; exit 2; } 65 66dsh() { 67 darling shell "$@" 68} 69 70# Run a command inside Darling with Nix on PATH 71dsh_nix() { 72 local nix_flags="" 73 if [ "$DEBUG" -eq 1 ]; then 74 nix_flags="-vvvv --debug" 75 fi 76 77 darling shell bash -lc " 78 # Source Nix profile 79 if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ]; then 80 . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' 81 elif [ -e \"\\\$HOME/.nix-profile/etc/profile.d/nix.sh\" ]; then 82 . \"\\\$HOME/.nix-profile/etc/profile.d/nix.sh\" 83 elif [ -e '/etc/profile.d/nix-darling.sh' ]; then 84 . '/etc/profile.d/nix-darling.sh' 85 fi 86 $* 87 " 2>&1 88} 89 90usage() { 91 cat <<'EOF' 92Usage: ./scripts/build-trivial.sh [OPTIONS] 93 94Build progressively more complex Nix derivations inside Darling to validate 95the full build pipeline. 96 97Options: 98 --prefix <path> Darling prefix (default: ~/.darling or $DPREFIX) 99 --level <N> Run only level N (1-5; default: all) 100 --keep Don't garbage-collect built derivations 101 --verbose Show full nix-build output 102 --debug Pass -vvvv --debug to nix-build 103 --help Show this help 104 105Levels: 106 1 Echo to $out — minimal: /bin/bash writes a one-liner to $out 107 2 Multi-line builder — bash script with variables, loops, file I/O 108 3 Input transformation — derivation that reads from an input file 109 4 Derivation dependency — one derivation depends on another 110 5 Binary substitution — fetch a pre-built path from cache.nixos.org 111 112Each level exercises more of the Nix + Darling stack. If a level fails, 113the script prints debugging hints specific to that level's failure mode. 114EOF 115 exit 0 116} 117 118# ── Argument Parsing ──────────────────────────────────────────────────────── 119 120while [ $# -gt 0 ]; do 121 case "$1" in 122 --prefix) 123 [ $# -ge 2 ] || fatal "--prefix requires an argument" 124 DARLING_PREFIX="$2" 125 shift 2 126 ;; 127 --level) 128 [ $# -ge 2 ] || fatal "--level requires an argument" 129 SELECTED_LEVEL="$2" 130 if ! [[ "$SELECTED_LEVEL" =~ ^[1-5]$ ]]; then 131 fatal "--level must be 1-5, got: $SELECTED_LEVEL" 132 fi 133 shift 2 134 ;; 135 --keep) 136 KEEP_BUILDS=1 137 shift 138 ;; 139 --verbose|-v) 140 VERBOSE=1 141 shift 142 ;; 143 --debug) 144 DEBUG=1 145 VERBOSE=1 146 shift 147 ;; 148 --help|-h) 149 usage 150 ;; 151 *) 152 fatal "Unknown option: $1 (try --help)" 153 ;; 154 esac 155done 156 157# ── Preflight ─────────────────────────────────────────────────────────────── 158 159log "${BOLD}Preflight checks...${RESET}" 160 161if ! command -v darling &>/dev/null; then 162 fatal "darling is not in PATH" 163fi 164 165if [ ! -d "$DARLING_PREFIX" ]; then 166 fatal "Darling prefix not found at $DARLING_PREFIX" 167fi 168 169if ! dsh echo ok &>/dev/null; then 170 fatal "darling shell is not functional" 171fi 172 173# Check Nix is installed 174nix_version="" 175nix_version=$(dsh_nix "nix --version" 2>&1) || true 176if [ -z "$nix_version" ] || ! echo "$nix_version" | grep -qi "nix"; then 177 fatal "Nix does not appear to be installed in the Darling prefix.\n" \ 178 " Run: ./scripts/install-nix-in-darling.sh" 179fi 180 181log " Prefix: $DARLING_PREFIX" 182log " Nix: $nix_version" 183 184# ── Level Definitions ─────────────────────────────────────────────────────── 185 186# Each level is a function that: 187# - Prints what it exercises 188# - Runs the build 189# - Returns 0 on success, 1 on failure 190 191level1_echo_to_out() { 192 cat <<'DESC' 193 Level 1: Echo to $out 194 Exercises: posix_spawn, sandbox-exec stub, /bin/bash, file creation 195 in /nix/store, store path registration, chmod/lchflags on 196 store path. 197DESC 198 199 local expr='derivation { 200 name = "darling-test-1-echo"; 201 builder = "/bin/bash"; 202 args = [ "-c" "echo Hello from Darling > $out" ]; 203 system = "x86_64-darwin"; 204 }' 205 206 local nix_flags="" 207 if [ "$DEBUG" -eq 1 ]; then 208 nix_flags="-vvvv" 209 fi 210 211 local output="" 212 local exit_code=0 213 output=$(dsh_nix "nix-build --no-out-link $nix_flags --expr '$expr' 2>&1") || exit_code=$? 214 215 if [ "$VERBOSE" -eq 1 ]; then 216 echo "$output" | sed 's/^/ /' 217 fi 218 219 if [ "$exit_code" -ne 0 ]; then 220 echo "$output" | tail -20 | sed 's/^/ /' 221 echo "" 222 echo " Debugging hints for Level 1 failure:" 223 echo " • 'clearing flags of path': lchflags still broken (Phase 1.1)" 224 echo " • 'Bad file descriptor' / ENOEXEC: sandbox-exec stub issue (Phase 2)" 225 echo " • 'sandbox profile' write fail: check /tmp is writable inside prefix" 226 echo " • Builder hangs: posix_spawn with POSIX_SPAWN_SETEXEC broken" 227 echo " • 'Unimplemented syscall': check plan/syscall-triage.md" 228 echo "" 229 echo " Manual reproduction:" 230 echo " darling shell bash -lc 'nix-build -vvvv --no-out-link --expr \"$expr\"'" 231 echo " darling shell /usr/bin/sandbox-exec -f /dev/null /bin/bash -c 'echo ok'" 232 return 1 233 fi 234 235 # Verify the output exists and has the right content 236 local store_path 237 store_path=$(echo "$output" | grep '^/nix/store/' | tail -1) 238 if [ -z "$store_path" ]; then 239 echo " Build appeared to succeed but no store path in output." 240 echo " Output: $output" 241 return 1 242 fi 243 244 local content 245 content=$(dsh_nix "cat '$store_path'" 2>&1) || true 246 if echo "$content" | grep -q "Hello from Darling"; then 247 echo " Store path: $store_path" 248 echo " Content: $(echo "$content" | head -1)" 249 return 0 250 else 251 echo " Store path content mismatch." 252 echo " Expected: 'Hello from Darling'" 253 echo " Got: '$content'" 254 return 1 255 fi 256} 257 258level2_multiline_builder() { 259 cat <<'DESC' 260 Level 2: Multi-line builder script 261 Exercises: bash scripting, variables, loops, file I/O, mkdir, directory 262 output (vs single file), multiple files in $out. 263DESC 264 265 local expr='derivation { 266 name = "darling-test-2-multiline"; 267 builder = "/bin/bash"; 268 args = [ "-c" " 269 set -e 270 mkdir -p $out/bin $out/share 271 echo \"#!/bin/bash\" > $out/bin/hello 272 echo \"echo Hello from Darling build\" >> $out/bin/hello 273 chmod +x $out/bin/hello 274 for i in 1 2 3; do 275 echo \"Item $i\" > $out/share/item-$i.txt 276 done 277 echo done > $out/share/status.txt 278 " ]; 279 system = "x86_64-darwin"; 280 }' 281 282 local nix_flags="" 283 if [ "$DEBUG" -eq 1 ]; then 284 nix_flags="-vvvv" 285 fi 286 287 local output="" 288 local exit_code=0 289 output=$(dsh_nix "nix-build --no-out-link $nix_flags --expr '$expr' 2>&1") || exit_code=$? 290 291 if [ "$VERBOSE" -eq 1 ]; then 292 echo "$output" | sed 's/^/ /' 293 fi 294 295 if [ "$exit_code" -ne 0 ]; then 296 echo "$output" | tail -20 | sed 's/^/ /' 297 echo "" 298 echo " Debugging hints for Level 2 failure:" 299 echo " • mkdir/chmod failures: filesystem or syscall issue" 300 echo " • 'for' loop issues: bash not fully working in sandbox" 301 echo " • Same as Level 1 hints if Level 1 also failed" 302 return 1 303 fi 304 305 local store_path 306 store_path=$(echo "$output" | grep '^/nix/store/' | tail -1) 307 if [ -z "$store_path" ]; then 308 echo " No store path in output." 309 return 1 310 fi 311 312 # Verify directory structure 313 local verify_exit=0 314 dsh_nix " 315 test -x '$store_path/bin/hello' && 316 test -f '$store_path/share/item-1.txt' && 317 test -f '$store_path/share/item-2.txt' && 318 test -f '$store_path/share/item-3.txt' && 319 test -f '$store_path/share/status.txt' && 320 grep -q 'done' '$store_path/share/status.txt' 321 " >/dev/null 2>&1 || verify_exit=$? 322 323 if [ "$verify_exit" -eq 0 ]; then 324 echo " Store path: $store_path" 325 echo " Verified: bin/hello (executable), share/item-{1,2,3}.txt, share/status.txt" 326 return 0 327 else 328 echo " Output verification failed." 329 echo " Store path: $store_path" 330 dsh_nix "find '$store_path' -type f 2>/dev/null" | sed 's/^/ /' || true 331 return 1 332 fi 333} 334 335level3_input_transform() { 336 cat <<'DESC' 337 Level 3: Input transformation 338 Exercises: builtins.toFile, passing string context to a derivation, 339 reading input files, text processing (wc, sort). 340DESC 341 342 local expr='let 343 input = builtins.toFile "input.txt" "apple\nbanana\ncherry\ndate\nelderberry\n"; 344 in derivation { 345 name = "darling-test-3-transform"; 346 builder = "/bin/bash"; 347 args = [ "-c" " 348 set -e 349 mkdir -p $out 350 cp ${input} $out/original.txt 351 sort ${input} > $out/sorted.txt 352 wc -l < ${input} | tr -d \" \" > $out/count.txt 353 " ]; 354 system = "x86_64-darwin"; 355 inherit input; 356 }' 357 358 local nix_flags="" 359 if [ "$DEBUG" -eq 1 ]; then 360 nix_flags="-vvvv" 361 fi 362 363 local output="" 364 local exit_code=0 365 output=$(dsh_nix "nix-build --no-out-link $nix_flags --expr '$expr' 2>&1") || exit_code=$? 366 367 if [ "$VERBOSE" -eq 1 ]; then 368 echo "$output" | sed 's/^/ /' 369 fi 370 371 if [ "$exit_code" -ne 0 ]; then 372 echo "$output" | tail -20 | sed 's/^/ /' 373 echo "" 374 echo " Debugging hints for Level 3 failure:" 375 echo " • builtins.toFile failure: store write issue" 376 echo " • sort/wc not found: PATH issue inside build sandbox" 377 echo " • Input file not readable: store path access issue" 378 return 1 379 fi 380 381 local store_path 382 store_path=$(echo "$output" | grep '^/nix/store/' | tail -1) 383 if [ -z "$store_path" ]; then 384 echo " No store path in output." 385 return 1 386 fi 387 388 local count 389 count=$(dsh_nix "cat '$store_path/count.txt'" 2>&1 | tr -d '[:space:]') 390 if [ "$count" = "5" ]; then 391 echo " Store path: $store_path" 392 echo " Line count: $count (correct)" 393 return 0 394 else 395 echo " Count verification failed: expected '5', got '$count'" 396 return 1 397 fi 398} 399 400level4_derivation_dependency() { 401 cat <<'DESC' 402 Level 4: Derivation dependency 403 Exercises: one derivation depending on another's output, Nix's dependency 404 tracking, incremental builds, store path references. 405DESC 406 407 local expr='let 408 dep = derivation { 409 name = "darling-test-4-dep"; 410 builder = "/bin/bash"; 411 args = [ "-c" "echo DEPENDENCY_OUTPUT > $out" ]; 412 system = "x86_64-darwin"; 413 }; 414 in derivation { 415 name = "darling-test-4-consumer"; 416 builder = "/bin/bash"; 417 args = [ "-c" " 418 set -e 419 mkdir -p $out 420 content=\$(cat ${dep}) 421 echo \"Read from dep: \$content\" > $out/result.txt 422 echo ${dep} > $out/dep-path.txt 423 " ]; 424 system = "x86_64-darwin"; 425 inherit dep; 426 }' 427 428 local nix_flags="" 429 if [ "$DEBUG" -eq 1 ]; then 430 nix_flags="-vvvv" 431 fi 432 433 local output="" 434 local exit_code=0 435 output=$(dsh_nix "nix-build --no-out-link $nix_flags --expr '$expr' 2>&1") || exit_code=$? 436 437 if [ "$VERBOSE" -eq 1 ]; then 438 echo "$output" | sed 's/^/ /' 439 fi 440 441 if [ "$exit_code" -ne 0 ]; then 442 echo "$output" | tail -20 | sed 's/^/ /' 443 echo "" 444 echo " Debugging hints for Level 4 failure:" 445 echo " • If dep itself failed: same as Level 1/2 hints" 446 echo " • If consumer failed reading dep: store path access issue" 447 echo " • Build order issue: Nix should build dep first automatically" 448 return 1 449 fi 450 451 local store_path 452 store_path=$(echo "$output" | grep '^/nix/store/' | tail -1) 453 if [ -z "$store_path" ]; then 454 echo " No store path in output." 455 return 1 456 fi 457 458 local result 459 result=$(dsh_nix "cat '$store_path/result.txt'" 2>&1) 460 if echo "$result" | grep -q "DEPENDENCY_OUTPUT"; then 461 echo " Store path: $store_path" 462 echo " Result: $result" 463 echo " Dep path: $(dsh_nix "cat '$store_path/dep-path.txt'" 2>&1 | head -1)" 464 return 0 465 else 466 echo " Dependency content not found in result." 467 echo " Expected to contain: 'DEPENDENCY_OUTPUT'" 468 echo " Got: '$result'" 469 return 1 470 fi 471} 472 473level5_binary_substitution() { 474 cat <<'DESC' 475 Level 5: Binary substitution (requires network) 476 Exercises: curl/TLS, binary cache access, NAR download, signature 477 verification, store path registration from remote. 478DESC 479 480 # Check if we can reach the cache first 481 local cache_check="" 482 cache_check=$(dsh_nix "curl -sfI https://cache.nixos.org/nix-cache-info 2>&1 | head -1") || true 483 if ! echo "$cache_check" | grep -qi "200"; then 484 echo " Cannot reach cache.nixos.org — skipping Level 5." 485 echo " (This level requires network access.)" 486 echo " cache check result: $cache_check" 487 return 2 # special: skip, not fail 488 fi 489 490 # Try to realise a simple, very small store path from the cache. 491 # We use `nix-store -r` on a known path, or `nix build` with --substituters. 492 # The safest approach: evaluate a nixpkgs attr and fetch it. 493 local output="" 494 local exit_code=0 495 output=$(dsh_nix " 496 # Try to fetch a tiny package from the cache. 497 # 'hello' is small and almost always cached. 498 nix build --no-link --print-out-paths \\ 499 --expr '(import <nixpkgs> {}).hello' \\ 500 --substituters https://cache.nixos.org \\ 501 --trusted-public-keys 'cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=' \\ 502 2>&1 503 ") || exit_code=$? 504 505 if [ "$VERBOSE" -eq 1 ]; then 506 echo "$output" | sed 's/^/ /' 507 fi 508 509 if [ "$exit_code" -ne 0 ]; then 510 echo "$output" | tail -20 | sed 's/^/ /' 511 echo "" 512 echo " Debugging hints for Level 5 failure:" 513 echo " • 'SSL' / 'TLS' error: Darling's certificate bundle may be outdated" 514 echo " • 'cannot connect': DNS or network issue inside Darling" 515 echo " • '<nixpkgs>' not found: channels not set up — run nix-channel --update" 516 echo " • NAR download failure: curl or decompression issue" 517 echo " • Signature mismatch: trusted-public-keys not configured" 518 return 1 519 fi 520 521 local store_path 522 store_path=$(echo "$output" | grep '^/nix/store/' | tail -1) 523 if [ -z "$store_path" ]; then 524 echo " Build output did not contain a store path." 525 echo " Output: $(echo "$output" | tail -5)" 526 return 1 527 fi 528 529 # Try running the fetched hello binary 530 local hello_output 531 hello_output=$(dsh_nix "'$store_path/bin/hello'" 2>&1) || true 532 if echo "$hello_output" | grep -qi "hello"; then 533 echo " Store path: $store_path" 534 echo " Output: $hello_output" 535 return 0 536 else 537 echo " Store path: $store_path" 538 echo " hello binary did not produce expected output: $hello_output" 539 echo " (This may be OK — the binary was fetched, which is the main test.)" 540 return 0 541 fi 542} 543 544# ── Determine which levels to run ────────────────────────────────────────── 545 546ALL_LEVELS=(1 2 3 4 5) 547 548if [ -n "$SELECTED_LEVEL" ]; then 549 RUN_LEVELS=("$SELECTED_LEVEL") 550else 551 RUN_LEVELS=("${ALL_LEVELS[@]}") 552fi 553 554# ── Execute ───────────────────────────────────────────────────────────────── 555 556echo "" 557log "${BOLD}═══════════════════════════════════════════════════════════${RESET}" 558log "${BOLD} Trivial Derivation Build Tests (Phase 4.1)${RESET}" 559log "${BOLD}═══════════════════════════════════════════════════════════${RESET}" 560echo "" 561 562LEVELS_PASSED=0 563LEVELS_FAILED=0 564LEVELS_SKIPPED=0 565 566declare -A LEVEL_RESULT # "pass", "fail", "skip" 567LEVEL_NAMES=( 568 [1]="Echo to \$out" 569 [2]="Multi-line builder" 570 [3]="Input transformation" 571 [4]="Derivation dependency" 572 [5]="Binary substitution (network)" 573) 574 575LEVEL_FUNCS=( 576 [1]=level1_echo_to_out 577 [2]=level2_multiline_builder 578 [3]=level3_input_transform 579 [4]=level4_derivation_dependency 580 [5]=level5_binary_substitution 581) 582 583for level in "${RUN_LEVELS[@]}"; do 584 echo -e "${BLUE}━━━ Level $level: ${LEVEL_NAMES[$level]} ━━━${RESET}" 585 echo "" 586 587 exit_code=0 588 ${LEVEL_FUNCS[$level]} || exit_code=$? 589 590 echo "" 591 592 if [ "$exit_code" -eq 0 ]; then 593 LEVELS_PASSED=$((LEVELS_PASSED + 1)) 594 LEVEL_RESULT[$level]="pass" 595 echo -e " ${GREEN}✓ Level $level PASSED${RESET}" 596 elif [ "$exit_code" -eq 2 ]; then 597 LEVELS_SKIPPED=$((LEVELS_SKIPPED + 1)) 598 LEVEL_RESULT[$level]="skip" 599 echo -e " ${YELLOW}⊘ Level $level SKIPPED${RESET}" 600 else 601 LEVELS_FAILED=$((LEVELS_FAILED + 1)) 602 LEVEL_RESULT[$level]="fail" 603 echo -e " ${RED}✗ Level $level FAILED${RESET}" 604 605 # If an early level fails, later levels will almost certainly fail too 606 if [ "$level" -le 2 ] && [ -z "$SELECTED_LEVEL" ]; then 607 warn "Level $level failed — skipping remaining levels (they depend on this)." 608 for remaining in "${RUN_LEVELS[@]}"; do 609 if [ "$remaining" -gt "$level" ] && [ -z "${LEVEL_RESULT[$remaining]+x}" ]; then 610 LEVELS_SKIPPED=$((LEVELS_SKIPPED + 1)) 611 LEVEL_RESULT[$remaining]="skip" 612 fi 613 done 614 break 615 fi 616 fi 617 618 echo "" 619done 620 621# ── Garbage Collection ────────────────────────────────────────────────────── 622 623if [ "$KEEP_BUILDS" -eq 0 ] && [ "$LEVELS_PASSED" -gt 0 ]; then 624 log "Cleaning up test derivations..." 625 dsh_nix "nix-collect-garbage 2>/dev/null" >/dev/null 2>&1 || true 626else 627 if [ "$KEEP_BUILDS" -eq 1 ]; then 628 log "Keeping built derivations (--keep)." 629 fi 630fi 631 632# ── Summary ───────────────────────────────────────────────────────────────── 633 634TOTAL=$((LEVELS_PASSED + LEVELS_FAILED + LEVELS_SKIPPED)) 635 636echo "" 637log "${BOLD}═══════════════════════════════════════════════════════════${RESET}" 638log "${BOLD} Build Test Summary${RESET}" 639log "${BOLD}═══════════════════════════════════════════════════════════${RESET}" 640echo "" 641 642printf " %-5s %-35s %s\n" "Level" "Name" "Result" 643printf " %-5s %-35s %s\n" "─────" "───────────────────────────────────" "──────" 644 645for level in "${ALL_LEVELS[@]}"; do 646 result="${LEVEL_RESULT[$level]:-skip}" 647 case "$result" in 648 pass) printf " %-5s %-35s ${GREEN}✓ PASS${RESET}\n" "$level" "${LEVEL_NAMES[$level]}" ;; 649 fail) printf " %-5s %-35s ${RED}✗ FAIL${RESET}\n" "$level" "${LEVEL_NAMES[$level]}" ;; 650 skip) printf " %-5s %-35s ${YELLOW}⊘ SKIP${RESET}\n" "$level" "${LEVEL_NAMES[$level]}" ;; 651 esac 652done 653 654echo "" 655printf " Total: %d levels\n" "$TOTAL" 656printf " Passed: ${GREEN}%d${RESET}\n" "$LEVELS_PASSED" 657printf " Failed: ${RED}%d${RESET}\n" "$LEVELS_FAILED" 658printf " Skipped: ${YELLOW}%d${RESET}\n" "$LEVELS_SKIPPED" 659echo "" 660 661if [ "$LEVELS_FAILED" -gt 0 ]; then 662 err "Some build levels failed." 663 echo "" >&2 664 echo "Next steps:" >&2 665 echo " • Run a single level: $0 --level N --debug" >&2 666 echo " • Manual build: darling shell bash -lc 'nix-build -vvvv --expr \"...\"'" >&2 667 echo " • Manual sandbox test: darling shell /usr/bin/sandbox-exec -f /dev/null /bin/bash -c 'echo ok'" >&2 668 echo " • Check syscalls: ./scripts/triage-syscalls.sh" >&2 669 echo " • Host-side trace: strace -f -p \$(pidof darlingserver) 2>&1 | head -500" >&2 670 echo " • Darling xtrace: DARLING_XTRACE=1 darling shell bash -lc 'nix-build --expr ...'" >&2 671 echo "" >&2 672 exit 1 673elif [ "$LEVELS_PASSED" -eq 0 ]; then 674 warn "No levels were attempted — check that Nix is installed." 675 exit 2 676else 677 log "${GREEN}All build levels passed!${RESET}" 678 if [ "$LEVELS_SKIPPED" -gt 0 ]; then 679 log "${DIM}($LEVELS_SKIPPED levels skipped — re-run with --level N to target them)${RESET}" 680 fi 681 log "" 682 log "Phase 4.1 is complete! Next steps:" 683 log " • Phase 4.2: Test bash in build sandboxes (more complex scripts)" 684 log " • Phase 4.5: Build a C program with Darwin stdenv" 685 log " • See: plan/06-phase4-building.md" 686 exit 0 687fi