2020-10-12 20:08:52 +03:00
|
|
|
#include "worker.hh"
|
|
|
|
#include "substitution-goal.hh"
|
2020-10-11 19:26:10 +03:00
|
|
|
#include "nar-info.hh"
|
|
|
|
#include "finally.hh"
|
2003-08-20 14:30:45 +03:00
|
|
|
|
2020-10-11 19:26:10 +03:00
|
|
|
namespace nix {
|
2004-06-18 21:09:32 +03:00
|
|
|
|
2020-11-09 14:47:06 +02:00
|
|
|
PathSubstitutionGoal::PathSubstitutionGoal(const StorePath & storePath, Worker & worker, RepairFlag repair, std::optional<ContentAddress> ca)
|
2022-03-09 13:25:35 +02:00
|
|
|
: Goal(worker, DerivedPath::Opaque { storePath })
|
2020-06-16 23:20:18 +03:00
|
|
|
, storePath(storePath)
|
2012-10-02 21:08:59 +03:00
|
|
|
, repair(repair)
|
2020-06-13 08:07:42 +03:00
|
|
|
, ca(ca)
|
2004-06-18 21:09:32 +03:00
|
|
|
{
|
2020-11-09 14:47:06 +02:00
|
|
|
state = &PathSubstitutionGoal::init;
|
2020-01-06 23:18:00 +02:00
|
|
|
name = fmt("substitution of '%s'", worker.store.printStorePath(this->storePath));
|
2005-02-18 11:50:20 +02:00
|
|
|
trace("created");
|
2017-08-14 23:12:36 +03:00
|
|
|
maintainExpectedSubstitutions = std::make_unique<MaintainCount<uint64_t>>(worker.expectedSubstitutions);
|
2004-06-18 21:09:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-09 14:47:06 +02:00
|
|
|
PathSubstitutionGoal::~PathSubstitutionGoal()
|
2004-06-25 18:36:09 +03:00
|
|
|
{
|
2021-04-07 13:21:31 +03:00
|
|
|
cleanup();
|
2006-12-08 20:41:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-04-06 13:41:18 +03:00
|
|
|
void PathSubstitutionGoal::done(
|
|
|
|
ExitCode result,
|
|
|
|
BuildResult::Status status,
|
|
|
|
std::optional<std::string> errorMsg)
|
2022-03-08 20:50:46 +02:00
|
|
|
{
|
|
|
|
buildResult.status = status;
|
2022-04-06 13:41:18 +03:00
|
|
|
if (errorMsg) {
|
|
|
|
debug(*errorMsg);
|
|
|
|
buildResult.errorMsg = *errorMsg;
|
|
|
|
}
|
2022-03-08 20:50:46 +02:00
|
|
|
amDone(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-09 14:47:06 +02:00
|
|
|
void PathSubstitutionGoal::work()
|
2004-06-18 21:09:32 +03:00
|
|
|
{
|
|
|
|
(this->*state)();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-09 14:47:06 +02:00
|
|
|
void PathSubstitutionGoal::init()
|
2004-06-18 21:09:32 +03:00
|
|
|
{
|
2004-06-22 20:04:10 +03:00
|
|
|
trace("init");
|
2004-06-18 21:09:32 +03:00
|
|
|
|
2008-06-09 16:52:45 +03:00
|
|
|
worker.store.addTempRoot(storePath);
|
2012-07-27 16:59:18 +03:00
|
|
|
|
2004-06-18 21:09:32 +03:00
|
|
|
/* If the path already exists we're done. */
|
2012-10-02 21:08:59 +03:00
|
|
|
if (!repair && worker.store.isValidPath(storePath)) {
|
2022-03-08 20:50:46 +02:00
|
|
|
done(ecSuccess, BuildResult::AlreadyValid);
|
2004-06-18 21:09:32 +03:00
|
|
|
return;
|
2003-08-20 14:30:45 +03:00
|
|
|
}
|
|
|
|
|
2012-07-31 02:55:41 +03:00
|
|
|
if (settings.readOnlyMode)
|
2019-12-05 20:11:09 +02:00
|
|
|
throw Error("cannot substitute path '%s' - no write access to the Nix store", worker.store.printStorePath(storePath));
|
2009-12-09 19:45:22 +02:00
|
|
|
|
2016-06-02 15:25:07 +03:00
|
|
|
subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
|
2012-07-27 16:59:18 +03:00
|
|
|
|
2008-08-04 16:15:35 +03:00
|
|
|
tryNext();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-09 14:47:06 +02:00
|
|
|
void PathSubstitutionGoal::tryNext()
|
2008-08-04 16:15:35 +03:00
|
|
|
{
|
|
|
|
trace("trying next substituter");
|
|
|
|
|
2021-04-07 13:21:31 +03:00
|
|
|
cleanup();
|
|
|
|
|
2008-08-04 16:15:35 +03:00
|
|
|
if (subs.size() == 0) {
|
|
|
|
/* None left. Terminate this goal and let someone else deal
|
|
|
|
with it. */
|
2016-01-06 23:07:59 +02:00
|
|
|
|
2012-07-09 01:39:24 +03:00
|
|
|
/* Hack: don't indicate failure if there were no substituters.
|
|
|
|
In that case the calling derivation should just do a
|
|
|
|
build. */
|
2022-04-06 13:41:18 +03:00
|
|
|
done(
|
|
|
|
substituterFailed ? ecFailed : ecNoSubstituters,
|
|
|
|
BuildResult::NoSubstituters,
|
|
|
|
fmt("path '%s' is required, but there is no substituter that can build it", worker.store.printStorePath(storePath)));
|
2017-08-15 16:31:59 +03:00
|
|
|
|
2018-06-05 17:04:41 +03:00
|
|
|
if (substituterFailed) {
|
2017-08-15 16:31:59 +03:00
|
|
|
worker.failedSubstitutions++;
|
|
|
|
worker.updateProgress();
|
|
|
|
}
|
|
|
|
|
2007-08-12 03:29:28 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-08-04 16:15:35 +03:00
|
|
|
sub = subs.front();
|
|
|
|
subs.pop_front();
|
|
|
|
|
2020-06-22 20:08:11 +03:00
|
|
|
if (ca) {
|
2020-10-13 18:36:20 +03:00
|
|
|
subPath = sub->makeFixedOutputPathFromCA({
|
|
|
|
.name = std::string { storePath.name() },
|
|
|
|
.info = caWithoutRefs(*ca),
|
|
|
|
});
|
2020-06-17 21:04:46 +03:00
|
|
|
if (sub->storeDir == worker.store.storeDir)
|
|
|
|
assert(subPath == storePath);
|
2020-07-02 17:59:24 +03:00
|
|
|
} else if (sub->storeDir != worker.store.storeDir) {
|
2016-06-01 17:40:49 +03:00
|
|
|
tryNext();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-04-29 14:57:08 +03:00
|
|
|
try {
|
|
|
|
// FIXME: make async
|
2020-07-02 18:12:05 +03:00
|
|
|
info = sub->queryPathInfo(subPath ? *subPath : storePath);
|
2016-04-29 14:57:08 +03:00
|
|
|
} catch (InvalidPath &) {
|
|
|
|
tryNext();
|
|
|
|
return;
|
2018-09-07 18:08:43 +03:00
|
|
|
} catch (SubstituterDisabled &) {
|
|
|
|
if (settings.tryFallback) {
|
|
|
|
tryNext();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
throw;
|
2018-09-07 17:35:48 +03:00
|
|
|
} catch (Error & e) {
|
|
|
|
if (settings.tryFallback) {
|
2020-05-03 17:01:25 +03:00
|
|
|
logError(e.info());
|
2018-09-07 17:35:48 +03:00
|
|
|
tryNext();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
throw;
|
2016-04-29 14:57:08 +03:00
|
|
|
}
|
|
|
|
|
2020-06-13 08:07:42 +03:00
|
|
|
if (info->path != storePath) {
|
2020-10-13 18:36:20 +03:00
|
|
|
if (info->isContentAddressed(*sub) && info->references.empty() && !info->hasSelfReference) {
|
2020-06-17 21:14:22 +03:00
|
|
|
auto info2 = std::make_shared<ValidPathInfo>(*info);
|
2020-06-17 20:18:47 +03:00
|
|
|
info2->path = storePath;
|
2020-06-13 08:07:42 +03:00
|
|
|
info = info2;
|
|
|
|
} else {
|
|
|
|
printError("asked '%s' for '%s' but got '%s'",
|
|
|
|
sub->getUri(), worker.store.printStorePath(storePath), sub->printStorePath(info->path));
|
|
|
|
tryNext();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-14 21:14:55 +03:00
|
|
|
/* Update the total expected download size. */
|
|
|
|
auto narInfo = std::dynamic_pointer_cast<const NarInfo>(info);
|
|
|
|
|
2018-02-05 18:46:43 +02:00
|
|
|
maintainExpectedNar = std::make_unique<MaintainCount<uint64_t>>(worker.expectedNarSize, info->narSize);
|
2017-08-14 21:14:55 +03:00
|
|
|
|
|
|
|
maintainExpectedDownload =
|
|
|
|
narInfo && narInfo->fileSize
|
|
|
|
? std::make_unique<MaintainCount<uint64_t>>(worker.expectedDownloadSize, narInfo->fileSize)
|
|
|
|
: nullptr;
|
|
|
|
|
|
|
|
worker.updateProgress();
|
|
|
|
|
2016-05-30 16:09:01 +03:00
|
|
|
/* Bail out early if this substituter lacks a valid
|
|
|
|
signature. LocalStore::addToStore() also checks for this, but
|
|
|
|
only after we've downloaded the path. */
|
2021-03-08 16:07:33 +02:00
|
|
|
if (!sub->isTrusted && worker.store.pathInfoIsUntrusted(*info))
|
2018-02-05 19:08:30 +02:00
|
|
|
{
|
2022-06-23 15:22:11 +03:00
|
|
|
warn("ignoring substitute for '%s' from '%s', as it's not signed by any of the keys in 'trusted-public-keys'",
|
2021-12-11 02:02:22 +02:00
|
|
|
worker.store.printStorePath(storePath), sub->getUri());
|
2016-05-30 16:09:01 +03:00
|
|
|
tryNext();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2005-09-20 19:14:00 +03:00
|
|
|
/* To maintain the closure invariant, we first have to realise the
|
2005-01-25 19:08:52 +02:00
|
|
|
paths referenced by this one. */
|
2016-04-29 14:57:08 +03:00
|
|
|
for (auto & i : info->references)
|
2021-04-06 01:29:52 +03:00
|
|
|
addWaitee(worker.makePathSubstitutionGoal(i));
|
2005-01-25 19:08:52 +02:00
|
|
|
|
|
|
|
if (waitees.empty()) /* to prevent hang (no wake-up event) */
|
|
|
|
referencesValid();
|
|
|
|
else
|
2020-11-09 14:47:06 +02:00
|
|
|
state = &PathSubstitutionGoal::referencesValid;
|
2005-01-25 19:08:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-09 14:47:06 +02:00
|
|
|
void PathSubstitutionGoal::referencesValid()
|
2005-01-25 19:08:52 +02:00
|
|
|
{
|
2007-08-12 03:29:28 +03:00
|
|
|
trace("all references realised");
|
2005-01-25 19:08:52 +02:00
|
|
|
|
2006-12-08 19:26:21 +02:00
|
|
|
if (nrFailed > 0) {
|
2022-03-08 20:50:46 +02:00
|
|
|
done(
|
|
|
|
nrNoSubstituters > 0 || nrIncompleteClosure > 0 ? ecIncompleteClosure : ecFailed,
|
2022-04-06 13:41:18 +03:00
|
|
|
BuildResult::DependencyFailed,
|
|
|
|
fmt("some references of path '%s' could not be realised", worker.store.printStorePath(storePath)));
|
2006-12-08 19:26:21 +02:00
|
|
|
return;
|
|
|
|
}
|
2005-01-25 19:08:52 +02:00
|
|
|
|
2016-04-29 14:57:08 +03:00
|
|
|
for (auto & i : info->references)
|
2020-10-13 18:36:20 +03:00
|
|
|
assert(worker.store.isValidPath(i));
|
2004-06-20 22:17:54 +03:00
|
|
|
|
2020-11-09 14:47:06 +02:00
|
|
|
state = &PathSubstitutionGoal::tryToRun;
|
2009-04-01 00:14:07 +03:00
|
|
|
worker.wakeUp(shared_from_this());
|
2004-06-22 12:00:31 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-09 14:47:06 +02:00
|
|
|
void PathSubstitutionGoal::tryToRun()
|
2004-06-22 12:00:31 +03:00
|
|
|
{
|
2004-06-22 20:04:10 +03:00
|
|
|
trace("trying to run");
|
|
|
|
|
2009-04-01 00:14:07 +03:00
|
|
|
/* Make sure that we are allowed to start a build. Note that even
|
2017-04-14 15:42:20 +03:00
|
|
|
if maxBuildJobs == 0 (no local builds allowed), we still allow
|
2009-04-01 00:14:07 +03:00
|
|
|
a substituter to run. This is because substitutions cannot be
|
|
|
|
distributed to another machine via the build hook. */
|
2017-04-28 17:20:46 +03:00
|
|
|
if (worker.getNrLocalBuilds() >= std::max(1U, (unsigned int) settings.maxBuildJobs)) {
|
2004-06-22 12:00:31 +03:00
|
|
|
worker.waitForBuildSlot(shared_from_this());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-08-14 23:42:17 +03:00
|
|
|
maintainRunningSubstitutions = std::make_unique<MaintainCount<uint64_t>>(worker.runningSubstitutions);
|
|
|
|
worker.updateProgress();
|
|
|
|
|
2012-07-27 19:16:02 +03:00
|
|
|
outPipe.create();
|
2012-11-09 19:00:33 +02:00
|
|
|
|
2016-04-29 14:57:08 +03:00
|
|
|
promise = std::promise<void>();
|
2012-11-09 19:00:33 +02:00
|
|
|
|
2016-04-29 14:57:08 +03:00
|
|
|
thr = std::thread([this]() {
|
|
|
|
try {
|
|
|
|
/* Wake up the worker loop when we're done. */
|
2021-04-07 13:21:31 +03:00
|
|
|
Finally updateStats([this]() { outPipe.writeSide.close(); });
|
2004-06-20 22:17:54 +03:00
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
Activity act(*logger, actSubstitute, Logger::Fields{worker.store.printStorePath(storePath), sub->getUri()});
|
2017-08-25 18:49:40 +03:00
|
|
|
PushActivity pact(act.id);
|
|
|
|
|
2021-07-19 13:01:06 +03:00
|
|
|
copyStorePath(*sub, worker.store,
|
2020-07-02 18:12:05 +03:00
|
|
|
subPath ? *subPath : storePath, repair, sub->isTrusted ? NoCheckSigs : CheckSigs);
|
2004-06-20 22:17:54 +03:00
|
|
|
|
2016-04-29 14:57:08 +03:00
|
|
|
promise.set_value();
|
|
|
|
} catch (...) {
|
|
|
|
promise.set_exception(std::current_exception());
|
|
|
|
}
|
2014-07-10 17:50:51 +03:00
|
|
|
});
|
2012-07-27 19:16:02 +03:00
|
|
|
|
2016-07-11 22:44:44 +03:00
|
|
|
worker.childStarted(shared_from_this(), {outPipe.readSide.get()}, true, false);
|
2004-06-20 22:17:54 +03:00
|
|
|
|
2020-11-09 14:47:06 +02:00
|
|
|
state = &PathSubstitutionGoal::finished;
|
2004-06-20 22:17:54 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-09 14:47:06 +02:00
|
|
|
void PathSubstitutionGoal::finished()
|
2004-06-20 22:17:54 +03:00
|
|
|
{
|
2004-06-22 20:04:10 +03:00
|
|
|
trace("substitute finished");
|
2004-06-20 22:17:54 +03:00
|
|
|
|
2016-04-29 14:57:08 +03:00
|
|
|
thr.join();
|
2016-08-30 16:45:39 +03:00
|
|
|
worker.childTerminated(this);
|
2004-06-20 22:17:54 +03:00
|
|
|
|
2004-06-24 16:40:38 +03:00
|
|
|
try {
|
2016-04-29 14:57:08 +03:00
|
|
|
promise.get_future().get();
|
2018-06-05 17:04:41 +03:00
|
|
|
} catch (std::exception & e) {
|
|
|
|
printError(e.what());
|
|
|
|
|
|
|
|
/* Cause the parent build to fail unless --fallback is given,
|
|
|
|
or the substitute has disappeared. The latter case behaves
|
|
|
|
the same as the substitute never having existed in the
|
|
|
|
first place. */
|
|
|
|
try {
|
|
|
|
throw;
|
|
|
|
} catch (SubstituteGone &) {
|
|
|
|
} catch (...) {
|
|
|
|
substituterFailed = true;
|
|
|
|
}
|
2012-07-27 16:59:18 +03:00
|
|
|
|
2004-06-24 16:40:38 +03:00
|
|
|
/* Try the next substitute. */
|
2020-11-09 14:47:06 +02:00
|
|
|
state = &PathSubstitutionGoal::tryNext;
|
2004-06-24 16:40:38 +03:00
|
|
|
worker.wakeUp(shared_from_this());
|
|
|
|
return;
|
|
|
|
}
|
2004-06-20 22:17:54 +03:00
|
|
|
|
2020-06-16 23:20:18 +03:00
|
|
|
worker.markContentsGood(storePath);
|
2012-10-03 17:38:09 +03:00
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
printMsg(lvlChatty, "substitution of path '%s' succeeded", worker.store.printStorePath(storePath));
|
2004-06-24 16:40:38 +03:00
|
|
|
|
2017-08-14 23:42:17 +03:00
|
|
|
maintainRunningSubstitutions.reset();
|
|
|
|
|
2017-08-14 23:12:36 +03:00
|
|
|
maintainExpectedSubstitutions.reset();
|
|
|
|
worker.doneSubstitutions++;
|
|
|
|
|
2017-08-14 21:14:55 +03:00
|
|
|
if (maintainExpectedDownload) {
|
|
|
|
auto fileSize = maintainExpectedDownload->delta;
|
|
|
|
maintainExpectedDownload.reset();
|
|
|
|
worker.doneDownloadSize += fileSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
worker.doneNarSize += maintainExpectedNar->delta;
|
|
|
|
maintainExpectedNar.reset();
|
|
|
|
|
|
|
|
worker.updateProgress();
|
|
|
|
|
2022-03-08 20:50:46 +02:00
|
|
|
done(ecSuccess, BuildResult::Substituted);
|
2004-06-18 21:09:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
void PathSubstitutionGoal::handleChildOutput(int fd, std::string_view data)
|
2004-06-29 12:41:50 +03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-09 14:47:06 +02:00
|
|
|
void PathSubstitutionGoal::handleEOF(int fd)
|
2005-10-17 18:33:24 +03:00
|
|
|
{
|
2016-07-11 22:44:44 +03:00
|
|
|
if (fd == outPipe.readSide.get()) worker.wakeUp(shared_from_this());
|
2005-10-17 18:33:24 +03:00
|
|
|
}
|
|
|
|
|
2021-04-07 13:21:31 +03:00
|
|
|
|
|
|
|
void PathSubstitutionGoal::cleanup()
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
if (thr.joinable()) {
|
|
|
|
// FIXME: signal worker thread to quit.
|
|
|
|
thr.join();
|
|
|
|
worker.childTerminated(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
outPipe.close();
|
|
|
|
} catch (...) {
|
|
|
|
ignoreException();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-09-05 00:06:23 +03:00
|
|
|
}
|