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

DerivationGoal inline gaveUpOnSubstitution lambda

We can shuffle around control flow so it's only called once. You'll
definitely want to review this diff ignoring whitespace.
This commit is contained in:
John Ericson 2025-08-14 00:21:37 -04:00
parent 88275e5723
commit 14441f9382

View file

@ -75,121 +75,114 @@ Goal::Co DerivationGoal::haveDerivation()
if (!drv->type().hasKnownOutputPaths())
experimentalFeatureSettings.require(Xp::CaDerivations);
/* At least one of the output paths could not be
produced using a substitute. So we have to build instead. */
auto gaveUpOnSubstitution = [&]() -> Goal::Co {
auto g = worker.makeDerivationBuildingGoal(drvPath, *drv, buildMode);
/* We will finish with it ourselves, as if we were the derivational goal. */
g->preserveException = true;
{
Goals waitees;
waitees.insert(g);
co_await await(std::move(waitees));
}
trace("outer build done");
buildResult = g->buildResult;
if (buildMode == bmCheck) {
/* In checking mode, the builder will not register any outputs.
So we want to make sure the ones that we wanted to check are
properly there. */
buildResult.builtOutputs = {{wantedOutput, assertPathValidity()}};
}
for (auto it = buildResult.builtOutputs.begin(); it != buildResult.builtOutputs.end();) {
if (it->first != wantedOutput) {
it = buildResult.builtOutputs.erase(it);
} else {
++it;
}
}
if (buildResult.success())
assert(buildResult.builtOutputs.count(wantedOutput) > 0);
co_return amDone(g->exitCode, g->ex);
};
for (auto & i : drv->outputsAndOptPaths(worker.store))
if (i.second.second)
worker.store.addTempRoot(*i.second.second);
if (auto * mOutputHash = get(staticOutputHashes(worker.evalStore, *drv), wantedOutput)) {
outputHash = *mOutputHash;
}
/* We don't yet have any safe way to cache an impure derivation at
this step. */
if (drv->type().isImpure()) {
experimentalFeatureSettings.require(Xp::ImpureDerivations);
} else {
/* Check what outputs paths are not already valid. */
auto checkResult = checkPathValidity();
/* If they are all valid, then we're done. */
if (checkResult && checkResult->second == PathStatus::Valid && buildMode == bmNormal) {
co_return done(BuildResult::AlreadyValid, {{wantedOutput, checkResult->first}});
}
Goals waitees;
/* We are first going to try to create the invalid output paths
through substitutes. If that doesn't work, we'll build
them. */
if (settings.useSubstitutes && drvOptions.substitutesAllowed()) {
if (!checkResult)
waitees.insert(upcast_goal(worker.makeDrvOutputSubstitutionGoal(
DrvOutput{outputHash, wantedOutput}, buildMode == bmRepair ? Repair : NoRepair)));
else {
auto * cap = getDerivationCA(*drv);
waitees.insert(upcast_goal(worker.makePathSubstitutionGoal(
checkResult->first.outPath,
buildMode == bmRepair ? Repair : NoRepair,
cap ? std::optional{*cap} : std::nullopt)));
}
}
co_await await(std::move(waitees));
trace("all outputs substituted (maybe)");
assert(!drv->type().isImpure());
if (nrFailed > 0 && nrFailed > nrNoSubstituters && !settings.tryFallback) {
co_return done(
BuildResult::TransientFailure,
{},
Error(
"some substitutes for the outputs of derivation '%s' failed (usually happens due to networking issues); try '--fallback' to build derivation from source ",
worker.store.printStorePath(drvPath)));
}
nrFailed = nrNoSubstituters = 0;
checkResult = checkPathValidity();
bool allValid = checkResult && checkResult->second == PathStatus::Valid;
if (buildMode == bmNormal && allValid) {
co_return done(BuildResult::Substituted, {{wantedOutput, checkResult->first}});
}
if (buildMode == bmRepair && allValid) {
co_return repairClosure();
}
if (buildMode == bmCheck && !allValid)
throw Error(
"some outputs of '%s' are not valid, so checking is not possible",
worker.store.printStorePath(drvPath));
}
/* Give up on substitution for the output we want, actually build this derivation */
auto g = worker.makeDerivationBuildingGoal(drvPath, *drv, buildMode);
/* We will finish with it ourselves, as if we were the derivational goal. */
g->preserveException = true;
{
if (auto * mOutputHash = get(staticOutputHashes(worker.evalStore, *drv), wantedOutput)) {
outputHash = *mOutputHash;
}
Goals waitees;
waitees.insert(g);
co_await await(std::move(waitees));
}
if (drv->type().isImpure()) {
experimentalFeatureSettings.require(Xp::ImpureDerivations);
/* We don't yet have any safe way to cache an impure derivation at
this step. */
co_return gaveUpOnSubstitution();
trace("outer build done");
buildResult = g->buildResult;
if (buildMode == bmCheck) {
/* In checking mode, the builder will not register any outputs.
So we want to make sure the ones that we wanted to check are
properly there. */
buildResult.builtOutputs = {{wantedOutput, assertPathValidity()}};
}
for (auto it = buildResult.builtOutputs.begin(); it != buildResult.builtOutputs.end();) {
if (it->first != wantedOutput) {
it = buildResult.builtOutputs.erase(it);
} else {
++it;
}
}
/* Check what outputs paths are not already valid. */
auto checkResult = checkPathValidity();
if (buildResult.success())
assert(buildResult.builtOutputs.count(wantedOutput) > 0);
/* If they are all valid, then we're done. */
if (checkResult && checkResult->second == PathStatus::Valid && buildMode == bmNormal) {
co_return done(BuildResult::AlreadyValid, {{wantedOutput, checkResult->first}});
}
Goals waitees;
/* We are first going to try to create the invalid output paths
through substitutes. If that doesn't work, we'll build
them. */
if (settings.useSubstitutes && drvOptions.substitutesAllowed()) {
if (!checkResult)
waitees.insert(upcast_goal(worker.makeDrvOutputSubstitutionGoal(
DrvOutput{outputHash, wantedOutput}, buildMode == bmRepair ? Repair : NoRepair)));
else {
auto * cap = getDerivationCA(*drv);
waitees.insert(upcast_goal(worker.makePathSubstitutionGoal(
checkResult->first.outPath,
buildMode == bmRepair ? Repair : NoRepair,
cap ? std::optional{*cap} : std::nullopt)));
}
}
co_await await(std::move(waitees));
trace("all outputs substituted (maybe)");
assert(!drv->type().isImpure());
if (nrFailed > 0 && nrFailed > nrNoSubstituters && !settings.tryFallback) {
co_return done(
BuildResult::TransientFailure,
{},
Error(
"some substitutes for the outputs of derivation '%s' failed (usually happens due to networking issues); try '--fallback' to build derivation from source ",
worker.store.printStorePath(drvPath)));
}
nrFailed = nrNoSubstituters = 0;
checkResult = checkPathValidity();
bool allValid = checkResult && checkResult->second == PathStatus::Valid;
if (buildMode == bmNormal && allValid) {
co_return done(BuildResult::Substituted, {{wantedOutput, checkResult->first}});
}
if (buildMode == bmRepair && allValid) {
co_return repairClosure();
}
if (buildMode == bmCheck && !allValid)
throw Error(
"some outputs of '%s' are not valid, so checking is not possible", worker.store.printStorePath(drvPath));
/* Nothing to wait for; tail call */
co_return gaveUpOnSubstitution();
co_return amDone(g->exitCode, g->ex);
}
/**