Doing what you do is heresy according to Restrict fixed-output derivations · Issue #2270 · NixOS/nix · GitHub
Let the heresy begin! But first TLDR: you have to replace inputString = ldcBuild.outPath; with outPath to test derivation. Fixing infinite recursion shouldn’t be hard.
let
pkgs = import <nixpkgs> {};
lib = pkgs.lib;
in rec {
Let’s also make some abstractions out of this. First, we’ll reuse @Profpatsch test runner, but heavily modified one:
drvSeqL = drvDeps: drvOut: let
drvOutOutputs = drvOut.outputs or ["out"];
in
lib.overrideDerivation drvOut (_: {
inherit drvDeps;
buildCommand =
(lib.concatMapStrings (output: ''
target=${lib.escapeShellArg drvOut.${output}}
# if the target is already a symlink, follow it until it’s not;
# this is done to prevent too many dereferences
target=$(readlink -e "$target")
# link to the output
ln -s "$target" "${"$"}${output}"
'') drvOutOutputs);
});
drvSeq = drvDep: drvOut: drvSeqL [drvDep] drvOut;
Then let’s define our compiler:
compiler = pkgs.runCommand "" {
pname = "compiler";
version = "0.1";
meta.description = "A compiler!";
outputs = [ "out" "doc" ];
} ''
echo BUILDING COMPILER
mkdir -p $out/bin
echo -n '#!/bin/sh
echo hello $1, really compiled with compiler v'"$version"'
' > $out/bin/compiler
chmod +x $out/bin/compiler
# multiple outputs!
echo run like "compiler world" to produce "hello world" > $doc
'';
Pretty nice compiler, read help cat $(nix-build -A compiler.doc) on how to use this compiler.
We want some test also, right?
compilerTest = pkgs.runCommand "${compiler.name}-tests" {
buildInputs = with pkgs; [ curl compiler ];
} ''
echo RUNNING TESTS 1
curl --insecure -LO http://nixos.org/nix/install
set -e
compiler world | grep -q "hello world"
echo -n $inputString > $out
'';
Very nice test, but it doesn’t work:
$ nix-build -A compilerTest
these derivations will be built:
/nix/store/37s0s3amkkm4697mz62mf7pi1zqg9m0g-compiler-0.1-tests.drv
building '/nix/store/37s0s3amkkm4697mz62mf7pi1zqg9m0g-compiler-0.1-tests.drv'...
RUNNING TESTS 1
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0curl: (6) Could not resolve host: nixos.org
builder for '/nix/store/37s0s3amkkm4697mz62mf7pi1zqg9m0g-compiler-0.1-tests.drv' failed with exit code 6
error: build of '/nix/store/37s0s3amkkm4697mz62mf7pi1zqg9m0g-compiler-0.1-tests.drv' failed
Uh oh. This is because you can’t run test without getting package out. We will fake our packages with
test = testedPackage compilerTest (
pkgs.runCommand "compiler-tests" { } "touch $out");
$ nix-build -A test
these derivations will be built:
/nix/store/5fpcvplpfd4frcx7dhhp4f1y6a7mf37p-compiler-0.1-tests.drv
/nix/store/avby8nf3224mvd8lspicnmcnv8gr8amn-compiler-tests.drv
building '/nix/store/5fpcvplpfd4frcx7dhhp4f1y6a7mf37p-compiler-0.1-tests.drv'...
RUNNING TESTS 1
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 237 100 237 0 0 1234 0 --:--:-- --:--:-- --:--:-- 1234
100 2476 100 2476 0 0 4559 0 --:--:-- --:--:-- --:--:-- 4559
building '/nix/store/avby8nf3224mvd8lspicnmcnv8gr8amn-compiler-tests.drv'...
/nix/store/qyskkrclp5ix4wx6f00dqkzfg9lsp55s-compiler-tests
Look ma! It curls internet in sandbox mode! But getting dummy package isn’t interesting. Let’s get real package:
compilerOut = testedPackage compilerTest compiler;
$ nix-build -A compilerOut
/nix/store/2flxjqal2fjj5y9nb5s14w3srk63xpjx-compiler-0.1
Let’s check, if test is rerun when compiler version is changed (I’m changing it to 0.6):
$ nix-build -A compilerOut
these derivations will be built:
/nix/store/82ya3qa1120by2aqm8mz3zwm5q8fazkn-compiler-0.6.drv
/nix/store/frjxiczb32q57wblb6m09zwqhpmnaag3-compiler-0.6-tests.drv
/nix/store/45nndb36xip8jb51j3phljkjksgj0axj-compiler-0.6.drv
building '/nix/store/82ya3qa1120by2aqm8mz3zwm5q8fazkn-compiler-0.6.drv'...
BUILDING COMPILER
building '/nix/store/frjxiczb32q57wblb6m09zwqhpmnaag3-compiler-0.6-tests.drv'...
RUNNING TESTS 1
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 237 100 237 0 0 1346 0 --:--:-- --:--:-- --:--:-- 1338
100 2476 100 2476 0 0 4602 0 --:--:-- --:--:-- --:--:-- 4602
building '/nix/store/45nndb36xip8jb51j3phljkjksgj0axj-compiler-0.6.drv'...
/nix/store/qmj5y5lw79q9l2m4ysycwr1sx0b9gj7s-compiler-0.6
$ nix-build -A compilerOut
/nix/store/qmj5y5lw79q9l2m4ysycwr1sx0b9gj7s-compiler-0.6
Good, so it reruns tests when compiler was changed. But now let’s introduce wrong test (compiler world | grep -q "bla bla"):
$ nix-build -A compilerOut
these derivations will be built:
/nix/store/3gx6k899zl8w5fgq2f0vaqifyzawrl46-compiler-0.6-tests.drv
/nix/store/5zdbvjp2ws5pdvrqgbs3l5kksmda2ppg-compiler-0.6.drv
building '/nix/store/3gx6k899zl8w5fgq2f0vaqifyzawrl46-compiler-0.6-tests.drv'...
RUNNING TESTS 1
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 237 100 237 0 0 1227 0 --:--:-- --:--:-- --:--:-- 1227
100 2476 100 2476 0 0 4298 0 --:--:-- --:--:-- --:--:-- 805k
builder for '/nix/store/3gx6k899zl8w5fgq2f0vaqifyzawrl46-compiler-0.6-tests.drv' failed with exit code 1
cannot build derivation '/nix/store/5zdbvjp2ws5pdvrqgbs3l5kksmda2ppg-compiler-0.6.drv': 1 dependencies couldn't be built
error: build of '/nix/store/5zdbvjp2ws5pdvrqgbs3l5kksmda2ppg-compiler-0.6.drv' failed
Very good. I mean, it’s bad, tests shouldn’t fail, but it’s good it reruns tests, but doesn’t rebuild compiler if compiler isn’t changed. Let’s fix test and rerun:
$ nix-build -A compilerOut
these derivations will be built:
/nix/store/f3pairqlnrlyqhd4j55n3xbyap5ki9b8-compiler-0.6-tests.drv
/nix/store/8n4zz64fp2lqsycv20ni2lj9vh4s6k4j-compiler-0.6.drv
building '/nix/store/f3pairqlnrlyqhd4j55n3xbyap5ki9b8-compiler-0.6-tests.drv'...
RUNNING TESTS 1
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 237 100 237 0 0 1240 0 --:--:-- --:--:-- --:--:-- 1240
100 2476 100 2476 0 0 3844 0 --:--:-- --:--:-- --:--:-- 3844
building '/nix/store/8n4zz64fp2lqsycv20ni2lj9vh4s6k4j-compiler-0.6.drv'...
/nix/store/bx0z3yll0ajhincwgrkpyg96yk6hg8d3-compiler-0.6
$ cat $(nix-build -A compilerOut.doc)
run like compiler world to produce hello world
@ThomasMader is that what you wanted? If yes, then here is the missing part of the puzzle:
testedPackage = test: package:
let
_tested = derivation (test.drvAttrs // rec {
inputString = builtins.unsafeDiscardStringContext test.outPath;
outputHashAlgo = "sha256";
outputHash = builtins.hashString "sha256" inputString;
});
in drvSeq _tested package;