libstore: return finishedness from Goal methods
this is the first step towards removing all result-related mutation of Goal state from goal implementations themselves, and into Worker state instead. once that is done we can treat all non-const Goal fields like private state of the goal itself, and make threading of goals possible Change-Id: I69ff7d02a6fd91a65887c6640bfc4f5fb785b45c
This commit is contained in:
parent
724b345eb9
commit
dfcab1c3f0
10 changed files with 180 additions and 183 deletions
|
@ -130,16 +130,16 @@ void DerivationGoal::killChild()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DerivationGoal::timedOut(Error && ex)
|
Goal::Finished DerivationGoal::timedOut(Error && ex)
|
||||||
{
|
{
|
||||||
killChild();
|
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)
|
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");
|
trace("init");
|
||||||
|
|
||||||
|
@ -171,23 +171,22 @@ void DerivationGoal::getDerivation()
|
||||||
exists. If it doesn't, it may be created through a
|
exists. If it doesn't, it may be created through a
|
||||||
substitute. */
|
substitute. */
|
||||||
if (buildMode == bmNormal && worker.evalStore.isValidPath(drvPath)) {
|
if (buildMode == bmNormal && worker.evalStore.isValidPath(drvPath)) {
|
||||||
loadDerivation();
|
return loadDerivation();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addWaitee(worker.makePathSubstitutionGoal(drvPath));
|
addWaitee(worker.makePathSubstitutionGoal(drvPath));
|
||||||
|
|
||||||
state = &DerivationGoal::loadDerivation;
|
state = &DerivationGoal::loadDerivation;
|
||||||
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DerivationGoal::loadDerivation()
|
Goal::WorkResult DerivationGoal::loadDerivation()
|
||||||
{
|
{
|
||||||
trace("loading derivation");
|
trace("loading derivation");
|
||||||
|
|
||||||
if (nrFailed != 0) {
|
if (nrFailed != 0) {
|
||||||
done(BuildResult::MiscFailure, {}, Error("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath)));
|
return done(BuildResult::MiscFailure, {}, Error("cannot build missing derivation '%s'", worker.store.printStorePath(drvPath)));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* `drvPath' should already be a root, but let's be on the safe
|
/* `drvPath' should already be a root, but let's be on the safe
|
||||||
|
@ -209,11 +208,11 @@ void DerivationGoal::loadDerivation()
|
||||||
}
|
}
|
||||||
assert(drv);
|
assert(drv);
|
||||||
|
|
||||||
haveDerivation();
|
return haveDerivation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DerivationGoal::haveDerivation()
|
Goal::WorkResult DerivationGoal::haveDerivation()
|
||||||
{
|
{
|
||||||
trace("have derivation");
|
trace("have derivation");
|
||||||
|
|
||||||
|
@ -241,8 +240,7 @@ void DerivationGoal::haveDerivation()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
gaveUpOnSubstitution();
|
return gaveUpOnSubstitution();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto & i : drv->outputsAndOptPaths(worker.store))
|
for (auto & i : drv->outputsAndOptPaths(worker.store))
|
||||||
|
@ -264,8 +262,7 @@ void DerivationGoal::haveDerivation()
|
||||||
|
|
||||||
/* If they are all valid, then we're done. */
|
/* If they are all valid, then we're done. */
|
||||||
if (allValid && buildMode == bmNormal) {
|
if (allValid && buildMode == bmNormal) {
|
||||||
done(BuildResult::AlreadyValid, std::move(validOutputs));
|
return done(BuildResult::AlreadyValid, std::move(validOutputs));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We are first going to try to create the invalid output paths
|
/* 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) */
|
if (waitees.empty()) { /* to prevent hang (no wake-up event) */
|
||||||
outputsSubstitutionTried();
|
return outputsSubstitutionTried();
|
||||||
else
|
} else {
|
||||||
state = &DerivationGoal::outputsSubstitutionTried;
|
state = &DerivationGoal::outputsSubstitutionTried;
|
||||||
|
return StillAlive{};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Goal::WorkResult DerivationGoal::outputsSubstitutionTried()
|
||||||
void DerivationGoal::outputsSubstitutionTried()
|
|
||||||
{
|
{
|
||||||
trace("all outputs substituted (maybe)");
|
trace("all outputs substituted (maybe)");
|
||||||
|
|
||||||
assert(drv->type().isPure());
|
assert(drv->type().isPure());
|
||||||
|
|
||||||
if (nrFailed > 0 && nrFailed > nrNoSubstituters + nrIncompleteClosure && !settings.tryFallback) {
|
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 ",
|
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)));
|
worker.store.printStorePath(drvPath)));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the substitutes form an incomplete closure, then we should
|
/* If the substitutes form an incomplete closure, then we should
|
||||||
|
@ -341,32 +338,29 @@ void DerivationGoal::outputsSubstitutionTried()
|
||||||
|
|
||||||
if (needRestart == NeedRestartForMoreOutputs::OutputsAddedDoNeed) {
|
if (needRestart == NeedRestartForMoreOutputs::OutputsAddedDoNeed) {
|
||||||
needRestart = NeedRestartForMoreOutputs::OutputsUnmodifedDontNeed;
|
needRestart = NeedRestartForMoreOutputs::OutputsUnmodifedDontNeed;
|
||||||
haveDerivation();
|
return haveDerivation();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto [allValid, validOutputs] = checkPathValidity();
|
auto [allValid, validOutputs] = checkPathValidity();
|
||||||
|
|
||||||
if (buildMode == bmNormal && allValid) {
|
if (buildMode == bmNormal && allValid) {
|
||||||
done(BuildResult::Substituted, std::move(validOutputs));
|
return done(BuildResult::Substituted, std::move(validOutputs));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (buildMode == bmRepair && allValid) {
|
if (buildMode == bmRepair && allValid) {
|
||||||
repairClosure();
|
return repairClosure();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (buildMode == bmCheck && !allValid)
|
if (buildMode == bmCheck && !allValid)
|
||||||
throw Error("some outputs of '%s' are not valid, so checking is not possible",
|
throw Error("some outputs of '%s' are not valid, so checking is not possible",
|
||||||
worker.store.printStorePath(drvPath));
|
worker.store.printStorePath(drvPath));
|
||||||
|
|
||||||
/* Nothing to wait for; tail call */
|
/* Nothing to wait for; tail call */
|
||||||
gaveUpOnSubstitution();
|
return gaveUpOnSubstitution();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* 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. */
|
||||||
void DerivationGoal::gaveUpOnSubstitution()
|
Goal::WorkResult DerivationGoal::gaveUpOnSubstitution()
|
||||||
{
|
{
|
||||||
/* At this point we are building all outputs, so if more are wanted there
|
/* At this point we are building all outputs, so if more are wanted there
|
||||||
is no need to restart. */
|
is no need to restart. */
|
||||||
|
@ -427,14 +421,16 @@ void DerivationGoal::gaveUpOnSubstitution()
|
||||||
addWaitee(worker.makePathSubstitutionGoal(i));
|
addWaitee(worker.makePathSubstitutionGoal(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (waitees.empty()) /* to prevent hang (no wake-up event) */
|
if (waitees.empty()) {/* to prevent hang (no wake-up event) */
|
||||||
inputsRealised();
|
return inputsRealised();
|
||||||
else
|
} else {
|
||||||
state = &DerivationGoal::inputsRealised;
|
state = &DerivationGoal::inputsRealised;
|
||||||
|
return StillAlive{};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DerivationGoal::repairClosure()
|
Goal::WorkResult DerivationGoal::repairClosure()
|
||||||
{
|
{
|
||||||
assert(drv->type().isPure());
|
assert(drv->type().isPure());
|
||||||
|
|
||||||
|
@ -488,41 +484,39 @@ void DerivationGoal::repairClosure()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (waitees.empty()) {
|
if (waitees.empty()) {
|
||||||
done(BuildResult::AlreadyValid, assertPathValidity());
|
return done(BuildResult::AlreadyValid, assertPathValidity());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state = &DerivationGoal::closureRepaired;
|
state = &DerivationGoal::closureRepaired;
|
||||||
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DerivationGoal::closureRepaired()
|
Goal::WorkResult DerivationGoal::closureRepaired()
|
||||||
{
|
{
|
||||||
trace("closure repaired");
|
trace("closure repaired");
|
||||||
if (nrFailed > 0)
|
if (nrFailed > 0)
|
||||||
throw Error("some paths in the output closure of derivation '%s' could not be repaired",
|
throw Error("some paths in the output closure of derivation '%s' could not be repaired",
|
||||||
worker.store.printStorePath(drvPath));
|
worker.store.printStorePath(drvPath));
|
||||||
done(BuildResult::AlreadyValid, assertPathValidity());
|
return done(BuildResult::AlreadyValid, assertPathValidity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DerivationGoal::inputsRealised()
|
Goal::WorkResult DerivationGoal::inputsRealised()
|
||||||
{
|
{
|
||||||
trace("all inputs realised");
|
trace("all inputs realised");
|
||||||
|
|
||||||
if (nrFailed != 0) {
|
if (nrFailed != 0) {
|
||||||
if (!useDerivation)
|
if (!useDerivation)
|
||||||
throw Error("some dependencies of '%s' are missing", worker.store.printStorePath(drvPath));
|
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",
|
"%s dependencies of derivation '%s' failed to build",
|
||||||
nrFailed, worker.store.printStorePath(drvPath)));
|
nrFailed, worker.store.printStorePath(drvPath)));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retrySubstitution == RetrySubstitution::YesNeed) {
|
if (retrySubstitution == RetrySubstitution::YesNeed) {
|
||||||
retrySubstitution = RetrySubstitution::AlreadyRetried;
|
retrySubstitution = RetrySubstitution::AlreadyRetried;
|
||||||
haveDerivation();
|
return haveDerivation();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Gather information necessary for computing the closure and/or
|
/* Gather information necessary for computing the closure and/or
|
||||||
|
@ -589,7 +583,7 @@ void DerivationGoal::inputsRealised()
|
||||||
addWaitee(resolvedDrvGoal);
|
addWaitee(resolvedDrvGoal);
|
||||||
|
|
||||||
state = &DerivationGoal::resolvedFinished;
|
state = &DerivationGoal::resolvedFinished;
|
||||||
return;
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::function<void(const StorePath &, const DerivedPathMap<StringSet>::ChildNode &)> accumInputPaths;
|
std::function<void(const StorePath &, const DerivedPathMap<StringSet>::ChildNode &)> accumInputPaths;
|
||||||
|
@ -655,9 +649,10 @@ void DerivationGoal::inputsRealised()
|
||||||
build hook. */
|
build hook. */
|
||||||
state = &DerivationGoal::tryToBuild;
|
state = &DerivationGoal::tryToBuild;
|
||||||
worker.wakeUp(shared_from_this());
|
worker.wakeUp(shared_from_this());
|
||||||
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
void DerivationGoal::started()
|
Goal::WorkResult DerivationGoal::started()
|
||||||
{
|
{
|
||||||
auto msg = fmt(
|
auto msg = fmt(
|
||||||
buildMode == bmRepair ? "repairing outputs of '%s'" :
|
buildMode == bmRepair ? "repairing outputs of '%s'" :
|
||||||
|
@ -668,9 +663,10 @@ void DerivationGoal::started()
|
||||||
act = std::make_unique<Activity>(*logger, lvlInfo, actBuild, msg,
|
act = std::make_unique<Activity>(*logger, lvlInfo, actBuild, msg,
|
||||||
Logger::Fields{worker.store.printStorePath(drvPath), hook ? machineName : "", 1, 1});
|
Logger::Fields{worker.store.printStorePath(drvPath), hook ? machineName : "", 1, 1});
|
||||||
mcRunningBuilds = std::make_unique<MaintainCount<uint64_t>>(worker.runningBuilds);
|
mcRunningBuilds = std::make_unique<MaintainCount<uint64_t>>(worker.runningBuilds);
|
||||||
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
void DerivationGoal::tryToBuild()
|
Goal::WorkResult DerivationGoal::tryToBuild()
|
||||||
{
|
{
|
||||||
trace("trying to build");
|
trace("trying to build");
|
||||||
|
|
||||||
|
@ -706,7 +702,7 @@ void DerivationGoal::tryToBuild()
|
||||||
actLock = std::make_unique<Activity>(*logger, lvlWarn, actBuildWaiting,
|
actLock = std::make_unique<Activity>(*logger, lvlWarn, actBuildWaiting,
|
||||||
fmt("waiting for lock on %s", Magenta(showPaths(lockFiles))));
|
fmt("waiting for lock on %s", Magenta(showPaths(lockFiles))));
|
||||||
worker.waitForAWhile(shared_from_this());
|
worker.waitForAWhile(shared_from_this());
|
||||||
return;
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
actLock.reset();
|
actLock.reset();
|
||||||
|
@ -723,8 +719,7 @@ void DerivationGoal::tryToBuild()
|
||||||
if (buildMode != bmCheck && allValid) {
|
if (buildMode != bmCheck && allValid) {
|
||||||
debug("skipping build of derivation '%s', someone beat us to it", worker.store.printStorePath(drvPath));
|
debug("skipping build of derivation '%s', someone beat us to it", worker.store.printStorePath(drvPath));
|
||||||
outputLocks.setDeletion(true);
|
outputLocks.setDeletion(true);
|
||||||
done(BuildResult::AlreadyValid, std::move(validOutputs));
|
return done(BuildResult::AlreadyValid, std::move(validOutputs));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If any of the outputs already exist but are not valid, delete
|
/* If any of the outputs already exist but are not valid, delete
|
||||||
|
@ -751,8 +746,7 @@ void DerivationGoal::tryToBuild()
|
||||||
actLock.reset();
|
actLock.reset();
|
||||||
buildResult.startTime = time(0); // inexact
|
buildResult.startTime = time(0); // inexact
|
||||||
state = &DerivationGoal::buildDone;
|
state = &DerivationGoal::buildDone;
|
||||||
started();
|
return started();
|
||||||
return;
|
|
||||||
case rpPostpone:
|
case rpPostpone:
|
||||||
/* Not now; wait until at least one child finishes or
|
/* Not now; wait until at least one child finishes or
|
||||||
the wake-up timeout expires. */
|
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))));
|
fmt("waiting for a machine to build '%s'", Magenta(worker.store.printStorePath(drvPath))));
|
||||||
worker.waitForAWhile(shared_from_this());
|
worker.waitForAWhile(shared_from_this());
|
||||||
outputLocks.unlock();
|
outputLocks.unlock();
|
||||||
return;
|
return StillAlive{};
|
||||||
case rpDecline:
|
case rpDecline:
|
||||||
/* We should do it ourselves. */
|
/* We should do it ourselves. */
|
||||||
break;
|
break;
|
||||||
|
@ -772,9 +766,10 @@ void DerivationGoal::tryToBuild()
|
||||||
|
|
||||||
state = &DerivationGoal::tryLocalBuild;
|
state = &DerivationGoal::tryLocalBuild;
|
||||||
worker.wakeUp(shared_from_this());
|
worker.wakeUp(shared_from_this());
|
||||||
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
void DerivationGoal::tryLocalBuild() {
|
Goal::WorkResult DerivationGoal::tryLocalBuild() {
|
||||||
throw Error(
|
throw Error(
|
||||||
"unable to build with a primary store that isn't a local store; "
|
"unable to build with a primary store that isn't a local store; "
|
||||||
"either pass a different '--store' or enable remote builds."
|
"either pass a different '--store' or enable remote builds."
|
||||||
|
@ -932,7 +927,7 @@ void runPostBuildHook(
|
||||||
proc.getStdout()->drainInto(sink);
|
proc.getStdout()->drainInto(sink);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DerivationGoal::buildDone()
|
Goal::WorkResult DerivationGoal::buildDone()
|
||||||
{
|
{
|
||||||
trace("build done");
|
trace("build done");
|
||||||
|
|
||||||
|
@ -1027,8 +1022,7 @@ void DerivationGoal::buildDone()
|
||||||
outputLocks.setDeletion(true);
|
outputLocks.setDeletion(true);
|
||||||
outputLocks.unlock();
|
outputLocks.unlock();
|
||||||
|
|
||||||
done(BuildResult::Built, std::move(builtOutputs));
|
return done(BuildResult::Built, std::move(builtOutputs));
|
||||||
|
|
||||||
} catch (BuildError & e) {
|
} catch (BuildError & e) {
|
||||||
outputLocks.unlock();
|
outputLocks.unlock();
|
||||||
|
|
||||||
|
@ -1049,12 +1043,11 @@ void DerivationGoal::buildDone()
|
||||||
BuildResult::PermanentFailure;
|
BuildResult::PermanentFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
done(st, {}, std::move(e));
|
return done(st, {}, std::move(e));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DerivationGoal::resolvedFinished()
|
Goal::WorkResult DerivationGoal::resolvedFinished()
|
||||||
{
|
{
|
||||||
trace("resolved derivation finished");
|
trace("resolved derivation finished");
|
||||||
|
|
||||||
|
@ -1122,7 +1115,7 @@ void DerivationGoal::resolvedFinished()
|
||||||
if (status == BuildResult::AlreadyValid)
|
if (status == BuildResult::AlreadyValid)
|
||||||
status = BuildResult::ResolvesToAlreadyValid;
|
status = BuildResult::ResolvesToAlreadyValid;
|
||||||
|
|
||||||
done(status, std::move(builtOutputs));
|
return done(status, std::move(builtOutputs));
|
||||||
}
|
}
|
||||||
|
|
||||||
HookReply DerivationGoal::tryBuildHook()
|
HookReply DerivationGoal::tryBuildHook()
|
||||||
|
@ -1293,7 +1286,7 @@ bool DerivationGoal::isReadDesc(int fd)
|
||||||
return fd == hook->builderOut.readSide.get();
|
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.
|
// local & `ssh://`-builds are dealt with here.
|
||||||
auto isWrittenToLog = isReadDesc(fd);
|
auto isWrittenToLog = isReadDesc(fd);
|
||||||
|
@ -1302,11 +1295,10 @@ void DerivationGoal::handleChildOutput(int fd, std::string_view data)
|
||||||
logSize += data.size();
|
logSize += data.size();
|
||||||
if (settings.maxLogSize && logSize > settings.maxLogSize) {
|
if (settings.maxLogSize && logSize > settings.maxLogSize) {
|
||||||
killChild();
|
killChild();
|
||||||
done(
|
return done(
|
||||||
BuildResult::LogLimitExceeded, {},
|
BuildResult::LogLimitExceeded, {},
|
||||||
Error("%s killed after writing more than %d bytes of log output",
|
Error("%s killed after writing more than %d bytes of log output",
|
||||||
getName(), settings.maxLogSize));
|
getName(), settings.maxLogSize));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto c : data)
|
for (auto c : data)
|
||||||
|
@ -1357,6 +1349,8 @@ void DerivationGoal::handleChildOutput(int fd, std::string_view data)
|
||||||
} else
|
} else
|
||||||
currentHookLine += c;
|
currentHookLine += c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1505,7 +1499,7 @@ SingleDrvOutputs DerivationGoal::assertPathValidity()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DerivationGoal::done(
|
Goal::Finished DerivationGoal::done(
|
||||||
BuildResult::Status status,
|
BuildResult::Status status,
|
||||||
SingleDrvOutputs builtOutputs,
|
SingleDrvOutputs builtOutputs,
|
||||||
std::optional<Error> ex)
|
std::optional<Error> ex)
|
||||||
|
@ -1540,7 +1534,7 @@ void DerivationGoal::done(
|
||||||
fs << worker.store.printStorePath(drvPath) << "\t" << buildResult.toString() << std::endl;
|
fs << worker.store.printStorePath(drvPath) << "\t" << buildResult.toString() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
amDone(buildResult.success() ? ecSuccess : ecFailed, std::move(ex));
|
return amDone(buildResult.success() ? ecSuccess : ecFailed, std::move(ex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -188,7 +188,7 @@ struct DerivationGoal : public Goal
|
||||||
*/
|
*/
|
||||||
std::optional<DerivationType> derivationType;
|
std::optional<DerivationType> derivationType;
|
||||||
|
|
||||||
typedef void (DerivationGoal::*GoalState)();
|
typedef WorkResult (DerivationGoal::*GoalState)();
|
||||||
GoalState state;
|
GoalState state;
|
||||||
|
|
||||||
BuildMode buildMode;
|
BuildMode buildMode;
|
||||||
|
@ -217,11 +217,11 @@ struct DerivationGoal : public Goal
|
||||||
BuildMode buildMode = bmNormal);
|
BuildMode buildMode = bmNormal);
|
||||||
virtual ~DerivationGoal() noexcept(false);
|
virtual ~DerivationGoal() noexcept(false);
|
||||||
|
|
||||||
void timedOut(Error && ex) override;
|
Finished timedOut(Error && ex) override;
|
||||||
|
|
||||||
std::string key() override;
|
std::string key() override;
|
||||||
|
|
||||||
void work() override;
|
WorkResult work() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add wanted outputs to an already existing derivation goal.
|
* Add wanted outputs to an already existing derivation goal.
|
||||||
|
@ -231,18 +231,18 @@ struct DerivationGoal : public Goal
|
||||||
/**
|
/**
|
||||||
* The states.
|
* The states.
|
||||||
*/
|
*/
|
||||||
void getDerivation();
|
WorkResult getDerivation();
|
||||||
void loadDerivation();
|
WorkResult loadDerivation();
|
||||||
void haveDerivation();
|
WorkResult haveDerivation();
|
||||||
void outputsSubstitutionTried();
|
WorkResult outputsSubstitutionTried();
|
||||||
void gaveUpOnSubstitution();
|
WorkResult gaveUpOnSubstitution();
|
||||||
void closureRepaired();
|
WorkResult closureRepaired();
|
||||||
void inputsRealised();
|
WorkResult inputsRealised();
|
||||||
void tryToBuild();
|
WorkResult tryToBuild();
|
||||||
virtual void tryLocalBuild();
|
virtual WorkResult tryLocalBuild();
|
||||||
void buildDone();
|
WorkResult buildDone();
|
||||||
|
|
||||||
void resolvedFinished();
|
WorkResult resolvedFinished();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the build hook willing to perform the build?
|
* Is the build hook willing to perform the build?
|
||||||
|
@ -292,7 +292,7 @@ struct DerivationGoal : public Goal
|
||||||
/**
|
/**
|
||||||
* Callback used by the worker to write to the log.
|
* Callback used by the worker to write to the log.
|
||||||
*/
|
*/
|
||||||
void handleChildOutput(int fd, std::string_view data) override;
|
WorkResult handleChildOutput(int fd, std::string_view data) override;
|
||||||
void handleEOF(int fd) override;
|
void handleEOF(int fd) override;
|
||||||
void flushLine();
|
void flushLine();
|
||||||
|
|
||||||
|
@ -323,11 +323,11 @@ struct DerivationGoal : public Goal
|
||||||
*/
|
*/
|
||||||
virtual void killChild();
|
virtual void killChild();
|
||||||
|
|
||||||
void repairClosure();
|
WorkResult repairClosure();
|
||||||
|
|
||||||
void started();
|
WorkResult started();
|
||||||
|
|
||||||
void done(
|
Finished done(
|
||||||
BuildResult::Status status,
|
BuildResult::Status status,
|
||||||
SingleDrvOutputs builtOutputs = {},
|
SingleDrvOutputs builtOutputs = {},
|
||||||
std::optional<Error> ex = {});
|
std::optional<Error> ex = {});
|
||||||
|
|
|
@ -20,21 +20,20 @@ DrvOutputSubstitutionGoal::DrvOutputSubstitutionGoal(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DrvOutputSubstitutionGoal::init()
|
Goal::WorkResult DrvOutputSubstitutionGoal::init()
|
||||||
{
|
{
|
||||||
trace("init");
|
trace("init");
|
||||||
|
|
||||||
/* If the derivation already exists, we’re done */
|
/* If the derivation already exists, we’re done */
|
||||||
if (worker.store.queryRealisation(id)) {
|
if (worker.store.queryRealisation(id)) {
|
||||||
amDone(ecSuccess);
|
return amDone(ecSuccess);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
|
subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
|
||||||
tryNext();
|
return tryNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrvOutputSubstitutionGoal::tryNext()
|
Goal::WorkResult DrvOutputSubstitutionGoal::tryNext()
|
||||||
{
|
{
|
||||||
trace("trying next substituter");
|
trace("trying next substituter");
|
||||||
|
|
||||||
|
@ -43,7 +42,7 @@ void DrvOutputSubstitutionGoal::tryNext()
|
||||||
prevents infinite waiting. */
|
prevents infinite waiting. */
|
||||||
if (worker.runningSubstitutions >= std::max(1U, settings.maxSubstitutionJobs.get())) {
|
if (worker.runningSubstitutions >= std::max(1U, settings.maxSubstitutionJobs.get())) {
|
||||||
worker.waitForBuildSlot(shared_from_this());
|
worker.waitForBuildSlot(shared_from_this());
|
||||||
return;
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
maintainRunningSubstitutions =
|
maintainRunningSubstitutions =
|
||||||
|
@ -54,16 +53,14 @@ void DrvOutputSubstitutionGoal::tryNext()
|
||||||
with it. */
|
with it. */
|
||||||
debug("derivation 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
|
|
||||||
build. */
|
|
||||||
amDone(substituterFailed ? ecFailed : ecNoSubstituters);
|
|
||||||
|
|
||||||
if (substituterFailed) {
|
if (substituterFailed) {
|
||||||
worker.failedSubstitutions++;
|
worker.failedSubstitutions++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
/* Hack: don't indicate failure if there were no substituters.
|
||||||
|
In that case the calling derivation should just do a
|
||||||
|
build. */
|
||||||
|
return amDone(substituterFailed ? ecFailed : ecNoSubstituters);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub = subs.front();
|
sub = subs.front();
|
||||||
|
@ -85,9 +82,10 @@ void DrvOutputSubstitutionGoal::tryNext()
|
||||||
worker.childStarted(shared_from_this(), {downloadState->outPipe.readSide.get()}, true, false);
|
worker.childStarted(shared_from_this(), {downloadState->outPipe.readSide.get()}, true, false);
|
||||||
|
|
||||||
state = &DrvOutputSubstitutionGoal::realisationFetched;
|
state = &DrvOutputSubstitutionGoal::realisationFetched;
|
||||||
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrvOutputSubstitutionGoal::realisationFetched()
|
Goal::WorkResult DrvOutputSubstitutionGoal::realisationFetched()
|
||||||
{
|
{
|
||||||
worker.childTerminated(this);
|
worker.childTerminated(this);
|
||||||
maintainRunningSubstitutions.reset();
|
maintainRunningSubstitutions.reset();
|
||||||
|
@ -116,8 +114,7 @@ void DrvOutputSubstitutionGoal::realisationFetched()
|
||||||
worker.store.printStorePath(localOutputInfo->outPath),
|
worker.store.printStorePath(localOutputInfo->outPath),
|
||||||
worker.store.printStorePath(depPath)
|
worker.store.printStorePath(depPath)
|
||||||
);
|
);
|
||||||
tryNext();
|
return tryNext();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
addWaitee(worker.makeDrvOutputSubstitutionGoal(depId));
|
addWaitee(worker.makeDrvOutputSubstitutionGoal(depId));
|
||||||
}
|
}
|
||||||
|
@ -125,29 +122,32 @@ void DrvOutputSubstitutionGoal::realisationFetched()
|
||||||
|
|
||||||
addWaitee(worker.makePathSubstitutionGoal(outputInfo->outPath));
|
addWaitee(worker.makePathSubstitutionGoal(outputInfo->outPath));
|
||||||
|
|
||||||
if (waitees.empty()) outPathValid();
|
if (waitees.empty()) {
|
||||||
else state = &DrvOutputSubstitutionGoal::outPathValid;
|
return outPathValid();
|
||||||
|
} else {
|
||||||
|
state = &DrvOutputSubstitutionGoal::outPathValid;
|
||||||
|
return StillAlive{};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrvOutputSubstitutionGoal::outPathValid()
|
Goal::WorkResult DrvOutputSubstitutionGoal::outPathValid()
|
||||||
{
|
{
|
||||||
assert(outputInfo);
|
assert(outputInfo);
|
||||||
trace("output path substituted");
|
trace("output path substituted");
|
||||||
|
|
||||||
if (nrFailed > 0) {
|
if (nrFailed > 0) {
|
||||||
debug("The output path of the derivation output '%s' could not be substituted", id.to_string());
|
debug("The output path of the derivation output '%s' could not be substituted", id.to_string());
|
||||||
amDone(nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed);
|
return amDone(nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
worker.store.registerDrvOutput(*outputInfo);
|
worker.store.registerDrvOutput(*outputInfo);
|
||||||
finished();
|
return finished();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrvOutputSubstitutionGoal::finished()
|
Goal::WorkResult DrvOutputSubstitutionGoal::finished()
|
||||||
{
|
{
|
||||||
trace("finished");
|
trace("finished");
|
||||||
amDone(ecSuccess);
|
return amDone(ecSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DrvOutputSubstitutionGoal::key()
|
std::string DrvOutputSubstitutionGoal::key()
|
||||||
|
@ -157,9 +157,9 @@ std::string DrvOutputSubstitutionGoal::key()
|
||||||
return "a$" + std::string(id.to_string());
|
return "a$" + std::string(id.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrvOutputSubstitutionGoal::work()
|
Goal::WorkResult DrvOutputSubstitutionGoal::work()
|
||||||
{
|
{
|
||||||
(this->*state)();
|
return (this->*state)();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -58,20 +58,20 @@ class DrvOutputSubstitutionGoal : public Goal {
|
||||||
public:
|
public:
|
||||||
DrvOutputSubstitutionGoal(const DrvOutput& id, Worker & worker, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
|
DrvOutputSubstitutionGoal(const DrvOutput& id, Worker & worker, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
|
||||||
|
|
||||||
typedef void (DrvOutputSubstitutionGoal::*GoalState)();
|
typedef WorkResult (DrvOutputSubstitutionGoal::*GoalState)();
|
||||||
GoalState state;
|
GoalState state;
|
||||||
|
|
||||||
void init();
|
WorkResult init();
|
||||||
void tryNext();
|
WorkResult tryNext();
|
||||||
void realisationFetched();
|
WorkResult realisationFetched();
|
||||||
void outPathValid();
|
WorkResult outPathValid();
|
||||||
void finished();
|
WorkResult finished();
|
||||||
|
|
||||||
void timedOut(Error && ex) override { abort(); };
|
Finished timedOut(Error && ex) override { abort(); };
|
||||||
|
|
||||||
std::string key() override;
|
std::string key() override;
|
||||||
|
|
||||||
void work() override;
|
WorkResult work() override;
|
||||||
|
|
||||||
JobCategory jobCategory() const override {
|
JobCategory jobCategory() const override {
|
||||||
return JobCategory::Substitution;
|
return JobCategory::Substitution;
|
||||||
|
|
|
@ -45,7 +45,7 @@ void Goal::waiteeDone(GoalPtr waitee, ExitCode result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Goal::amDone(ExitCode result, std::optional<Error> ex)
|
Goal::Finished Goal::amDone(ExitCode result, std::optional<Error> ex)
|
||||||
{
|
{
|
||||||
trace("done");
|
trace("done");
|
||||||
assert(!exitCode.has_value());
|
assert(!exitCode.has_value());
|
||||||
|
@ -66,6 +66,7 @@ void Goal::amDone(ExitCode result, std::optional<Error> ex)
|
||||||
worker.removeGoal(shared_from_this());
|
worker.removeGoal(shared_from_this());
|
||||||
|
|
||||||
cleanup();
|
cleanup();
|
||||||
|
return Finished{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,15 @@ struct Goal : public std::enable_shared_from_this<Goal>
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
struct StillAlive {};
|
||||||
|
struct Finished {};
|
||||||
|
|
||||||
|
struct WorkResult : std::variant<StillAlive, Finished>
|
||||||
|
{
|
||||||
|
WorkResult() = delete;
|
||||||
|
using variant::variant;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception containing an error message, if any.
|
* Exception containing an error message, if any.
|
||||||
*/
|
*/
|
||||||
|
@ -119,13 +128,13 @@ public:
|
||||||
trace("goal destroyed");
|
trace("goal destroyed");
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void work() = 0;
|
virtual WorkResult work() = 0;
|
||||||
|
|
||||||
void addWaitee(GoalPtr waitee);
|
void addWaitee(GoalPtr waitee);
|
||||||
|
|
||||||
virtual void waiteeDone(GoalPtr waitee, ExitCode result);
|
virtual void waiteeDone(GoalPtr waitee, ExitCode result);
|
||||||
|
|
||||||
virtual void handleChildOutput(int fd, std::string_view data)
|
virtual WorkResult handleChildOutput(int fd, std::string_view data)
|
||||||
{
|
{
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
@ -146,11 +155,11 @@ public:
|
||||||
* get rid of any running child processes that are being monitored
|
* get rid of any running child processes that are being monitored
|
||||||
* by the worker (important!), etc.
|
* by the worker (important!), etc.
|
||||||
*/
|
*/
|
||||||
virtual void timedOut(Error && ex) = 0;
|
virtual Finished timedOut(Error && ex) = 0;
|
||||||
|
|
||||||
virtual std::string key() = 0;
|
virtual std::string key() = 0;
|
||||||
|
|
||||||
void amDone(ExitCode result, std::optional<Error> ex = {});
|
Finished amDone(ExitCode result, std::optional<Error> ex = {});
|
||||||
|
|
||||||
virtual void cleanup() { }
|
virtual void cleanup() { }
|
||||||
|
|
||||||
|
|
|
@ -161,7 +161,7 @@ void LocalDerivationGoal::killSandbox(bool getStats)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LocalDerivationGoal::tryLocalBuild()
|
Goal::WorkResult LocalDerivationGoal::tryLocalBuild()
|
||||||
{
|
{
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
additionalSandboxProfile = parsedDrv->getStringAttr("__sandboxProfile").value_or("");
|
additionalSandboxProfile = parsedDrv->getStringAttr("__sandboxProfile").value_or("");
|
||||||
|
@ -172,7 +172,7 @@ void LocalDerivationGoal::tryLocalBuild()
|
||||||
state = &DerivationGoal::tryToBuild;
|
state = &DerivationGoal::tryToBuild;
|
||||||
worker.waitForBuildSlot(shared_from_this());
|
worker.waitForBuildSlot(shared_from_this());
|
||||||
outputLocks.unlock();
|
outputLocks.unlock();
|
||||||
return;
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(derivationType);
|
assert(derivationType);
|
||||||
|
@ -215,7 +215,7 @@ void LocalDerivationGoal::tryLocalBuild()
|
||||||
actLock = std::make_unique<Activity>(*logger, lvlWarn, actBuildWaiting,
|
actLock = std::make_unique<Activity>(*logger, lvlWarn, actBuildWaiting,
|
||||||
fmt("waiting for a free build user ID for '%s'", Magenta(worker.store.printStorePath(drvPath))));
|
fmt("waiting for a free build user ID for '%s'", Magenta(worker.store.printStorePath(drvPath))));
|
||||||
worker.waitForAWhile(shared_from_this());
|
worker.waitForAWhile(shared_from_this());
|
||||||
return;
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,15 +250,14 @@ void LocalDerivationGoal::tryLocalBuild()
|
||||||
outputLocks.unlock();
|
outputLocks.unlock();
|
||||||
buildUser.reset();
|
buildUser.reset();
|
||||||
worker.permanentFailure = true;
|
worker.permanentFailure = true;
|
||||||
done(BuildResult::InputRejected, {}, std::move(e));
|
return done(BuildResult::InputRejected, {}, std::move(e));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This state will be reached when we get EOF on the child's
|
/* This state will be reached when we get EOF on the child's
|
||||||
log pipe. */
|
log pipe. */
|
||||||
state = &DerivationGoal::buildDone;
|
state = &DerivationGoal::buildDone;
|
||||||
|
|
||||||
started();
|
return started();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -211,7 +211,7 @@ struct LocalDerivationGoal : public DerivationGoal
|
||||||
/**
|
/**
|
||||||
* The additional states.
|
* The additional states.
|
||||||
*/
|
*/
|
||||||
void tryLocalBuild() override;
|
WorkResult tryLocalBuild() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start building a derivation.
|
* Start building a derivation.
|
||||||
|
|
|
@ -25,7 +25,7 @@ PathSubstitutionGoal::~PathSubstitutionGoal()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PathSubstitutionGoal::done(
|
Goal::Finished PathSubstitutionGoal::done(
|
||||||
ExitCode result,
|
ExitCode result,
|
||||||
BuildResult::Status status,
|
BuildResult::Status status,
|
||||||
std::optional<std::string> errorMsg)
|
std::optional<std::string> errorMsg)
|
||||||
|
@ -35,17 +35,17 @@ void PathSubstitutionGoal::done(
|
||||||
debug(*errorMsg);
|
debug(*errorMsg);
|
||||||
buildResult.errorMsg = *errorMsg;
|
buildResult.errorMsg = *errorMsg;
|
||||||
}
|
}
|
||||||
amDone(result);
|
return amDone(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PathSubstitutionGoal::work()
|
Goal::WorkResult PathSubstitutionGoal::work()
|
||||||
{
|
{
|
||||||
(this->*state)();
|
return (this->*state)();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PathSubstitutionGoal::init()
|
Goal::WorkResult PathSubstitutionGoal::init()
|
||||||
{
|
{
|
||||||
trace("init");
|
trace("init");
|
||||||
|
|
||||||
|
@ -53,8 +53,7 @@ void PathSubstitutionGoal::init()
|
||||||
|
|
||||||
/* If the path already exists we're done. */
|
/* If the path already exists we're done. */
|
||||||
if (!repair && worker.store.isValidPath(storePath)) {
|
if (!repair && worker.store.isValidPath(storePath)) {
|
||||||
done(ecSuccess, BuildResult::AlreadyValid);
|
return done(ecSuccess, BuildResult::AlreadyValid);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.readOnlyMode)
|
if (settings.readOnlyMode)
|
||||||
|
@ -62,11 +61,11 @@ void PathSubstitutionGoal::init()
|
||||||
|
|
||||||
subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
|
subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
|
||||||
|
|
||||||
tryNext();
|
return tryNext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PathSubstitutionGoal::tryNext()
|
Goal::WorkResult PathSubstitutionGoal::tryNext()
|
||||||
{
|
{
|
||||||
trace("trying next substituter");
|
trace("trying next substituter");
|
||||||
|
|
||||||
|
@ -75,20 +74,17 @@ void PathSubstitutionGoal::tryNext()
|
||||||
if (subs.size() == 0) {
|
if (subs.size() == 0) {
|
||||||
/* None left. Terminate this goal and let someone else deal
|
/* None left. Terminate this goal and let someone else deal
|
||||||
with it. */
|
with it. */
|
||||||
|
|
||||||
/* 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,
|
|
||||||
fmt("path '%s' is required, but there is no substituter that can build it", worker.store.printStorePath(storePath)));
|
|
||||||
|
|
||||||
if (substituterFailed) {
|
if (substituterFailed) {
|
||||||
worker.failedSubstitutions++;
|
worker.failedSubstitutions++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
/* Hack: don't indicate failure if there were no substituters.
|
||||||
|
In that case the calling derivation should just do a
|
||||||
|
build. */
|
||||||
|
return done(
|
||||||
|
substituterFailed ? ecFailed : ecNoSubstituters,
|
||||||
|
BuildResult::NoSubstituters,
|
||||||
|
fmt("path '%s' is required, but there is no substituter that can build it", worker.store.printStorePath(storePath)));
|
||||||
}
|
}
|
||||||
|
|
||||||
sub = subs.front();
|
sub = subs.front();
|
||||||
|
@ -101,27 +97,23 @@ void PathSubstitutionGoal::tryNext()
|
||||||
if (sub->storeDir == worker.store.storeDir)
|
if (sub->storeDir == worker.store.storeDir)
|
||||||
assert(subPath == storePath);
|
assert(subPath == storePath);
|
||||||
} else if (sub->storeDir != worker.store.storeDir) {
|
} else if (sub->storeDir != worker.store.storeDir) {
|
||||||
tryNext();
|
return tryNext();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// FIXME: make async
|
// FIXME: make async
|
||||||
info = sub->queryPathInfo(subPath ? *subPath : storePath);
|
info = sub->queryPathInfo(subPath ? *subPath : storePath);
|
||||||
} catch (InvalidPath &) {
|
} catch (InvalidPath &) {
|
||||||
tryNext();
|
return tryNext();
|
||||||
return;
|
|
||||||
} catch (SubstituterDisabled &) {
|
} catch (SubstituterDisabled &) {
|
||||||
if (settings.tryFallback) {
|
if (settings.tryFallback) {
|
||||||
tryNext();
|
return tryNext();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
throw;
|
throw;
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
if (settings.tryFallback) {
|
if (settings.tryFallback) {
|
||||||
logError(e.info());
|
logError(e.info());
|
||||||
tryNext();
|
return tryNext();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -134,8 +126,7 @@ void PathSubstitutionGoal::tryNext()
|
||||||
} else {
|
} else {
|
||||||
printError("asked '%s' for '%s' but got '%s'",
|
printError("asked '%s' for '%s' but got '%s'",
|
||||||
sub->getUri(), worker.store.printStorePath(storePath), sub->printStorePath(info->path));
|
sub->getUri(), worker.store.printStorePath(storePath), sub->printStorePath(info->path));
|
||||||
tryNext();
|
return tryNext();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,8 +147,7 @@ void PathSubstitutionGoal::tryNext()
|
||||||
{
|
{
|
||||||
warn("ignoring substitute for '%s' from '%s', as it's not signed by any of the keys in 'trusted-public-keys'",
|
warn("ignoring substitute for '%s' from '%s', as it's not signed by any of the keys in 'trusted-public-keys'",
|
||||||
worker.store.printStorePath(storePath), sub->getUri());
|
worker.store.printStorePath(storePath), sub->getUri());
|
||||||
tryNext();
|
return tryNext();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* To maintain the closure invariant, we first have to realise the
|
/* To maintain the closure invariant, we first have to realise the
|
||||||
|
@ -166,23 +156,24 @@ void PathSubstitutionGoal::tryNext()
|
||||||
if (i != storePath) /* ignore self-references */
|
if (i != storePath) /* ignore self-references */
|
||||||
addWaitee(worker.makePathSubstitutionGoal(i));
|
addWaitee(worker.makePathSubstitutionGoal(i));
|
||||||
|
|
||||||
if (waitees.empty()) /* to prevent hang (no wake-up event) */
|
if (waitees.empty()) {/* to prevent hang (no wake-up event) */
|
||||||
referencesValid();
|
return referencesValid();
|
||||||
else
|
} else {
|
||||||
state = &PathSubstitutionGoal::referencesValid;
|
state = &PathSubstitutionGoal::referencesValid;
|
||||||
|
return StillAlive{};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PathSubstitutionGoal::referencesValid()
|
Goal::WorkResult PathSubstitutionGoal::referencesValid()
|
||||||
{
|
{
|
||||||
trace("all references realised");
|
trace("all references realised");
|
||||||
|
|
||||||
if (nrFailed > 0) {
|
if (nrFailed > 0) {
|
||||||
done(
|
return done(
|
||||||
nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed,
|
nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed,
|
||||||
BuildResult::DependencyFailed,
|
BuildResult::DependencyFailed,
|
||||||
fmt("some references of path '%s' could not be realised", worker.store.printStorePath(storePath)));
|
fmt("some references of path '%s' could not be realised", worker.store.printStorePath(storePath)));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto & i : info->references)
|
for (auto & i : info->references)
|
||||||
|
@ -191,10 +182,11 @@ void PathSubstitutionGoal::referencesValid()
|
||||||
|
|
||||||
state = &PathSubstitutionGoal::tryToRun;
|
state = &PathSubstitutionGoal::tryToRun;
|
||||||
worker.wakeUp(shared_from_this());
|
worker.wakeUp(shared_from_this());
|
||||||
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PathSubstitutionGoal::tryToRun()
|
Goal::WorkResult PathSubstitutionGoal::tryToRun()
|
||||||
{
|
{
|
||||||
trace("trying to run");
|
trace("trying to run");
|
||||||
|
|
||||||
|
@ -203,7 +195,7 @@ void PathSubstitutionGoal::tryToRun()
|
||||||
prevents infinite waiting. */
|
prevents infinite waiting. */
|
||||||
if (worker.getNrSubstitutions() >= std::max(1U, (unsigned int) settings.maxSubstitutionJobs)) {
|
if (worker.getNrSubstitutions() >= std::max(1U, (unsigned int) settings.maxSubstitutionJobs)) {
|
||||||
worker.waitForBuildSlot(shared_from_this());
|
worker.waitForBuildSlot(shared_from_this());
|
||||||
return;
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
maintainRunningSubstitutions = std::make_unique<MaintainCount<uint64_t>>(worker.runningSubstitutions);
|
maintainRunningSubstitutions = std::make_unique<MaintainCount<uint64_t>>(worker.runningSubstitutions);
|
||||||
|
@ -236,10 +228,11 @@ void PathSubstitutionGoal::tryToRun()
|
||||||
worker.childStarted(shared_from_this(), {outPipe.readSide.get()}, true, false);
|
worker.childStarted(shared_from_this(), {outPipe.readSide.get()}, true, false);
|
||||||
|
|
||||||
state = &PathSubstitutionGoal::finished;
|
state = &PathSubstitutionGoal::finished;
|
||||||
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PathSubstitutionGoal::finished()
|
Goal::WorkResult PathSubstitutionGoal::finished()
|
||||||
{
|
{
|
||||||
trace("substitute finished");
|
trace("substitute finished");
|
||||||
|
|
||||||
|
@ -264,7 +257,7 @@ void PathSubstitutionGoal::finished()
|
||||||
/* Try the next substitute. */
|
/* Try the next substitute. */
|
||||||
state = &PathSubstitutionGoal::tryNext;
|
state = &PathSubstitutionGoal::tryNext;
|
||||||
worker.wakeUp(shared_from_this());
|
worker.wakeUp(shared_from_this());
|
||||||
return;
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
worker.markContentsGood(storePath);
|
worker.markContentsGood(storePath);
|
||||||
|
@ -285,12 +278,13 @@ void PathSubstitutionGoal::finished()
|
||||||
worker.doneNarSize += maintainExpectedNar->delta;
|
worker.doneNarSize += maintainExpectedNar->delta;
|
||||||
maintainExpectedNar.reset();
|
maintainExpectedNar.reset();
|
||||||
|
|
||||||
done(ecSuccess, BuildResult::Substituted);
|
return done(ecSuccess, BuildResult::Substituted);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void PathSubstitutionGoal::handleChildOutput(int fd, std::string_view data)
|
Goal::WorkResult PathSubstitutionGoal::handleChildOutput(int fd, std::string_view data)
|
||||||
{
|
{
|
||||||
|
return StillAlive{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ struct PathSubstitutionGoal : public Goal
|
||||||
std::unique_ptr<MaintainCount<uint64_t>> maintainExpectedSubstitutions,
|
std::unique_ptr<MaintainCount<uint64_t>> maintainExpectedSubstitutions,
|
||||||
maintainRunningSubstitutions, maintainExpectedNar, maintainExpectedDownload;
|
maintainRunningSubstitutions, maintainExpectedNar, maintainExpectedDownload;
|
||||||
|
|
||||||
typedef void (PathSubstitutionGoal::*GoalState)();
|
typedef WorkResult (PathSubstitutionGoal::*GoalState)();
|
||||||
GoalState state;
|
GoalState state;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -74,7 +74,7 @@ struct PathSubstitutionGoal : public Goal
|
||||||
*/
|
*/
|
||||||
std::optional<ContentAddress> ca;
|
std::optional<ContentAddress> ca;
|
||||||
|
|
||||||
void done(
|
Finished done(
|
||||||
ExitCode result,
|
ExitCode result,
|
||||||
BuildResult::Status status,
|
BuildResult::Status status,
|
||||||
std::optional<std::string> errorMsg = {});
|
std::optional<std::string> errorMsg = {});
|
||||||
|
@ -83,7 +83,7 @@ public:
|
||||||
PathSubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
|
PathSubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
|
||||||
~PathSubstitutionGoal();
|
~PathSubstitutionGoal();
|
||||||
|
|
||||||
void timedOut(Error && ex) override { abort(); };
|
Finished timedOut(Error && ex) override { abort(); };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* We prepend "a$" to the key name to ensure substitution goals
|
* We prepend "a$" to the key name to ensure substitution goals
|
||||||
|
@ -94,22 +94,22 @@ public:
|
||||||
return "a$" + std::string(storePath.name()) + "$" + worker.store.printStorePath(storePath);
|
return "a$" + std::string(storePath.name()) + "$" + worker.store.printStorePath(storePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void work() override;
|
WorkResult work() override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The states.
|
* The states.
|
||||||
*/
|
*/
|
||||||
void init();
|
WorkResult init();
|
||||||
void tryNext();
|
WorkResult tryNext();
|
||||||
void gotInfo();
|
WorkResult gotInfo();
|
||||||
void referencesValid();
|
WorkResult referencesValid();
|
||||||
void tryToRun();
|
WorkResult tryToRun();
|
||||||
void finished();
|
WorkResult finished();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback used by the worker to write to the log.
|
* Callback used by the worker to write to the log.
|
||||||
*/
|
*/
|
||||||
void handleChildOutput(int fd, std::string_view data) override;
|
WorkResult handleChildOutput(int fd, std::string_view data) override;
|
||||||
|
|
||||||
/* Called by destructor, can't be overridden */
|
/* Called by destructor, can't be overridden */
|
||||||
void cleanup() override final;
|
void cleanup() override final;
|
||||||
|
|
Loading…
Reference in a new issue