1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-09 03:56:01 +01:00

Fix ca/eval-store.sh test

The refactor in the last commit fixed the bug it was supposed to fix,
but introduced a new bug in that sometimes we tried to write a resolved
derivation to a store before all its `inputSrcs` were in that store.

The solution is to defer writing the derivation until inside
`DerivationBuildingGoal`, just before we do an actual build. At this
point, we are sure that all inputs in are the store.

This does have the side effect of meaning we don't write down the
resolved derivation in the substituting case, only the building case,
but I think that is actually fine. The store that actually does the
building should make a record of what it built by storing the resolved
derivation. Other stores that just substitute from that store don't
necessary want that derivation however. They can trust the substituter
to keep the record around, or baring that, they can attempt to re
resolve everything, if they need to be audited.

(cherry picked from commit c97b050a6c)
This commit is contained in:
John Ericson 2025-09-26 01:40:00 -04:00
parent 06bb1c2f93
commit ad893acf46
7 changed files with 53 additions and 25 deletions

View file

@ -26,8 +26,8 @@
namespace nix { namespace nix {
DerivationBuildingGoal::DerivationBuildingGoal( DerivationBuildingGoal::DerivationBuildingGoal(
const StorePath & drvPath, const Derivation & drv, Worker & worker, BuildMode buildMode) const StorePath & drvPath, const Derivation & drv, Worker & worker, BuildMode buildMode, bool storeDerivation)
: Goal(worker, gaveUpOnSubstitution()) : Goal(worker, gaveUpOnSubstitution(storeDerivation))
, drvPath(drvPath) , drvPath(drvPath)
, drv{std::make_unique<Derivation>(drv)} , drv{std::make_unique<Derivation>(drv)}
, buildMode(buildMode) , buildMode(buildMode)
@ -107,7 +107,7 @@ static void runPostBuildHook(
/* At least one of the output paths could not be /* At least one of the output paths could not be
produced using a substitute. So we have to build instead. */ produced using a substitute. So we have to build instead. */
Goal::Co DerivationBuildingGoal::gaveUpOnSubstitution() Goal::Co DerivationBuildingGoal::gaveUpOnSubstitution(bool storeDerivation)
{ {
Goals waitees; Goals waitees;
@ -155,6 +155,13 @@ Goal::Co DerivationBuildingGoal::gaveUpOnSubstitution()
/* Determine the full set of input paths. */ /* Determine the full set of input paths. */
if (storeDerivation) {
assert(drv->inputDrvs.map.empty());
/* Store the resolved derivation, as part of the record of
what we're actually building */
writeDerivation(worker.store, *drv);
}
{ {
/* If we get this far, we know no dynamic drvs inputs */ /* If we get this far, we know no dynamic drvs inputs */

View file

@ -30,8 +30,9 @@ DerivationGoal::DerivationGoal(
const Derivation & drv, const Derivation & drv,
const OutputName & wantedOutput, const OutputName & wantedOutput,
Worker & worker, Worker & worker,
BuildMode buildMode) BuildMode buildMode,
: Goal(worker, haveDerivation()) bool storeDerivation)
: Goal(worker, haveDerivation(storeDerivation))
, drvPath(drvPath) , drvPath(drvPath)
, wantedOutput(wantedOutput) , wantedOutput(wantedOutput)
, drv{std::make_unique<Derivation>(drv)} , drv{std::make_unique<Derivation>(drv)}
@ -59,7 +60,7 @@ std::string DerivationGoal::key()
}.to_string(worker.store); }.to_string(worker.store);
} }
Goal::Co DerivationGoal::haveDerivation() Goal::Co DerivationGoal::haveDerivation(bool storeDerivation)
{ {
trace("have derivation"); trace("have derivation");
@ -153,11 +154,8 @@ Goal::Co DerivationGoal::haveDerivation()
if (resolutionGoal->resolvedDrv) { if (resolutionGoal->resolvedDrv) {
auto & [pathResolved, drvResolved] = *resolutionGoal->resolvedDrv; auto & [pathResolved, drvResolved] = *resolutionGoal->resolvedDrv;
/* Store the resolved derivation, as part of the record of auto resolvedDrvGoal =
what we're actually building */ worker.makeDerivationGoal(pathResolved, drvResolved, wantedOutput, buildMode, /*storeDerivation=*/true);
writeDerivation(worker.store, drvResolved);
auto resolvedDrvGoal = worker.makeDerivationGoal(pathResolved, drvResolved, wantedOutput, buildMode);
{ {
Goals waitees{resolvedDrvGoal}; Goals waitees{resolvedDrvGoal};
co_await await(std::move(waitees)); co_await await(std::move(waitees));
@ -233,7 +231,7 @@ Goal::Co DerivationGoal::haveDerivation()
/* Give up on substitution for the output we want, actually build this derivation */ /* Give up on substitution for the output we want, actually build this derivation */
auto g = worker.makeDerivationBuildingGoal(drvPath, *drv, buildMode); auto g = worker.makeDerivationBuildingGoal(drvPath, *drv, buildMode, storeDerivation);
/* We will finish with it ourselves, as if we were the derivational goal. */ /* We will finish with it ourselves, as if we were the derivational goal. */
g->preserveException = true; g->preserveException = true;

View file

@ -145,7 +145,7 @@ Goal::Co DerivationTrampolineGoal::haveDerivation(StorePath drvPath, Derivation
/* Build this step! */ /* Build this step! */
for (auto & output : resolvedWantedOutputs) { for (auto & output : resolvedWantedOutputs) {
auto g = upcast_goal(worker.makeDerivationGoal(drvPath, drv, output, buildMode)); auto g = upcast_goal(worker.makeDerivationGoal(drvPath, drv, output, buildMode, false));
g->preserveException = true; g->preserveException = true;
/* We will finish with it ourselves, as if we were the derivational goal. */ /* We will finish with it ourselves, as if we were the derivational goal. */
concreteDrvGoals.insert(std::move(g)); concreteDrvGoals.insert(std::move(g));

View file

@ -76,9 +76,14 @@ std::shared_ptr<DerivationTrampolineGoal> Worker::makeDerivationTrampolineGoal(
} }
std::shared_ptr<DerivationGoal> Worker::makeDerivationGoal( std::shared_ptr<DerivationGoal> Worker::makeDerivationGoal(
const StorePath & drvPath, const Derivation & drv, const OutputName & wantedOutput, BuildMode buildMode) const StorePath & drvPath,
const Derivation & drv,
const OutputName & wantedOutput,
BuildMode buildMode,
bool storeDerivation)
{ {
return initGoalIfNeeded(derivationGoals[drvPath][wantedOutput], drvPath, drv, wantedOutput, *this, buildMode); return initGoalIfNeeded(
derivationGoals[drvPath][wantedOutput], drvPath, drv, wantedOutput, *this, buildMode, storeDerivation);
} }
std::shared_ptr<DerivationResolutionGoal> std::shared_ptr<DerivationResolutionGoal>
@ -87,10 +92,10 @@ Worker::makeDerivationResolutionGoal(const StorePath & drvPath, const Derivation
return initGoalIfNeeded(derivationResolutionGoals[drvPath], drvPath, drv, *this, buildMode); return initGoalIfNeeded(derivationResolutionGoals[drvPath], drvPath, drv, *this, buildMode);
} }
std::shared_ptr<DerivationBuildingGoal> std::shared_ptr<DerivationBuildingGoal> Worker::makeDerivationBuildingGoal(
Worker::makeDerivationBuildingGoal(const StorePath & drvPath, const Derivation & drv, BuildMode buildMode) const StorePath & drvPath, const Derivation & drv, BuildMode buildMode, bool storeDerivation)
{ {
return initGoalIfNeeded(derivationBuildingGoals[drvPath], drvPath, drv, *this, buildMode); return initGoalIfNeeded(derivationBuildingGoals[drvPath], drvPath, drv, *this, buildMode, storeDerivation);
} }
std::shared_ptr<PathSubstitutionGoal> std::shared_ptr<PathSubstitutionGoal>

View file

@ -29,7 +29,17 @@ typedef enum { rpAccept, rpDecline, rpPostpone } HookReply;
*/ */
struct DerivationBuildingGoal : public Goal struct DerivationBuildingGoal : public Goal
{ {
DerivationBuildingGoal(const StorePath & drvPath, const Derivation & drv, Worker & worker, BuildMode buildMode); /**
* @param storeDerivation Whether to store the derivation in
* `worker.store`. This is useful for newly-resolved derivations. In this
* case, the derivation was not created a priori, e.g. purely (or close
* enough) from evaluation of the Nix language, but also depends on the
* exact content produced by upstream builds. It is strongly advised to
* have a permanent record of such a resolved derivation in order to
* faithfully reconstruct the build history.
*/
DerivationBuildingGoal(
const StorePath & drvPath, const Derivation & drv, Worker & worker, BuildMode buildMode, bool storeDerivation);
~DerivationBuildingGoal(); ~DerivationBuildingGoal();
private: private:
@ -99,7 +109,7 @@ private:
/** /**
* The states. * The states.
*/ */
Co gaveUpOnSubstitution(); Co gaveUpOnSubstitution(bool storeDerivation);
Co tryToBuild(); Co tryToBuild();
/** /**

View file

@ -40,12 +40,16 @@ struct DerivationGoal : public Goal
*/ */
OutputName wantedOutput; OutputName wantedOutput;
/**
* @param storeDerivation See `DerivationBuildingGoal`. This is just passed along.
*/
DerivationGoal( DerivationGoal(
const StorePath & drvPath, const StorePath & drvPath,
const Derivation & drv, const Derivation & drv,
const OutputName & wantedOutput, const OutputName & wantedOutput,
Worker & worker, Worker & worker,
BuildMode buildMode); BuildMode buildMode,
bool storeDerivation);
~DerivationGoal() = default; ~DerivationGoal() = default;
void timedOut(Error && ex) override void timedOut(Error && ex) override
@ -80,7 +84,7 @@ private:
/** /**
* The states. * The states.
*/ */
Co haveDerivation(); Co haveDerivation(bool storeDerivation);
/** /**
* Return `std::nullopt` if the output is unknown, e.g. un unbuilt * Return `std::nullopt` if the output is unknown, e.g. un unbuilt

View file

@ -217,7 +217,11 @@ public:
const StorePath & drvPath, const OutputsSpec & wantedOutputs, const Derivation & drv, BuildMode buildMode); const StorePath & drvPath, const OutputsSpec & wantedOutputs, const Derivation & drv, BuildMode buildMode);
std::shared_ptr<DerivationGoal> makeDerivationGoal( std::shared_ptr<DerivationGoal> makeDerivationGoal(
const StorePath & drvPath, const Derivation & drv, const OutputName & wantedOutput, BuildMode buildMode); const StorePath & drvPath,
const Derivation & drv,
const OutputName & wantedOutput,
BuildMode buildMode,
bool storeDerivation);
/** /**
* @ref DerivationResolutionGoal "derivation resolution goal" * @ref DerivationResolutionGoal "derivation resolution goal"
@ -228,8 +232,8 @@ public:
/** /**
* @ref DerivationBuildingGoal "derivation building goal" * @ref DerivationBuildingGoal "derivation building goal"
*/ */
std::shared_ptr<DerivationBuildingGoal> std::shared_ptr<DerivationBuildingGoal> makeDerivationBuildingGoal(
makeDerivationBuildingGoal(const StorePath & drvPath, const Derivation & drv, BuildMode buildMode); const StorePath & drvPath, const Derivation & drv, BuildMode buildMode, bool storeDerivation);
/** /**
* @ref PathSubstitutionGoal "substitution goal" * @ref PathSubstitutionGoal "substitution goal"