1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-28 22:01:15 +02:00

WIP rework goals

This commit is contained in:
John Ericson 2025-02-15 13:34:38 -05:00
parent d80d68034c
commit 7b01c8b8cd
14 changed files with 498 additions and 98 deletions

View file

@ -3,7 +3,7 @@
#include "nix/store/build/worker.hh"
#include "nix/store/build/substitution-goal.hh"
#include "nix/util/callback.hh"
#include "nix/store/store-open.hh"
#include "nix/store/build/build-trace-goal.hh"
namespace nix {
@ -20,101 +20,32 @@ Goal::Co DrvOutputSubstitutionGoal::init()
{
trace("init");
/* If the derivation already exists, were done */
if (worker.store.queryRealisation(id)) {
co_return amDone(ecSuccess);
auto goal0 = worker.makeBuildTraceGoal({
makeConstantStorePathRef(id.drvPath),
id.outputName,
});
co_await await(Goals{upcast_goal(goal0)});
trace("output path substituted");
if (nrFailed > 0) {
debug("The output path of the derivation output '%s' could not be substituted", id.render(worker.store));
co_return amDone(nrNoSubstituters > 0 ? ecNoSubstituters : ecFailed);
}
auto subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
auto goal1 = worker.makePathSubstitutionGoal(goal0->outputInfo->outPath);
goal0.reset();
bool substituterFailed = false;
for (const auto & sub : subs) {
trace("trying next substituter");
/* The callback of the curl download below can outlive `this` (if
some other error occurs), so it must not touch `this`. So put
the shared state in a separate refcounted object. */
auto outPipe = std::make_shared<MuxablePipe>();
#ifndef _WIN32
outPipe->create();
#else
outPipe->createAsyncPipe(worker.ioport.get());
#endif
auto promise = std::make_shared<std::promise<std::shared_ptr<const UnkeyedRealisation>>>();
sub->queryRealisation(
id, {[outPipe(outPipe), promise(promise)](std::future<std::shared_ptr<const UnkeyedRealisation>> res) {
try {
Finally updateStats([&]() { outPipe->writeSide.close(); });
promise->set_value(res.get());
} catch (...) {
promise->set_exception(std::current_exception());
}
}});
worker.childStarted(
shared_from_this(),
{
#ifndef _WIN32
outPipe->readSide.get()
#else
&*outPipe
#endif
},
true,
false);
co_await Suspend{};
worker.childTerminated(this);
try {
outputInfo = promise->get_future().get();
} catch (std::exception & e) {
printError(e.what());
substituterFailed = true;
}
if (!outputInfo)
continue;
co_await await(Goals{worker.makePathSubstitutionGoal(outputInfo->outPath)});
trace("output path substituted");
if (nrFailed > 0) {
debug("The output path of the derivation output '%s' could not be substituted", id.render(worker.store));
co_return amDone(nrNoSubstituters > 0 ? ecNoSubstituters : ecFailed);
}
worker.store.registerDrvOutput({*outputInfo, id});
trace("finished");
co_return amDone(ecSuccess);
}
/* None left. Terminate this goal and let someone else deal
with it. */
debug("derivation output '%s' is required, but there is no substituter that can provide it", id.render(worker.store));
if (substituterFailed) {
worker.failedSubstitutions++;
worker.updateProgress();
}
/* Hack: don't indicate failure if there were no substituters.
In that case the calling derivation should just do a
build. */
co_return amDone(substituterFailed ? ecFailed : ecNoSubstituters);
goal1->preserveException = true;
co_await await(Goals{upcast_goal(goal1)});
co_return amDone(goal1->exitCode, goal1->ex);
}
std::string DrvOutputSubstitutionGoal::key()
{
/* "a$" ensures substitution goals happen before derivation
goals. */
return "a$" + std::string(id.render(worker.store));
return "b$" + std::string(id.render(worker.store));
}
void DrvOutputSubstitutionGoal::handleEOF(Descriptor fd)