From 18935e8b9f152f18705e738d4b8cc6fce97c8b02 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 11 Mar 2022 13:23:23 +0100 Subject: [PATCH] Support fixed-output derivations depending on impure derivations --- src/libstore/build/derivation-goal.cc | 9 +++++---- src/libstore/misc.cc | 7 ++++--- tests/impure-derivations.nix | 22 ++++++++++++++++++++++ tests/impure-derivations.sh | 19 +++++++++++++++++-- 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc index 2f3490829..542a6f6ea 100644 --- a/src/libstore/build/derivation-goal.cc +++ b/src/libstore/build/derivation-goal.cc @@ -342,9 +342,9 @@ void DerivationGoal::gaveUpOnSubstitution() inputDrvOutputs.clear(); if (useDerivation) for (auto & i : dynamic_cast(drv.get())->inputDrvs) { - /* Ensure that pure derivations don't depend on impure - derivations. */ - if (drv->type().isPure()) { + /* Ensure that pure, non-fixed-output derivations don't + depend on impure derivations. */ + if (drv->type().isPure() && !drv->type().isFixed()) { auto inputDrv = worker.evalStore.readDerivation(i.first); if (!inputDrv.type().isPure()) throw Error("pure derivation '%s' depends on impure derivation '%s'", @@ -993,7 +993,8 @@ void DerivationGoal::resolvedFinished() auto newRealisation = realisation; newRealisation.id = DrvOutput { initialOutputs.at(wantedOutput).outputHash, wantedOutput }; newRealisation.signatures.clear(); - newRealisation.dependentRealisations = drvOutputReferences(worker.store, *drv, realisation.outPath); + if (!drv->type().isFixed()) + newRealisation.dependentRealisations = drvOutputReferences(worker.store, *drv, realisation.outPath); signRealisation(newRealisation); worker.store.registerDrvOutput(newRealisation); } diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc index 1f0bae7fe..2bbd7aa70 100644 --- a/src/libstore/misc.cc +++ b/src/libstore/misc.cc @@ -277,15 +277,15 @@ std::map drvOutputReferences( { std::set inputRealisations; - for (const auto& [inputDrv, outputNames] : drv.inputDrvs) { + for (const auto & [inputDrv, outputNames] : drv.inputDrvs) { auto outputHashes = staticOutputHashes(store, store.readDerivation(inputDrv)); - for (const auto& outputName : outputNames) { + for (const auto & outputName : outputNames) { auto thisRealisation = store.queryRealisation( DrvOutput{outputHashes.at(outputName), outputName}); if (!thisRealisation) throw Error( - "output '%s' of derivation '%s' isn’t built", outputName, + "output '%s' of derivation '%s' isn't built", outputName, store.printStorePath(inputDrv)); inputRealisations.insert(*thisRealisation); } @@ -295,4 +295,5 @@ std::map drvOutputReferences( return drvOutputReferences(Realisation::closure(store, inputRealisations), info->references); } + } diff --git a/tests/impure-derivations.nix b/tests/impure-derivations.nix index ba7d53146..2fed56fe7 100644 --- a/tests/impure-derivations.nix +++ b/tests/impure-derivations.nix @@ -7,6 +7,7 @@ rec { outputs = [ "out" "stuff" ]; buildCommand = '' + echo impure x=$(< $TEST_ROOT/counter) mkdir $out $stuff echo $x > $out/n @@ -23,6 +24,7 @@ rec { name = "impure-on-impure"; buildCommand = '' + echo impure-on-impure x=$(< ${impure}/n) mkdir $out printf X$x > $out/n @@ -43,4 +45,24 @@ rec { ''; }; + contentAddressed = mkDerivation { + name = "content-addressed"; + buildCommand = + '' + echo content-addressed + x=$(< ${impureOnImpure}/n) + printf ''${x:0:1} > $out + ''; + outputHashAlgo = "sha256"; + outputHashMode = "recursive"; + outputHash = "sha256-eBYxcgkuWuiqs4cKNgKwkb3vY/HR0vVsJnqe8itJGcQ="; + }; + + inputAddressedAfterCA = mkDerivation { + name = "input-addressed-after-ca"; + buildCommand = + '' + cat ${contentAddressed} > $out + ''; + }; } diff --git a/tests/impure-derivations.sh b/tests/impure-derivations.sh index cb1eaf84a..85e3e09cc 100644 --- a/tests/impure-derivations.sh +++ b/tests/impure-derivations.sh @@ -21,10 +21,10 @@ path2=$(nix build -L --no-link --json --file ./impure-derivations.nix impure | j [[ $(< $path2/n) = 1 ]] # Test impure derivations that depend on impure derivations. -path3=$(nix build -L --no-link --json --file ./impure-derivations.nix impureOnImpure -vvvvv | jq -r .[].outputs.out) +path3=$(nix build -L --no-link --json --file ./impure-derivations.nix impureOnImpure | jq -r .[].outputs.out) [[ $(< $path3/n) = X2 ]] -path4=$(nix build -L --no-link --json --file ./impure-derivations.nix impureOnImpure -vvvvv | jq -r .[].outputs.out) +path4=$(nix build -L --no-link --json --file ./impure-derivations.nix impureOnImpure | jq -r .[].outputs.out) [[ $(< $path4/n) = X3 ]] # Test that (self-)references work. @@ -37,3 +37,18 @@ nix build -L --no-link --json --file ./impure-derivations.nix inputAddressed 2>& drvPath=$(nix eval --json --file ./impure-derivations.nix impure.drvPath | jq -r .) [[ $(nix show-derivation $drvPath | jq ".[\"$drvPath\"].outputs.out.impure") = true ]] [[ $(nix show-derivation $drvPath | jq ".[\"$drvPath\"].outputs.stuff.impure") = true ]] + +# Fixed-output derivations *can* depend on impure derivations. +path5=$(nix build -L --no-link --json --file ./impure-derivations.nix contentAddressed | jq -r .[].outputs.out) +[[ $(< $path5) = X ]] +[[ $(< $TEST_ROOT/counter) = 5 ]] + +# And they should not be rebuilt. +path5=$(nix build -L --no-link --json --file ./impure-derivations.nix contentAddressed | jq -r .[].outputs.out) +[[ $(< $path5) = X ]] +[[ $(< $TEST_ROOT/counter) = 5 ]] + +# Input-addressed derivations can depend on fixed-output derivations that depend on impure derivations. +path6=$(nix build -L --no-link --json --file ./impure-derivations.nix inputAddressedAfterCA | jq -r .[].outputs.out) +[[ $(< $path6) = X ]] +[[ $(< $TEST_ROOT/counter) = 5 ]]