aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/build/derivation-goal.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore/build/derivation-goal.cc')
-rw-r--r--src/libstore/build/derivation-goal.cc153
1 files changed, 75 insertions, 78 deletions
diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc
index 38c54e854..ab7b2b88c 100644
--- a/src/libstore/build/derivation-goal.cc
+++ b/src/libstore/build/derivation-goal.cc
@@ -130,16 +130,16 @@ void DerivationGoal::killChild()
}
-void DerivationGoal::timedOut(Error && ex)
+Goal::Finished DerivationGoal::timedOut(Error && ex)
{
killChild();
- done(BuildResult::TimedOut, {}, std::move(ex));
+ return done(BuildResult::TimedOut, {}, std::move(ex));
}
-void DerivationGoal::work()
+Goal::WorkResult DerivationGoal::work()
{
- (this->*state)();
+ return (this->*state)();
}
void DerivationGoal::addWantedOutputs(const OutputsSpec & outputs)
@@ -163,7 +163,7 @@ void DerivationGoal::addWantedOutputs(const OutputsSpec & outputs)
}
-void DerivationGoal::getDerivation()
+Goal::WorkResult DerivationGoal::getDerivation()
{
trace("init");
@@ -171,23 +171,22 @@ void DerivationGoal::getDerivation()
exists. If it doesn't, it may be created through a
substitute. */
if (buildMode == bmNormal && worker.evalStore.isValidPath(drvPath)) {
- loadDerivation();
- return;
+ return loadDerivation();
}
addWaitee(worker.makePathSubstitutionGoal(drvPath));
state = &DerivationGoal::loadDerivation;
+ return StillAlive{};
}
-void DerivationGoal::loadDerivation()
+Goal::WorkResult DerivationGoal::loadDerivation()
{
trace("loading derivation");
if (nrFailed != 0) {
- done(BuildResult::MiscFailure, {}, Error("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath)));
- return;
+ return done(BuildResult::MiscFailure, {}, Error("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath)));
}
/* `drvPath' should already be a root, but let's be on the safe
@@ -209,11 +208,11 @@ void DerivationGoal::loadDerivation()
}
assert(drv);
- haveDerivation();
+ return haveDerivation();
}
-void DerivationGoal::haveDerivation()
+Goal::WorkResult DerivationGoal::haveDerivation()
{
trace("have derivation");
@@ -241,8 +240,7 @@ void DerivationGoal::haveDerivation()
});
}
- gaveUpOnSubstitution();
- return;
+ return gaveUpOnSubstitution();
}
for (auto & i : drv->outputsAndOptPaths(worker.store))
@@ -264,8 +262,7 @@ void DerivationGoal::haveDerivation()
/* If they are all valid, then we're done. */
if (allValid && buildMode == bmNormal) {
- done(BuildResult::AlreadyValid, std::move(validOutputs));
- return;
+ return done(BuildResult::AlreadyValid, std::move(validOutputs));
}
/* We are first going to try to create the invalid output paths
@@ -290,24 +287,24 @@ void DerivationGoal::haveDerivation()
}
}
- if (waitees.empty()) /* to prevent hang (no wake-up event) */
- outputsSubstitutionTried();
- else
+ if (waitees.empty()) { /* to prevent hang (no wake-up event) */
+ return outputsSubstitutionTried();
+ } else {
state = &DerivationGoal::outputsSubstitutionTried;
+ return StillAlive{};
+ }
}
-
-void DerivationGoal::outputsSubstitutionTried()
+Goal::WorkResult DerivationGoal::outputsSubstitutionTried()
{
trace("all outputs substituted (maybe)");
assert(drv->type().isPure());
if (nrFailed > 0 && nrFailed > nrNoSubstituters + nrIncompleteClosure && !settings.tryFallback) {
- done(BuildResult::TransientFailure, {},
+ 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)));
- return;
}
/* If the substitutes form an incomplete closure, then we should
@@ -341,32 +338,29 @@ void DerivationGoal::outputsSubstitutionTried()
if (needRestart == NeedRestartForMoreOutputs::OutputsAddedDoNeed) {
needRestart = NeedRestartForMoreOutputs::OutputsUnmodifedDontNeed;
- haveDerivation();
- return;
+ return haveDerivation();
}
auto [allValid, validOutputs] = checkPathValidity();
if (buildMode == bmNormal && allValid) {
- done(BuildResult::Substituted, std::move(validOutputs));
- return;
+ return done(BuildResult::Substituted, std::move(validOutputs));
}
if (buildMode == bmRepair && allValid) {
- repairClosure();
- return;
+ 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 */
- gaveUpOnSubstitution();
+ return gaveUpOnSubstitution();
}
/* At least one of the output paths could not be
produced using a substitute. So we have to build instead. */
-void DerivationGoal::gaveUpOnSubstitution()
+Goal::WorkResult DerivationGoal::gaveUpOnSubstitution()
{
/* At this point we are building all outputs, so if more are wanted there
is no need to restart. */
@@ -427,14 +421,16 @@ void DerivationGoal::gaveUpOnSubstitution()
addWaitee(worker.makePathSubstitutionGoal(i));
}
- if (waitees.empty()) /* to prevent hang (no wake-up event) */
- inputsRealised();
- else
+ if (waitees.empty()) {/* to prevent hang (no wake-up event) */
+ return inputsRealised();
+ } else {
state = &DerivationGoal::inputsRealised;
+ return StillAlive{};
+ }
}
-void DerivationGoal::repairClosure()
+Goal::WorkResult DerivationGoal::repairClosure()
{
assert(drv->type().isPure());
@@ -488,41 +484,39 @@ void DerivationGoal::repairClosure()
}
if (waitees.empty()) {
- done(BuildResult::AlreadyValid, assertPathValidity());
- return;
+ return done(BuildResult::AlreadyValid, assertPathValidity());
}
state = &DerivationGoal::closureRepaired;
+ return StillAlive{};
}
-void DerivationGoal::closureRepaired()
+Goal::WorkResult DerivationGoal::closureRepaired()
{
trace("closure repaired");
if (nrFailed > 0)
throw Error("some paths in the output closure of derivation '%s' could not be repaired",
worker.store.printStorePath(drvPath));
- done(BuildResult::AlreadyValid, assertPathValidity());
+ return done(BuildResult::AlreadyValid, assertPathValidity());
}
-void DerivationGoal::inputsRealised()
+Goal::WorkResult DerivationGoal::inputsRealised()
{
trace("all inputs realised");
if (nrFailed != 0) {
if (!useDerivation)
throw Error("some dependencies of '%s' are missing", worker.store.printStorePath(drvPath));
- done(BuildResult::DependencyFailed, {}, Error(
+ return done(BuildResult::DependencyFailed, {}, Error(
"%s dependencies of derivation '%s' failed to build",
nrFailed, worker.store.printStorePath(drvPath)));
- return;
}
if (retrySubstitution == RetrySubstitution::YesNeed) {
retrySubstitution = RetrySubstitution::AlreadyRetried;
- haveDerivation();
- return;
+ return haveDerivation();
}
/* Gather information necessary for computing the closure and/or
@@ -589,7 +583,7 @@ void DerivationGoal::inputsRealised()
addWaitee(resolvedDrvGoal);
state = &DerivationGoal::resolvedFinished;
- return;
+ return StillAlive{};
}
std::function<void(const StorePath &, const DerivedPathMap<StringSet>::ChildNode &)> accumInputPaths;
@@ -655,9 +649,10 @@ void DerivationGoal::inputsRealised()
build hook. */
state = &DerivationGoal::tryToBuild;
worker.wakeUp(shared_from_this());
+ return StillAlive{};
}
-void DerivationGoal::started()
+Goal::WorkResult DerivationGoal::started()
{
auto msg = fmt(
buildMode == bmRepair ? "repairing outputs of '%s'" :
@@ -668,9 +663,10 @@ void DerivationGoal::started()
act = std::make_unique<Activity>(*logger, lvlInfo, actBuild, msg,
Logger::Fields{worker.store.printStorePath(drvPath), hook ? machineName : "", 1, 1});
mcRunningBuilds = std::make_unique<MaintainCount<uint64_t>>(worker.runningBuilds);
+ return StillAlive{};
}
-void DerivationGoal::tryToBuild()
+Goal::WorkResult DerivationGoal::tryToBuild()
{
trace("trying to build");
@@ -706,7 +702,7 @@ void DerivationGoal::tryToBuild()
actLock = std::make_unique<Activity>(*logger, lvlWarn, actBuildWaiting,
fmt("waiting for lock on %s", Magenta(showPaths(lockFiles))));
worker.waitForAWhile(shared_from_this());
- return;
+ return StillAlive{};
}
actLock.reset();
@@ -723,8 +719,7 @@ void DerivationGoal::tryToBuild()
if (buildMode != bmCheck && allValid) {
debug("skipping build of derivation '%s', someone beat us to it", worker.store.printStorePath(drvPath));
outputLocks.setDeletion(true);
- done(BuildResult::AlreadyValid, std::move(validOutputs));
- return;
+ return done(BuildResult::AlreadyValid, std::move(validOutputs));
}
/* If any of the outputs already exist but are not valid, delete
@@ -751,8 +746,7 @@ void DerivationGoal::tryToBuild()
actLock.reset();
buildResult.startTime = time(0); // inexact
state = &DerivationGoal::buildDone;
- started();
- return;
+ return started();
case rpPostpone:
/* Not now; wait until at least one child finishes or
the wake-up timeout expires. */
@@ -761,7 +755,7 @@ void DerivationGoal::tryToBuild()
fmt("waiting for a machine to build '%s'", Magenta(worker.store.printStorePath(drvPath))));
worker.waitForAWhile(shared_from_this());
outputLocks.unlock();
- return;
+ return StillAlive{};
case rpDecline:
/* We should do it ourselves. */
break;
@@ -772,9 +766,10 @@ void DerivationGoal::tryToBuild()
state = &DerivationGoal::tryLocalBuild;
worker.wakeUp(shared_from_this());
+ return StillAlive{};
}
-void DerivationGoal::tryLocalBuild() {
+Goal::WorkResult DerivationGoal::tryLocalBuild() {
throw Error(
"unable to build with a primary store that isn't a local store; "
"either pass a different '--store' or enable remote builds."
@@ -932,7 +927,7 @@ void runPostBuildHook(
proc.getStdout()->drainInto(sink);
}
-void DerivationGoal::buildDone()
+Goal::WorkResult DerivationGoal::buildDone()
{
trace("build done");
@@ -1027,8 +1022,7 @@ void DerivationGoal::buildDone()
outputLocks.setDeletion(true);
outputLocks.unlock();
- done(BuildResult::Built, std::move(builtOutputs));
-
+ return done(BuildResult::Built, std::move(builtOutputs));
} catch (BuildError & e) {
outputLocks.unlock();
@@ -1049,12 +1043,11 @@ void DerivationGoal::buildDone()
BuildResult::PermanentFailure;
}
- done(st, {}, std::move(e));
- return;
+ return done(st, {}, std::move(e));
}
}
-void DerivationGoal::resolvedFinished()
+Goal::WorkResult DerivationGoal::resolvedFinished()
{
trace("resolved derivation finished");
@@ -1122,26 +1115,26 @@ void DerivationGoal::resolvedFinished()
if (status == BuildResult::AlreadyValid)
status = BuildResult::ResolvesToAlreadyValid;
- done(status, std::move(builtOutputs));
+ return done(status, std::move(builtOutputs));
}
HookReply DerivationGoal::tryBuildHook()
{
- if (!worker.tryBuildHook || !useDerivation) return rpDecline;
+ if (!worker.hook.available || !useDerivation) return rpDecline;
- if (!worker.hook)
- worker.hook = std::make_unique<HookInstance>();
+ if (!worker.hook.instance)
+ worker.hook.instance = std::make_unique<HookInstance>();
try {
/* Send the request to the hook. */
- worker.hook->sink
+ worker.hook.instance->sink
<< "try"
<< (worker.getNrLocalBuilds() < settings.maxBuildJobs ? 1 : 0)
<< drv->platform
<< worker.store.printStorePath(drvPath)
<< parsedDrv->getRequiredSystemFeatures();
- worker.hook->sink.flush();
+ worker.hook.instance->sink.flush();
/* Read the first line of input, which should be a word indicating
whether the hook wishes to perform the build. */
@@ -1149,13 +1142,13 @@ HookReply DerivationGoal::tryBuildHook()
while (true) {
auto s = [&]() {
try {
- return readLine(worker.hook->fromHook.readSide.get());
+ return readLine(worker.hook.instance->fromHook.readSide.get());
} catch (Error & e) {
e.addTrace({}, "while reading the response from the build hook");
throw;
}
}();
- if (handleJSONLogMessage(s, worker.act, worker.hook->activities, true))
+ if (handleJSONLogMessage(s, worker.act, worker.hook.instance->activities, true))
;
else if (s.substr(0, 2) == "# ") {
reply = s.substr(2);
@@ -1172,8 +1165,8 @@ HookReply DerivationGoal::tryBuildHook()
if (reply == "decline")
return rpDecline;
else if (reply == "decline-permanently") {
- worker.tryBuildHook = false;
- worker.hook = 0;
+ worker.hook.available = false;
+ worker.hook.instance.reset();
return rpDecline;
}
else if (reply == "postpone")
@@ -1185,14 +1178,14 @@ HookReply DerivationGoal::tryBuildHook()
if (e.errNo == EPIPE) {
printError(
"build hook died unexpectedly: %s",
- chomp(drainFD(worker.hook->fromHook.readSide.get())));
- worker.hook = 0;
+ chomp(drainFD(worker.hook.instance->fromHook.readSide.get())));
+ worker.hook.instance.reset();
return rpDecline;
} else
throw;
}
- hook = std::move(worker.hook);
+ hook = std::move(worker.hook.instance);
try {
machineName = readLine(hook->fromHook.readSide.get());
@@ -1293,7 +1286,7 @@ bool DerivationGoal::isReadDesc(int fd)
return fd == hook->builderOut.readSide.get();
}
-void DerivationGoal::handleChildOutput(int fd, std::string_view data)
+Goal::WorkResult DerivationGoal::handleChildOutput(int fd, std::string_view data)
{
// local & `ssh://`-builds are dealt with here.
auto isWrittenToLog = isReadDesc(fd);
@@ -1302,11 +1295,10 @@ void DerivationGoal::handleChildOutput(int fd, std::string_view data)
logSize += data.size();
if (settings.maxLogSize && logSize > settings.maxLogSize) {
killChild();
- done(
+ return done(
BuildResult::LogLimitExceeded, {},
Error("%s killed after writing more than %d bytes of log output",
getName(), settings.maxLogSize));
- return;
}
for (auto c : data)
@@ -1357,6 +1349,8 @@ void DerivationGoal::handleChildOutput(int fd, std::string_view data)
} else
currentHookLine += c;
}
+
+ return StillAlive{};
}
@@ -1505,7 +1499,7 @@ SingleDrvOutputs DerivationGoal::assertPathValidity()
}
-void DerivationGoal::done(
+Goal::Finished DerivationGoal::done(
BuildResult::Status status,
SingleDrvOutputs builtOutputs,
std::optional<Error> ex)
@@ -1540,7 +1534,10 @@ void DerivationGoal::done(
fs << worker.store.printStorePath(drvPath) << "\t" << buildResult.toString() << std::endl;
}
- amDone(buildResult.success() ? ecSuccess : ecFailed, std::move(ex));
+ return Finished{
+ .result = buildResult.success() ? ecSuccess : ecFailed,
+ .ex = ex ? std::make_unique<Error>(std::move(*ex)) : nullptr,
+ };
}