Merge pull request #7721 from yorickvP/post-build-hook

Also pass unwanted outputs to post-build-hook
This commit is contained in:
Théophane Hufschmitt 2023-05-10 14:30:42 +02:00 committed by GitHub
commit 85ff212051
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 53 additions and 30 deletions

View file

@ -1020,43 +1020,33 @@ void DerivationGoal::resolvedFinished()
StorePathSet outputPaths; StorePathSet outputPaths;
// `wantedOutputs` might merely indicate “all the outputs” for (auto & outputName : resolvedDrv.outputNames()) {
auto realWantedOutputs = std::visit(overloaded { auto initialOutput = get(initialOutputs, outputName);
[&](const OutputsSpec::All &) { auto resolvedHash = get(resolvedHashes, outputName);
return resolvedDrv.outputNames();
},
[&](const OutputsSpec::Names & names) {
return static_cast<std::set<std::string>>(names);
},
}, wantedOutputs.raw());
for (auto & wantedOutput : realWantedOutputs) {
auto initialOutput = get(initialOutputs, wantedOutput);
auto resolvedHash = get(resolvedHashes, wantedOutput);
if ((!initialOutput) || (!resolvedHash)) if ((!initialOutput) || (!resolvedHash))
throw Error( throw Error(
"derivation '%s' doesn't have expected output '%s' (derivation-goal.cc/resolvedFinished,resolve)", "derivation '%s' doesn't have expected output '%s' (derivation-goal.cc/resolvedFinished,resolve)",
worker.store.printStorePath(drvPath), wantedOutput); worker.store.printStorePath(drvPath), outputName);
auto realisation = [&]{ auto realisation = [&]{
auto take1 = get(resolvedResult.builtOutputs, wantedOutput); auto take1 = get(resolvedResult.builtOutputs, outputName);
if (take1) return *take1; if (take1) return *take1;
/* The above `get` should work. But sateful tracking of /* The above `get` should work. But sateful tracking of
outputs in resolvedResult, this can get out of sync with the outputs in resolvedResult, this can get out of sync with the
store, which is our actual source of truth. For now we just store, which is our actual source of truth. For now we just
check the store directly if it fails. */ check the store directly if it fails. */
auto take2 = worker.evalStore.queryRealisation(DrvOutput { *resolvedHash, wantedOutput }); auto take2 = worker.evalStore.queryRealisation(DrvOutput { *resolvedHash, outputName });
if (take2) return *take2; if (take2) return *take2;
throw Error( throw Error(
"derivation '%s' doesn't have expected output '%s' (derivation-goal.cc/resolvedFinished,realisation)", "derivation '%s' doesn't have expected output '%s' (derivation-goal.cc/resolvedFinished,realisation)",
worker.store.printStorePath(resolvedDrvGoal->drvPath), wantedOutput); worker.store.printStorePath(resolvedDrvGoal->drvPath), outputName);
}(); }();
if (drv->type().isPure()) { if (drv->type().isPure()) {
auto newRealisation = realisation; auto newRealisation = realisation;
newRealisation.id = DrvOutput { initialOutput->outputHash, wantedOutput }; newRealisation.id = DrvOutput { initialOutput->outputHash, outputName };
newRealisation.signatures.clear(); newRealisation.signatures.clear();
if (!drv->type().isFixed()) if (!drv->type().isFixed())
newRealisation.dependentRealisations = drvOutputReferences(worker.store, *drv, realisation.outPath); newRealisation.dependentRealisations = drvOutputReferences(worker.store, *drv, realisation.outPath);
@ -1064,7 +1054,7 @@ void DerivationGoal::resolvedFinished()
worker.store.registerDrvOutput(newRealisation); worker.store.registerDrvOutput(newRealisation);
} }
outputPaths.insert(realisation.outPath); outputPaths.insert(realisation.outPath);
builtOutputs.emplace(wantedOutput, realisation); builtOutputs.emplace(outputName, realisation);
} }
runPostBuildHook( runPostBuildHook(
@ -1406,7 +1396,7 @@ std::pair<bool, SingleDrvOutputs> DerivationGoal::checkPathValidity()
); );
} }
} }
if (info.wanted && info.known && info.known->isValid()) if (info.known && info.known->isValid())
validOutputs.emplace(i.first, Realisation { drvOutput, info.known->path }); validOutputs.emplace(i.first, Realisation { drvOutput, info.known->path });
} }
@ -1457,8 +1447,9 @@ void DerivationGoal::done(
mcRunningBuilds.reset(); mcRunningBuilds.reset();
if (buildResult.success()) { if (buildResult.success()) {
assert(!builtOutputs.empty()); auto wantedBuiltOutputs = filterDrvOutputs(wantedOutputs, std::move(builtOutputs));
buildResult.builtOutputs = std::move(builtOutputs); assert(!wantedBuiltOutputs.empty());
buildResult.builtOutputs = std::move(wantedBuiltOutputs);
if (status == BuildResult::Built) if (status == BuildResult::Built)
worker.doneBuilds++; worker.doneBuilds++;
} else { } else {

View file

@ -306,15 +306,13 @@ struct DerivationGoal : public Goal
* Update 'initialOutputs' to determine the current status of the * Update 'initialOutputs' to determine the current status of the
* outputs of the derivation. Also returns a Boolean denoting * outputs of the derivation. Also returns a Boolean denoting
* whether all outputs are valid and non-corrupt, and a * whether all outputs are valid and non-corrupt, and a
* 'SingleDrvOutputs' structure containing the valid and wanted * 'SingleDrvOutputs' structure containing the valid outputs.
* outputs.
*/ */
std::pair<bool, SingleDrvOutputs> checkPathValidity(); std::pair<bool, SingleDrvOutputs> checkPathValidity();
/** /**
* Aborts if any output is not valid or corrupt, and otherwise * Aborts if any output is not valid or corrupt, and otherwise
* returns a 'SingleDrvOutputs' structure containing the wanted * returns a 'SingleDrvOutputs' structure containing all outputs.
* outputs.
*/ */
SingleDrvOutputs assertPathValidity(); SingleDrvOutputs assertPathValidity();

View file

@ -2701,8 +2701,7 @@ SingleDrvOutputs LocalDerivationGoal::registerOutputs()
signRealisation(thisRealisation); signRealisation(thisRealisation);
worker.store.registerDrvOutput(thisRealisation); worker.store.registerDrvOutput(thisRealisation);
} }
if (wantedOutputs.contains(outputName)) builtOutputs.emplace(outputName, thisRealisation);
builtOutputs.emplace(outputName, thisRealisation);
} }
return builtOutputs; return builtOutputs;

View file

@ -136,6 +136,19 @@ size_t Realisation::checkSignatures(const PublicKeys & publicKeys) const
return good; return good;
} }
SingleDrvOutputs filterDrvOutputs(const OutputsSpec& wanted, SingleDrvOutputs&& outputs)
{
SingleDrvOutputs ret = std::move(outputs);
for (auto it = ret.begin(); it != ret.end(); ) {
if (!wanted.contains(it->first))
it = ret.erase(it);
else
++it;
}
return ret;
}
StorePath RealisedPath::path() const { StorePath RealisedPath::path() const {
return std::visit([](auto && arg) { return arg.getPath(); }, raw); return std::visit([](auto && arg) { return arg.getPath(); }, raw);
} }

View file

@ -12,6 +12,7 @@
namespace nix { namespace nix {
class Store; class Store;
struct OutputsSpec;
/** /**
* A general `Realisation` key. * A general `Realisation` key.
@ -93,6 +94,14 @@ typedef std::map<std::string, Realisation> SingleDrvOutputs;
*/ */
typedef std::map<DrvOutput, Realisation> DrvOutputs; typedef std::map<DrvOutput, Realisation> DrvOutputs;
/**
* Filter a SingleDrvOutputs to include only specific output names
*
* Moves the `outputs` input.
*/
SingleDrvOutputs filterDrvOutputs(const OutputsSpec&, SingleDrvOutputs&&);
struct OpaquePath { struct OpaquePath {
StorePath path; StorePath path;

View file

@ -17,6 +17,10 @@ fi
# Build the dependencies and push them to the remote store. # Build the dependencies and push them to the remote store.
nix-build -o $TEST_ROOT/result dependencies.nix --post-build-hook "$pushToStore" nix-build -o $TEST_ROOT/result dependencies.nix --post-build-hook "$pushToStore"
# See if all outputs are passed to the post-build hook by only specifying one
# We're not able to test CA tests this way
export BUILD_HOOK_ONLY_OUT_PATHS=$([ ! $NIX_TESTS_CA_BY_DEFAULT ])
nix-build -o $TEST_ROOT/result-mult multiple-outputs.nix -A a.first --post-build-hook "$pushToStore"
clearStore clearStore
@ -24,3 +28,4 @@ clearStore
# closure of what we've just built. # closure of what we've just built.
nix copy --from "$REMOTE_STORE" --no-require-sigs -f dependencies.nix nix copy --from "$REMOTE_STORE" --no-require-sigs -f dependencies.nix
nix copy --from "$REMOTE_STORE" --no-require-sigs -f dependencies.nix input1_drv nix copy --from "$REMOTE_STORE" --no-require-sigs -f dependencies.nix input1_drv
nix copy --from "$REMOTE_STORE" --no-require-sigs -f multiple-outputs.nix a^second

View file

@ -7,4 +7,8 @@ set -e
[ -n "$DRV_PATH" ] [ -n "$DRV_PATH" ]
echo Pushing "$OUT_PATHS" to "$REMOTE_STORE" echo Pushing "$OUT_PATHS" to "$REMOTE_STORE"
printf "%s" "$DRV_PATH" | xargs nix copy --to "$REMOTE_STORE" --no-require-sigs if [ -n "$BUILD_HOOK_ONLY_OUT_PATHS" ]; then
printf "%s" "$OUT_PATHS" | xargs nix copy --to "$REMOTE_STORE" --no-require-sigs
else
printf "%s" "$DRV_PATH" | xargs nix copy --to "$REMOTE_STORE" --no-require-sigs
fi

View file

@ -7,4 +7,8 @@ set -e
[ -n "$DRV_PATH" ] [ -n "$DRV_PATH" ]
echo Pushing "$OUT_PATHS" to "$REMOTE_STORE" echo Pushing "$OUT_PATHS" to "$REMOTE_STORE"
printf "%s" "$DRV_PATH"^'*' | xargs nix copy --to "$REMOTE_STORE" --no-require-sigs if [ -n "$BUILD_HOOK_ONLY_OUT_PATHS" ]; then
printf "%s" "$OUT_PATHS" | xargs nix copy --to "$REMOTE_STORE" --no-require-sigs
else
printf "%s" "$DRV_PATH"^'*' | xargs nix copy --to "$REMOTE_STORE" --no-require-sigs
fi