Open lukego opened 1 year ago
Maybe I have an adequate kludge: Overriding the builder scripts to produce stdout/stderr logs instead of the normal outputs.
This addresses the problem more directly because the information that I want to capture is all included in the build outputs. I don't really need to capture the nix build
output because the information will be available in the result
file in plain text.
I have a little proof of concept (below) and it seems to reliably produce the output of the inner nix build like so:
[luke@snowy:~/git/lispnix]$ nix --experimental-features "nix-command recursive-nix" build -L -f rec.nix
[luke@snowy:~/git/lispnix]$ cat result
START: building /nix/store/nar8fpywn5lfbsrp8sh3g7agi8knpkqv-outer
warning: you don't have Internet access; disabling some network-dependent features
this derivation will be built:
/nix/store/fw35kdc1dn99v9ssa81mp15pgps614nz-inner.drv
START: building /nix/store/wxghg65467rfwhf21vy9764f2azq73ma-inner
building inner..
FINISH: exit status 0 for /nix/store/wxghg65467rfwhf21vy9764f2azq73ma-inner
FINISH: exit status 0 for /nix/store/nar8fpywn5lfbsrp8sh3g7agi8knpkqv-outer
This string building inner
is the information that has been alluding me.
This also seems to handle error cases plausibly. If the inner build fails then the log is produced with useful information. Likewise if the inner derivation fails to evaluate.
Error example for the case of an inner derivation that fails to evaluate due to syntax error:
[luke@snowy:~/git/lispnix]$ nix --experimental-features "nix-command recursive-nix" build -L -f rec.nix
[luke@snowy:~/git/lispnix]$ cat result
START: building /nix/store/56x4kwxfwciafmgahlghsc5rqnlqj20d-outer
warning: you don't have Internet access; disabling some network-dependent features
error: syntax error, unexpected ';'
at /nix/store/j29wqqy775lczrrds4ir8zppw1jrr2qr-inner.nix:3:78:
2| runCommand "inner"
3| { builder = /nix/store/h2vh7i7yqiflk36frsbw7cgs890hvs56-logging-builder.sh;;;;; }
| ^
4| "echo building inner.."
FINISH: exit status 1 for /nix/store/56x4kwxfwciafmgahlghsc5rqnlqj20d-outer
Good enough?
Here is the contents of rec.nix
:
let
# master branch 2022-11-08
nixpkgs = fetchTarball {
url = "https://github.com/nixos/nixpkgs/archive/f6072a8d7b1520194453e27be1fd59a28c751a7f.tar.gz";
sha256 = "sha256:1zr2jm5gjbsyca9bcq7f3h354qf8d5bd6b0h4qjr0i03dvrvl10s";
};
in
with import nixpkgs {};
# Custom builder for mkDerivation to produce build logs instead of normal output.
#
# Output will be a text file containing the output on stdout/stderr during build.
# One-liner header and trailer metadata is also included.
let logging-builder = writeScript "logging-builder.sh"
''
# Run the real builder as mkDerivation normally would
echo "START: building $out" | ${coreutils}/bin/tee .logging-builder.log
set +e
set -o pipefail
${stdenv.shell} -c 'source $stdenv/setup; genericBuild' 2>&1 \
| ${coreutils}/bin/tee -a .logging-builder.log
status=$?
echo "FINISH: exit status $status for $out" >> .logging-builder.log
[ -e "$out" ] && ${coreutils}/bin/rm -rf $out
${coreutils}/bin/cp .logging-builder.log $out
'';
in
runCommand "outer"
{
requiredSystemFeatures = [ "recursive-nix" ];
nativeBuildInputs = [ nix ];
expr = writeText "inner.nix"
''
with import ${nixpkgs} {};
runCommand "inner"
{ builder = ${logging-builder}; }
"echo building inner.."
'';
builder = logging-builder;
}
''
# Run nix build and log output
nix --experimental-features "recursive-nix nix-command" \
build -L -f $expr
status=$?
[ -e result ] && cat result
''
I would like to be able to run a recursive Nix build and to capture all the output logged to stdout/stderr. However I am not getting all of the output that I expect (see below.)
Context
My use case is "try-catch." The inner nix build attempts to build a derivation - which may fail either directly or via dependency - and the outer nix build produces the logs from this build attempt as its output.
(My higher-level use case is to use Nix to build a report about which derivations do and don't build successfully. I think it would be much neater to do this with recursive Nix than e.g. as an extension of Hydra.)
Example
Here is a recursive Nix expression:
that when built produces this output in the shell:
and produces this log as its result:
The problem is that this log is incomplete: what I need to see in the log is the output from the inner build,
building inner..
Is there a way that I can change this code so that the log-output of the inner build is captured as the build-output of the outer build?
(Aside: Is there also a neat way to avoid embedding the inner expression in a string while still ensuring that it's not built in the outer process? I'd imagined taking a
drvPath
and passing that tonix build
but that didn't seem to be accepted.)