aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/build
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore/build')
-rw-r--r--src/libstore/build/derivation-goal.cc219
-rw-r--r--src/libstore/build/derivation-goal.hh15
-rw-r--r--src/libstore/build/drv-output-substitution-goal.cc2
-rw-r--r--src/libstore/build/goal.cc2
-rw-r--r--src/libstore/build/goal.hh13
-rw-r--r--src/libstore/build/local-derivation-goal.cc51
-rw-r--r--src/libstore/build/substitution-goal.cc19
-rw-r--r--src/libstore/build/substitution-goal.hh5
8 files changed, 211 insertions, 115 deletions
diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc
index afed9bf16..53f212c1d 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -204,10 +204,33 @@ void DerivationGoal::haveDerivation()
{
trace("have derivation");
- if (drv->type() == DerivationType::CAFloating)
+ parsedDrv = std::make_unique<ParsedDerivation>(drvPath, *drv);
+
+ if (!drv->type().hasKnownOutputPaths())
settings.requireExperimentalFeature(Xp::CaDerivations);
- retrySubstitution = false;
+ if (!drv->type().isPure()) {
+ settings.requireExperimentalFeature(Xp::ImpureDerivations);
+
+ for (auto & [outputName, output] : drv->outputs) {
+ auto randomPath = StorePath::random(outputPathName(drv->name, outputName));
+ assert(!worker.store.isValidPath(randomPath));
+ initialOutputs.insert({
+ outputName,
+ InitialOutput {
+ .wanted = true,
+ .outputHash = impureOutputHash,
+ .known = InitialOutputStatus {
+ .path = randomPath,
+ .status = PathStatus::Absent
+ }
+ }
+ });
+ }
+
+ gaveUpOnSubstitution();
+ return;
+ }
for (auto & i : drv->outputsAndOptPaths(worker.store))
if (i.second.second)
@@ -232,9 +255,6 @@ void DerivationGoal::haveDerivation()
return;
}
- parsedDrv = std::make_unique<ParsedDerivation>(drvPath, *drv);
-
-
/* We are first going to try to create the invalid output paths
through substitutes. If that doesn't work, we'll build
them. */
@@ -268,6 +288,8 @@ void DerivationGoal::outputsSubstitutionTried()
{
trace("all outputs substituted (maybe)");
+ assert(drv->type().isPure());
+
if (nrFailed > 0 && nrFailed > nrNoSubstituters + nrIncompleteClosure && !settings.tryFallback) {
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 ",
@@ -311,18 +333,27 @@ void DerivationGoal::outputsSubstitutionTried()
gaveUpOnSubstitution();
}
+
/* At least one of the output paths could not be
produced using a substitute. So we have to build instead. */
void DerivationGoal::gaveUpOnSubstitution()
{
- /* Make sure checkPathValidity() from now on checks all
- outputs. */
- wantedOutputs.clear();
-
/* The inputs must be built before we can build this goal. */
+ inputDrvOutputs.clear();
if (useDerivation)
- for (auto & i : dynamic_cast<Derivation *>(drv.get())->inputDrvs)
+ for (auto & i : dynamic_cast<Derivation *>(drv.get())->inputDrvs) {
+ /* 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'",
+ worker.store.printStorePath(drvPath),
+ worker.store.printStorePath(i.first));
+ }
+
addWaitee(worker.makeDerivationGoal(i.first, i.second, buildMode == bmRepair ? bmRepair : bmNormal));
+ }
/* Copy the input sources from the eval store to the build
store. */
@@ -350,6 +381,8 @@ void DerivationGoal::gaveUpOnSubstitution()
void DerivationGoal::repairClosure()
{
+ assert(drv->type().isPure());
+
/* If we're repairing, we now know that our own outputs are valid.
Now check whether the other paths in the outputs closure are
good. If not, then start derivation goals for the derivations
@@ -426,7 +459,8 @@ void DerivationGoal::inputsRealised()
return;
}
- if (retrySubstitution) {
+ if (retrySubstitution && !retriedSubstitution) {
+ retriedSubstitution = true;
haveDerivation();
return;
}
@@ -440,19 +474,40 @@ void DerivationGoal::inputsRealised()
if (useDerivation) {
auto & fullDrv = *dynamic_cast<Derivation *>(drv.get());
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations) &&
- ((!fullDrv.inputDrvs.empty() && derivationIsCA(fullDrv.type()))
- || fullDrv.type() == DerivationType::DeferredInputAddressed)) {
+ auto drvType = fullDrv.type();
+ bool resolveDrv = std::visit(overloaded {
+ [&](const DerivationType::InputAddressed & ia) {
+ /* must resolve if deferred. */
+ return ia.deferred;
+ },
+ [&](const DerivationType::ContentAddressed & ca) {
+ return !fullDrv.inputDrvs.empty() && (
+ ca.fixed
+ /* Can optionally resolve if fixed, which is good
+ for avoiding unnecessary rebuilds. */
+ ? settings.isExperimentalFeatureEnabled(Xp::CaDerivations)
+ /* Must resolve if floating and there are any inputs
+ drvs. */
+ : true);
+ },
+ [&](const DerivationType::Impure &) {
+ return true;
+ }
+ }, drvType.raw());
+
+ if (resolveDrv && !fullDrv.inputDrvs.empty()) {
+ settings.requireExperimentalFeature(Xp::CaDerivations);
+
/* We are be able to resolve this derivation based on the
- now-known results of dependencies. If so, we become a stub goal
- aliasing that resolved derivation goal */
- std::optional attempt = fullDrv.tryResolve(worker.store);
+ now-known results of dependencies. If so, we become a
+ stub goal aliasing that resolved derivation goal. */
+ std::optional attempt = fullDrv.tryResolve(worker.store, inputDrvOutputs);
assert(attempt);
Derivation drvResolved { *std::move(attempt) };
auto pathResolved = writeDerivation(worker.store, drvResolved);
- auto msg = fmt("Resolved derivation: '%s' -> '%s'",
+ auto msg = fmt("resolved derivation: '%s' -> '%s'",
worker.store.printStorePath(drvPath),
worker.store.printStorePath(pathResolved));
act = std::make_unique<Activity>(*logger, lvlInfo, actBuildWaiting, msg,
@@ -473,21 +528,13 @@ void DerivationGoal::inputsRealised()
/* Add the relevant output closures of the input derivation
`i' as input paths. Only add the closures of output paths
that are specified as inputs. */
- assert(worker.evalStore.isValidPath(drvPath));
- auto outputs = worker.evalStore.queryPartialDerivationOutputMap(depDrvPath);
- for (auto & j : wantedDepOutputs) {
- if (outputs.count(j) > 0) {
- auto optRealizedInput = outputs.at(j);
- if (!optRealizedInput)
- throw Error(
- "derivation '%s' requires output '%s' from input derivation '%s', which is supposedly realized already, yet we still don't know what path corresponds to that output",
- worker.store.printStorePath(drvPath), j, worker.store.printStorePath(depDrvPath));
- worker.store.computeFSClosure(*optRealizedInput, inputPaths);
- } else
+ for (auto & j : wantedDepOutputs)
+ if (auto outPath = get(inputDrvOutputs, { depDrvPath, j }))
+ worker.store.computeFSClosure(*outPath, inputPaths);
+ else
throw Error(
"derivation '%s' requires non-existent output '%s' from input derivation '%s'",
worker.store.printStorePath(drvPath), j, worker.store.printStorePath(depDrvPath));
- }
}
}
@@ -501,7 +548,7 @@ void DerivationGoal::inputsRealised()
/* Don't repeat fixed-output derivations since they're already
verified by their output hash.*/
- nrRounds = derivationIsFixed(derivationType) ? 1 : settings.buildRepeat + 1;
+ nrRounds = derivationType.isFixed() ? 1 : settings.buildRepeat + 1;
/* Okay, try to build. Note that here we don't wait for a build
slot to become available, since we don't need one if there is a
@@ -908,7 +955,7 @@ void DerivationGoal::buildDone()
st =
dynamic_cast<NotDeterministic*>(&e) ? BuildResult::NotDeterministic :
statusOk(status) ? BuildResult::OutputRejected :
- derivationIsImpure(derivationType) || diskFull ? BuildResult::TransientFailure :
+ !derivationType.isSandboxed() || diskFull ? BuildResult::TransientFailure :
BuildResult::PermanentFailure;
}
@@ -919,60 +966,53 @@ void DerivationGoal::buildDone()
void DerivationGoal::resolvedFinished()
{
+ trace("resolved derivation finished");
+
assert(resolvedDrvGoal);
auto resolvedDrv = *resolvedDrvGoal->drv;
+ auto & resolvedResult = resolvedDrvGoal->buildResult;
- auto resolvedHashes = staticOutputHashes(worker.store, resolvedDrv);
+ DrvOutputs builtOutputs;
- StorePathSet outputPaths;
+ if (resolvedResult.success()) {
+ auto resolvedHashes = staticOutputHashes(worker.store, resolvedDrv);
- // `wantedOutputs` might be empty, which means “all the outputs”
- auto realWantedOutputs = wantedOutputs;
- if (realWantedOutputs.empty())
- realWantedOutputs = resolvedDrv.outputNames();
+ StorePathSet outputPaths;
- DrvOutputs builtOutputs;
+ // `wantedOutputs` might be empty, which means “all the outputs”
+ auto realWantedOutputs = wantedOutputs;
+ if (realWantedOutputs.empty())
+ realWantedOutputs = resolvedDrv.outputNames();
+
+ for (auto & wantedOutput : realWantedOutputs) {
+ assert(initialOutputs.count(wantedOutput) != 0);
+ assert(resolvedHashes.count(wantedOutput) != 0);
+ auto realisation = resolvedResult.builtOutputs.at(
+ DrvOutput { resolvedHashes.at(wantedOutput), wantedOutput });
+ if (drv->type().isPure()) {
+ auto newRealisation = realisation;
+ newRealisation.id = DrvOutput { initialOutputs.at(wantedOutput).outputHash, wantedOutput };
+ newRealisation.signatures.clear();
+ if (!drv->type().isFixed())
+ newRealisation.dependentRealisations = drvOutputReferences(worker.store, *drv, realisation.outPath);
+ signRealisation(newRealisation);
+ worker.store.registerDrvOutput(newRealisation);
+ }
+ outputPaths.insert(realisation.outPath);
+ builtOutputs.emplace(realisation.id, realisation);
+ }
- for (auto & wantedOutput : realWantedOutputs) {
- assert(initialOutputs.count(wantedOutput) != 0);
- assert(resolvedHashes.count(wantedOutput) != 0);
- auto realisation = worker.store.queryRealisation(
- DrvOutput{resolvedHashes.at(wantedOutput), wantedOutput}
+ runPostBuildHook(
+ worker.store,
+ *logger,
+ drvPath,
+ outputPaths
);
- // We've just built it, but maybe the build failed, in which case the
- // realisation won't be there
- if (realisation) {
- auto newRealisation = *realisation;
- newRealisation.id = DrvOutput{initialOutputs.at(wantedOutput).outputHash, wantedOutput};
- newRealisation.signatures.clear();
- newRealisation.dependentRealisations = drvOutputReferences(worker.store, *drv, realisation->outPath);
- signRealisation(newRealisation);
- worker.store.registerDrvOutput(newRealisation);
- outputPaths.insert(realisation->outPath);
- builtOutputs.emplace(realisation->id, *realisation);
- } else {
- // If we don't have a realisation, then it must mean that something
- // failed when building the resolved drv
- assert(!buildResult.success());
- }
}
- runPostBuildHook(
- worker.store,
- *logger,
- drvPath,
- outputPaths
- );
-
- auto status = [&]() {
- auto & resolvedResult = resolvedDrvGoal->buildResult;
- switch (resolvedResult.status) {
- case BuildResult::AlreadyValid:
- return BuildResult::ResolvesToAlreadyValid;
- default:
- return resolvedResult.status;
- }
- }();
+ auto status = resolvedResult.status;
+ if (status == BuildResult::AlreadyValid)
+ status = BuildResult::ResolvesToAlreadyValid;
done(status, std::move(builtOutputs));
}
@@ -1221,7 +1261,8 @@ void DerivationGoal::flushLine()
std::map<std::string, std::optional<StorePath>> DerivationGoal::queryPartialDerivationOutputMap()
{
- if (!useDerivation || drv->type() != DerivationType::CAFloating) {
+ assert(drv->type().isPure());
+ if (!useDerivation || drv->type().hasKnownOutputPaths()) {
std::map<std::string, std::optional<StorePath>> res;
for (auto & [name, output] : drv->outputs)
res.insert_or_assign(name, output.path(worker.store, drv->name, name));
@@ -1233,7 +1274,8 @@ std::map<std::string, std::optional<StorePath>> DerivationGoal::queryPartialDeri
OutputPathMap DerivationGoal::queryDerivationOutputMap()
{
- if (!useDerivation || drv->type() != DerivationType::CAFloating) {
+ assert(drv->type().isPure());
+ if (!useDerivation || drv->type().hasKnownOutputPaths()) {
OutputPathMap res;
for (auto & [name, output] : drv->outputsAndOptPaths(worker.store))
res.insert_or_assign(name, *output.second);
@@ -1246,6 +1288,8 @@ OutputPathMap DerivationGoal::queryDerivationOutputMap()
std::pair<bool, DrvOutputs> DerivationGoal::checkPathValidity()
{
+ if (!drv->type().isPure()) return { false, {} };
+
bool checkHash = buildMode == bmRepair;
auto wantedOutputsLeft = wantedOutputs;
DrvOutputs validOutputs;
@@ -1289,6 +1333,7 @@ std::pair<bool, DrvOutputs> DerivationGoal::checkPathValidity()
if (info.wanted && info.known && info.known->isValid())
validOutputs.emplace(drvOutput, Realisation { drvOutput, info.known->path });
}
+
// If we requested all the outputs via the empty set, we are always fine.
// If we requested specific elements, the loop above removes all the valid
// ones, so any that are left must be invalid.
@@ -1326,9 +1371,7 @@ void DerivationGoal::done(
{
buildResult.status = status;
if (ex)
- // FIXME: strip: "error: "
- buildResult.errorMsg = ex->what();
- amDone(buildResult.success() ? ecSuccess : ecFailed, ex);
+ buildResult.errorMsg = fmt("%s", normaltxt(ex->info().msg));
if (buildResult.status == BuildResult::TimedOut)
worker.timedOut = true;
if (buildResult.status == BuildResult::PermanentFailure)
@@ -1355,7 +1398,21 @@ void DerivationGoal::done(
fs.open(traceBuiltOutputsFile, std::fstream::out);
fs << worker.store.printStorePath(drvPath) << "\t" << buildResult.toString() << std::endl;
}
+
+ amDone(buildResult.success() ? ecSuccess : ecFailed, ex);
}
+void DerivationGoal::waiteeDone(GoalPtr waitee, ExitCode result)
+{
+ Goal::waiteeDone(waitee, result);
+
+ if (waitee->buildResult.success())
+ if (auto bfd = std::get_if<DerivedPath::Built>(&waitee->buildResult.path))
+ for (auto & [output, realisation] : waitee->buildResult.builtOutputs)
+ inputDrvOutputs.insert_or_assign(
+ { bfd->drvPath, output.outputName },
+ realisation.outPath);
+}
+
}
diff --git a/src/libstore/build/derivation-goal.hh b/src/libstore/build/derivation-goal.hh
index ea2db89b2..2d8bfd592 100644
--- a/src/libstore/build/derivation-goal.hh
+++ b/src/libstore/build/derivation-goal.hh
@@ -57,12 +57,21 @@ struct DerivationGoal : public Goal
them. */
StringSet wantedOutputs;
+ /* Mapping from input derivations + output names to actual store
+ paths. This is filled in by waiteeDone() as each dependency
+ finishes, before inputsRealised() is reached, */
+ std::map<std::pair<StorePath, std::string>, StorePath> inputDrvOutputs;
+
/* Whether additional wanted outputs have been added. */
bool needRestart = false;
/* Whether to retry substituting the outputs after building the
- inputs. */
- bool retrySubstitution;
+ inputs. This is done in case of an incomplete closure. */
+ bool retrySubstitution = false;
+
+ /* Whether we've retried substitution, in which case we won't try
+ again. */
+ bool retriedSubstitution = false;
/* The derivation stored at drvPath. */
std::unique_ptr<Derivation> drv;
@@ -220,6 +229,8 @@ struct DerivationGoal : public Goal
DrvOutputs builtOutputs = {},
std::optional<Error> ex = {});
+ void waiteeDone(GoalPtr waitee, ExitCode result) override;
+
StorePathSet exportReferences(const StorePathSet & storePaths);
};
diff --git a/src/libstore/build/drv-output-substitution-goal.cc b/src/libstore/build/drv-output-substitution-goal.cc
index e50292c1e..b7f7b5ab1 100644
--- a/src/libstore/build/drv-output-substitution-goal.cc
+++ b/src/libstore/build/drv-output-substitution-goal.cc
@@ -41,7 +41,7 @@ void DrvOutputSubstitutionGoal::tryNext()
if (subs.size() == 0) {
/* None left. Terminate this goal and let someone else deal
with it. */
- debug("drv output '%s' is required, but there is no substituter that can provide it", id.to_string());
+ debug("derivation output '%s' is required, but there is no substituter that can provide it", id.to_string());
/* Hack: don't indicate failure if there were no substituters.
In that case the calling derivation should just do a
diff --git a/src/libstore/build/goal.cc b/src/libstore/build/goal.cc
index d2420b107..58e805f55 100644
--- a/src/libstore/build/goal.cc
+++ b/src/libstore/build/goal.cc
@@ -28,7 +28,7 @@ void Goal::addWaitee(GoalPtr waitee)
void Goal::waiteeDone(GoalPtr waitee, ExitCode result)
{
- assert(waitees.find(waitee) != waitees.end());
+ assert(waitees.count(waitee));
waitees.erase(waitee);
trace(fmt("waitee '%s' done; %d left", waitee->name, waitees.size()));
diff --git a/src/libstore/build/goal.hh b/src/libstore/build/goal.hh
index 07c752bb9..35121c5d9 100644
--- a/src/libstore/build/goal.hh
+++ b/src/libstore/build/goal.hh
@@ -40,21 +40,21 @@ struct Goal : public std::enable_shared_from_this<Goal>
WeakGoals waiters;
/* Number of goals we are/were waiting for that have failed. */
- unsigned int nrFailed;
+ size_t nrFailed = 0;
/* Number of substitution goals we are/were waiting for that
failed because there are no substituters. */
- unsigned int nrNoSubstituters;
+ size_t nrNoSubstituters = 0;
/* Number of substitution goals we are/were waiting for that
failed because they had unsubstitutable references. */
- unsigned int nrIncompleteClosure;
+ size_t nrIncompleteClosure = 0;
/* Name of this goal for debugging purposes. */
std::string name;
/* Whether the goal is finished. */
- ExitCode exitCode;
+ ExitCode exitCode = ecBusy;
/* Build result. */
BuildResult buildResult;
@@ -65,10 +65,7 @@ struct Goal : public std::enable_shared_from_this<Goal>
Goal(Worker & worker, DerivedPath path)
: worker(worker)
, buildResult { .path = std::move(path) }
- {
- nrFailed = nrNoSubstituters = nrIncompleteClosure = 0;
- exitCode = ecBusy;
- }
+ { }
virtual ~Goal()
{
diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc
index a372728f5..4c91fa4fb 100644
--- a/src/libstore/build/local-derivation-goal.cc
+++ b/src/libstore/build/local-derivation-goal.cc
@@ -395,7 +395,7 @@ void LocalDerivationGoal::startBuilder()
else if (settings.sandboxMode == smDisabled)
useChroot = false;
else if (settings.sandboxMode == smRelaxed)
- useChroot = !(derivationIsImpure(derivationType)) && !noChroot;
+ useChroot = derivationType.isSandboxed() && !noChroot;
}
auto & localStore = getLocalStore();
@@ -608,7 +608,7 @@ void LocalDerivationGoal::startBuilder()
"nogroup:x:65534:\n", sandboxGid()));
/* Create /etc/hosts with localhost entry. */
- if (!(derivationIsImpure(derivationType)))
+ if (derivationType.isSandboxed())
writeFile(chrootRootDir + "/etc/hosts", "127.0.0.1 localhost\n::1 localhost\n");
/* Make the closure of the inputs available in the chroot,
@@ -704,6 +704,9 @@ void LocalDerivationGoal::startBuilder()
/* Run the builder. */
printMsg(lvlChatty, "executing builder '%1%'", drv->builder);
+ printMsg(lvlChatty, "using builder args '%1%'", concatStringsSep(" ", drv->args));
+ for (auto & i : drv->env)
+ printMsg(lvlVomit, "setting builder env variable '%1%'='%2%'", i.first, i.second);
/* Create the log file. */
Path logFile = openLogFile();
@@ -796,7 +799,7 @@ void LocalDerivationGoal::startBuilder()
us.
*/
- if (!(derivationIsImpure(derivationType)))
+ if (derivationType.isSandboxed())
privateNetwork = true;
userNamespaceSync.create();
@@ -1049,7 +1052,7 @@ void LocalDerivationGoal::initEnv()
derivation, tell the builder, so that for instance `fetchurl'
can skip checking the output. On older Nixes, this environment
variable won't be set, so `fetchurl' will do the check. */
- if (derivationIsFixed(derivationType)) env["NIX_OUTPUT_CHECKED"] = "1";
+ if (derivationType.isFixed()) env["NIX_OUTPUT_CHECKED"] = "1";
/* *Only* if this is a fixed-output derivation, propagate the
values of the environment variables specified in the
@@ -1060,7 +1063,7 @@ void LocalDerivationGoal::initEnv()
to the builder is generally impure, but the output of
fixed-output derivations is by definition pure (since we
already know the cryptographic hash of the output). */
- if (derivationIsImpure(derivationType)) {
+ if (!derivationType.isSandboxed()) {
for (auto & i : parsedDrv->getStringsAttr("impureEnvVars").value_or(Strings()))
env[i] = getEnv(i).value_or("");
}
@@ -1340,6 +1343,12 @@ struct RestrictedStore : public virtual RestrictedStoreConfig, public virtual Lo
next->queryMissing(allowed, willBuild, willSubstitute,
unknown, downloadSize, narSize);
}
+
+ virtual std::optional<std::string> getBuildLog(const StorePath & path) override
+ { return std::nullopt; }
+
+ virtual void addBuildLog(const StorePath & path, std::string_view log) override
+ { unsupported("addBuildLog"); }
};
@@ -1668,7 +1677,7 @@ void LocalDerivationGoal::runChild()
/* Fixed-output derivations typically need to access the
network, so give them access to /etc/resolv.conf and so
on. */
- if (derivationIsImpure(derivationType)) {
+ if (!derivationType.isSandboxed()) {
// Only use nss functions to resolve hosts and
// services. Don’t use it for anything else that may
// be configured for this system. This limits the
@@ -1912,7 +1921,7 @@ void LocalDerivationGoal::runChild()
sandboxProfile += "(import \"sandbox-defaults.sb\")\n";
- if (derivationIsImpure(derivationType))
+ if (!derivationType.isSandboxed())
sandboxProfile += "(import \"sandbox-network.sb\")\n";
/* Add the output paths we'll use at build-time to the chroot */
@@ -2273,7 +2282,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
return res;
};
- auto newInfoFromCA = [&](const DerivationOutputCAFloating outputHash) -> ValidPathInfo {
+ auto newInfoFromCA = [&](const DerivationOutput::CAFloating outputHash) -> ValidPathInfo {
auto & st = outputStats.at(outputName);
if (outputHash.method == FileIngestionMethod::Flat) {
/* The output path should be a regular file without execute permission. */
@@ -2340,7 +2349,7 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
ValidPathInfo newInfo = std::visit(overloaded {
- [&](const DerivationOutputInputAddressed & output) {
+ [&](const DerivationOutput::InputAddressed & output) {
/* input-addressed case */
auto requiredFinalPath = output.path;
/* Preemptively add rewrite rule for final hash, as that is
@@ -2360,8 +2369,8 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
return newInfo0;
},
- [&](const DerivationOutputCAFixed & dof) {
- auto newInfo0 = newInfoFromCA(DerivationOutputCAFloating {
+ [&](const DerivationOutput::CAFixed & dof) {
+ auto newInfo0 = newInfoFromCA(DerivationOutput::CAFloating {
.method = dof.hash.method,
.hashType = dof.hash.hash.type,
});
@@ -2383,17 +2392,24 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
return newInfo0;
},
- [&](DerivationOutputCAFloating & dof) {
+ [&](const DerivationOutput::CAFloating & dof) {
return newInfoFromCA(dof);
},
- [&](DerivationOutputDeferred) -> ValidPathInfo {
+ [&](const DerivationOutput::Deferred &) -> ValidPathInfo {
// No derivation should reach that point without having been
// rewritten first
assert(false);
},
- }, output.output);
+ [&](const DerivationOutput::Impure & doi) {
+ return newInfoFromCA(DerivationOutput::CAFloating {
+ .method = doi.method,
+ .hashType = doi.hashType,
+ });
+ },
+
+ }, output.raw());
/* FIXME: set proper permissions in restorePath() so
we don't have to do another traversal. */
@@ -2603,11 +2619,14 @@ DrvOutputs LocalDerivationGoal::registerOutputs()
},
.outPath = newInfo.path
};
- if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) {
+ if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)
+ && drv->type().isPure())
+ {
signRealisation(thisRealisation);
worker.store.registerDrvOutput(thisRealisation);
}
- builtOutputs.emplace(thisRealisation.id, thisRealisation);
+ if (wantOutput(outputName, wantedOutputs))
+ builtOutputs.emplace(thisRealisation.id, thisRealisation);
}
return builtOutputs;
diff --git a/src/libstore/build/substitution-goal.cc b/src/libstore/build/substitution-goal.cc
index 31e6dbc9f..ca5218627 100644
--- a/src/libstore/build/substitution-goal.cc
+++ b/src/libstore/build/substitution-goal.cc
@@ -24,9 +24,16 @@ PathSubstitutionGoal::~PathSubstitutionGoal()
}
-void PathSubstitutionGoal::done(ExitCode result, BuildResult::Status status)
+void PathSubstitutionGoal::done(
+ ExitCode result,
+ BuildResult::Status status,
+ std::optional<std::string> errorMsg)
{
buildResult.status = status;
+ if (errorMsg) {
+ debug(*errorMsg);
+ buildResult.errorMsg = *errorMsg;
+ }
amDone(result);
}
@@ -67,12 +74,14 @@ void PathSubstitutionGoal::tryNext()
if (subs.size() == 0) {
/* None left. Terminate this goal and let someone else deal
with it. */
- debug("path '%s' is required, but there is no substituter that can build it", worker.store.printStorePath(storePath));
/* Hack: don't indicate failure if there were no substituters.
In that case the calling derivation should just do a
build. */
- done(substituterFailed ? ecFailed : ecNoSubstituters, BuildResult::NoSubstituters);
+ done(
+ substituterFailed ? ecFailed : ecNoSubstituters,
+ BuildResult::NoSubstituters,
+ fmt("path '%s' is required, but there is no substituter that can build it", worker.store.printStorePath(storePath)));
if (substituterFailed) {
worker.failedSubstitutions++;
@@ -169,10 +178,10 @@ void PathSubstitutionGoal::referencesValid()
trace("all references realised");
if (nrFailed > 0) {
- debug("some references of path '%s' could not be realised", worker.store.printStorePath(storePath));
done(
nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed,
- BuildResult::DependencyFailed);
+ BuildResult::DependencyFailed,
+ fmt("some references of path '%s' could not be realised", worker.store.printStorePath(storePath)));
return;
}
diff --git a/src/libstore/build/substitution-goal.hh b/src/libstore/build/substitution-goal.hh
index 946f13841..a73f8e666 100644
--- a/src/libstore/build/substitution-goal.hh
+++ b/src/libstore/build/substitution-goal.hh
@@ -53,7 +53,10 @@ struct PathSubstitutionGoal : public Goal
/* Content address for recomputing store path */
std::optional<ContentAddress> ca;
- void done(ExitCode result, BuildResult::Status status);
+ void done(
+ ExitCode result,
+ BuildResult::Status status,
+ std::optional<std::string> errorMsg = {});
public:
PathSubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);