#!/usr/bin/env bash # # Prints build logs for failed derivations in quiet build mode (-Q). # See https://github.com/NixOS/nix/issues/443 # # Usage: # # nix-build ... -Q ... 2>&1 | whatsupnix [user@target[:port]] # # Exit Codes: # # 0 No failed derivations could be found. This either means there where # no build errors, or stdin wasn't nix-build output. # # 1 Usage error; arguments couldn't be parsed. # # 2 Nix error; input looks like Nix failed. # # 3 Build error; at least one failed derivation could be found. # tmpdir=$(mktemp -d --tmpdir whatsupnix.XXXXXXXX) failed_drvs=$tmpdir/failed_drvs; touch "$failed_drvs" nix_errors=$tmpdir/nix_errors; touch "$nix_errors" cleanup() { rm "$failed_drvs" rm "$nix_errors" rmdir "$tmpdir" } trap cleanup EXIT exec >&2 gawk \ -v failed_drvs="$failed_drvs" \ -v nix_errors="$nix_errors" \ ' /^(\033\[31;1m)?error:/ { print $0 >> nix_errors } match($0, /^builder for ‘(\/nix\/store\/[^’]+\.drv)’ failed/, m) { print m[1] >> failed_drvs } { print $0; fflush("/dev/stdout") } ' case $# in 0) print_log() { NIX_PAGER= nix-store -l "$1" } ;; 1) remote_user=${1%%@*} if test "$remote_user" = "$1"; then remote_user=root else set -- "${1#$remote_user@}" fi remote_port=${1##*:} if test "$remote_port" = "$1"; then remote_port=22 else set -- "${1%:$remote_port}" fi remote_host=$1 print_log() { ssh "$remote_user@$remote_host" -p "$remote_port" \ env NIX_PAGER= nix-store -l "$1" } ;; *) echo "usage: whatsupnix [[USER@]HOST[:PORT]]" >&2 exit 1 esac while read -r drv; do title="** FAILED $drv LOG **" frame=${title//?/*} echo "$frame" echo "$title" echo "$frame" echo print_log "$drv" echo done < "$failed_drvs" if test -s "$nix_errors"; then exit 2 elif test -s "$failed_drvs"; then exit 3 else exit 0 fi