mirror of
https://github.com/NixOS/nix
synced 2025-06-25 10:41:16 +02:00
WIP rework goals
This commit is contained in:
parent
d80d68034c
commit
7b01c8b8cd
14 changed files with 498 additions and 98 deletions
208
src/libstore/build/build-trace-goal.cc
Normal file
208
src/libstore/build/build-trace-goal.cc
Normal file
|
@ -0,0 +1,208 @@
|
||||||
|
#include "nix/store/build/build-trace-goal.hh"
|
||||||
|
#include "nix/util/finally.hh"
|
||||||
|
#include "nix/store/build/worker.hh"
|
||||||
|
#include "nix/store/build/substitution-goal.hh"
|
||||||
|
#include "nix/util/callback.hh"
|
||||||
|
#include "nix/util/util.hh"
|
||||||
|
#include "nix/store/derivations.hh"
|
||||||
|
#include "nix/store/store-open.hh"
|
||||||
|
#include "nix/store/build/derivation-resolution-goal.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
BuildTraceGoal::BuildTraceGoal(const SingleDerivedPath::Built & id, Worker & worker)
|
||||||
|
: Goal{worker, init()}
|
||||||
|
, id{id}
|
||||||
|
{
|
||||||
|
name = fmt("substitution of '%s'", id.to_string(worker.store));
|
||||||
|
trace("created");
|
||||||
|
}
|
||||||
|
|
||||||
|
Goal::Co BuildTraceGoal::init()
|
||||||
|
{
|
||||||
|
trace("init");
|
||||||
|
|
||||||
|
DrvOutput id2{
|
||||||
|
.drvPath = StorePath::dummy,
|
||||||
|
.outputName = id.output,
|
||||||
|
};
|
||||||
|
|
||||||
|
// No `std::visit` with coroutines :(
|
||||||
|
if (const auto * path = std::get_if<SingleDerivedPath::Opaque>(&*id.drvPath)) {
|
||||||
|
// At least we know the drv path statically, can procede
|
||||||
|
id2.drvPath = path->path;
|
||||||
|
} else if (const auto * outputDeriving = std::get_if<SingleDerivedPath::Built>(&*id.drvPath)) {
|
||||||
|
// Dynamic derivation case, need to resolve that first.
|
||||||
|
|
||||||
|
auto g = worker.makeBuildTraceGoal({
|
||||||
|
outputDeriving->drvPath,
|
||||||
|
outputDeriving->output,
|
||||||
|
});
|
||||||
|
|
||||||
|
co_await await(Goals{upcast_goal(g)});
|
||||||
|
|
||||||
|
if (nrFailed > 0) {
|
||||||
|
debug("The output deriving path '%s' could not be resolved", outputDeriving->to_string(worker.store));
|
||||||
|
co_return amDone(nrNoSubstituters > 0 ? ecNoSubstituters : ecFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
id2.drvPath = g->outputInfo->outPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the derivation already exists, we’re done */
|
||||||
|
if ((outputInfo = worker.store.queryRealisation(id2))) {
|
||||||
|
co_return amDone(ecSuccess);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Firstly, whether we know the status, secondly, what it is
|
||||||
|
*/
|
||||||
|
std::optional<bool> drvIsResolved;
|
||||||
|
|
||||||
|
/* If the derivation has statically-known output paths */
|
||||||
|
if (worker.evalStore.isValidPath(id2.drvPath)) {
|
||||||
|
auto drv = worker.evalStore.readDerivation(id2.drvPath);
|
||||||
|
auto os = drv.outputsAndOptPaths(worker.store);
|
||||||
|
/* Mark what we now know */
|
||||||
|
drvIsResolved = {drv.inputDrvs.map.empty()};
|
||||||
|
if (auto * p = get(os, id2.outputName)) {
|
||||||
|
if (auto & outPath = p->second) {
|
||||||
|
outputInfo = std::make_shared<UnkeyedRealisation>(*outPath);
|
||||||
|
co_return amDone(ecSuccess);
|
||||||
|
} else {
|
||||||
|
/* Otherwise, not failure, just looking up build trace below. */
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug(
|
||||||
|
"Derivation '%s' does not have output '%s', impossible to find build trace key-value pair",
|
||||||
|
worker.store.printStorePath(id2.drvPath),
|
||||||
|
id2.outputName);
|
||||||
|
co_return amDone(ecFailed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
|
||||||
|
|
||||||
|
bool substituterFailed = false;
|
||||||
|
|
||||||
|
if (!drvIsResolved || *drvIsResolved) {
|
||||||
|
/* Since derivation might be resolved --- isn't known to be
|
||||||
|
not-resolved, it might have entries. So, let's try querying
|
||||||
|
the substituters. */
|
||||||
|
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(
|
||||||
|
id2, {[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);
|
||||||
|
|
||||||
|
std::shared_ptr<const UnkeyedRealisation> outputInfo;
|
||||||
|
try {
|
||||||
|
outputInfo = promise->get_future().get();
|
||||||
|
} catch (std::exception & e) {
|
||||||
|
printError(e.what());
|
||||||
|
substituterFailed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!outputInfo)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
worker.store.registerDrvOutput({*outputInfo, id2});
|
||||||
|
|
||||||
|
trace("finished");
|
||||||
|
co_return amDone(ecSuccess);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Derivation might not be resolved, let's try doing that */
|
||||||
|
trace("trying resolving derivation in build-trace goal");
|
||||||
|
|
||||||
|
auto g = worker.makeDerivationResolutionGoal(id2.drvPath);
|
||||||
|
|
||||||
|
co_await await(Goals{g});
|
||||||
|
|
||||||
|
if (nrFailed > 0) {
|
||||||
|
/* 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",
|
||||||
|
id2.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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This should be set if the goal succeeded */
|
||||||
|
assert(g->resolvedDrv);
|
||||||
|
|
||||||
|
/* Try everything again, now with a resolved derivation */
|
||||||
|
auto bt2 = worker.makeBuildTraceGoal({
|
||||||
|
makeConstantStorePathRef(g->resolvedDrvPath),
|
||||||
|
id2.outputName,
|
||||||
|
});
|
||||||
|
|
||||||
|
co_await await(Goals{bt2});
|
||||||
|
|
||||||
|
/* Set the build trace value as our own. Note the signure will not
|
||||||
|
match our key since we're the unresolved derivation, but that's
|
||||||
|
fine. We're not writing it to the DB; that's `bt2`' job. */
|
||||||
|
if (bt2->outputInfo)
|
||||||
|
outputInfo = bt2->outputInfo;
|
||||||
|
|
||||||
|
co_return amDone(bt2->exitCode, bt2->ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string BuildTraceGoal::key()
|
||||||
|
{
|
||||||
|
/* "a$" ensures substitution goals happen before derivation
|
||||||
|
goals. */
|
||||||
|
return "a$" + std::string(id.to_string(worker.store));
|
||||||
|
}
|
||||||
|
|
||||||
|
void BuildTraceGoal::handleEOF(Descriptor fd)
|
||||||
|
{
|
||||||
|
worker.wakeUp(shared_from_this());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -62,7 +62,7 @@ std::string DerivationCreationAndRealisationGoal::key()
|
||||||
i.e. a derivation named "aardvark" always comes before "baboon". And
|
i.e. a derivation named "aardvark" always comes before "baboon". And
|
||||||
substitution goals and inner derivation goals always happen before
|
substitution goals and inner derivation goals always happen before
|
||||||
derivation goals (due to "b$"). */
|
derivation goals (due to "b$"). */
|
||||||
return "c$" + std::string(pathPartOfReq(*drvReq).name()) + "$" + DerivedPath::Built{
|
return "d$" + std::string(pathPartOfReq(*drvReq).name()) + "$" + DerivedPath::Built{
|
||||||
.drvPath = drvReq,
|
.drvPath = drvReq,
|
||||||
.outputs = wantedOutputs,
|
.outputs = wantedOutputs,
|
||||||
}.to_string(worker.store);
|
}.to_string(worker.store);
|
||||||
|
|
|
@ -50,7 +50,7 @@ std::string DerivationGoal::key()
|
||||||
i.e. a derivation named "aardvark" always comes before
|
i.e. a derivation named "aardvark" always comes before
|
||||||
"baboon". And substitution goals always happen before
|
"baboon". And substitution goals always happen before
|
||||||
derivation goals (due to "b$"). */
|
derivation goals (due to "b$"). */
|
||||||
return "b$" + std::string(drvPath.name()) + "$" + SingleDerivedPath::Built{
|
return "c$" + std::string(drvPath.name()) + "$" + SingleDerivedPath::Built{
|
||||||
.drvPath = makeConstantStorePathRef(drvPath),
|
.drvPath = makeConstantStorePathRef(drvPath),
|
||||||
.output = wantedOutput,
|
.output = wantedOutput,
|
||||||
}.to_string(worker.store);
|
}.to_string(worker.store);
|
||||||
|
|
82
src/libstore/build/derivation-resolution-goal.cc
Normal file
82
src/libstore/build/derivation-resolution-goal.cc
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
#include "nix/store/build/derivation-resolution-goal.hh"
|
||||||
|
#include "nix/util/finally.hh"
|
||||||
|
#include "nix/store/build/worker.hh"
|
||||||
|
#include "nix/store/build/substitution-goal.hh"
|
||||||
|
#include "nix/util/callback.hh"
|
||||||
|
#include "nix/store/derivations.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
DerivationResolutionGoal::DerivationResolutionGoal(const StorePath & drvPath, Worker & worker)
|
||||||
|
: Goal(worker, init())
|
||||||
|
, drvPath(drvPath)
|
||||||
|
{
|
||||||
|
name = fmt("resolution of '%s'", worker.store.printStorePath(drvPath));
|
||||||
|
trace("created");
|
||||||
|
}
|
||||||
|
|
||||||
|
Goal::Co DerivationResolutionGoal::init()
|
||||||
|
{
|
||||||
|
trace("init");
|
||||||
|
|
||||||
|
std::unique_ptr<Derivation> drv;
|
||||||
|
|
||||||
|
if (worker.evalStore.isValidPath(drvPath)) {
|
||||||
|
drv = std::make_unique<Derivation>(worker.evalStore.readDerivation(drvPath));
|
||||||
|
} else if (worker.store.isValidPath(drvPath)) {
|
||||||
|
drv = std::make_unique<Derivation>(worker.store.readDerivation(drvPath));
|
||||||
|
} else {
|
||||||
|
auto goal0 = worker.makePathSubstitutionGoal(drvPath);
|
||||||
|
goal0->preserveException = true;
|
||||||
|
co_await await(Goals{goal0});
|
||||||
|
if (nrFailed > 0)
|
||||||
|
co_return amDone(goal0->exitCode, goal0->ex);
|
||||||
|
|
||||||
|
drv = std::make_unique<Derivation>(worker.store.readDerivation(drvPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
trace("output path substituted");
|
||||||
|
|
||||||
|
std::set<std::shared_ptr<BuildTraceGoal>> goals;
|
||||||
|
|
||||||
|
std::function<void(ref<SingleDerivedPath>, const DerivedPathMap<StringSet>::ChildNode &)> accumInputPaths;
|
||||||
|
|
||||||
|
accumInputPaths = [&](ref<SingleDerivedPath> depDrvPath, const DerivedPathMap<StringSet>::ChildNode & inputNode) {
|
||||||
|
for (auto & outputName : inputNode.value)
|
||||||
|
goals.insert(worker.makeBuildTraceGoal(SingleDerivedPath::Built{depDrvPath, outputName}));
|
||||||
|
|
||||||
|
for (auto & [outputName, childNode] : inputNode.childMap)
|
||||||
|
accumInputPaths(make_ref<SingleDerivedPath>(SingleDerivedPath::Built{depDrvPath, outputName}), childNode);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto & [depDrvPath, depNode] : drv->inputDrvs.map)
|
||||||
|
accumInputPaths(makeConstantStorePathRef(depDrvPath), depNode);
|
||||||
|
|
||||||
|
if (nrFailed > 0) {
|
||||||
|
debug("TODO message");
|
||||||
|
co_return amDone(nrNoSubstituters > 0 ? ecNoSubstituters : ecFailed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true /*auto d = drv.tryResolve(....)*/) {
|
||||||
|
//resolvedDerivation = d.take();
|
||||||
|
|
||||||
|
trace("finished");
|
||||||
|
co_return amDone(ecSuccess);
|
||||||
|
} else {
|
||||||
|
// fail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string DerivationResolutionGoal::key()
|
||||||
|
{
|
||||||
|
/* "a$" ensures substitution goals happen before derivation
|
||||||
|
goals. */
|
||||||
|
return "b$" + worker.store.printStorePath(drvPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DerivationResolutionGoal::handleEOF(Descriptor fd)
|
||||||
|
{
|
||||||
|
worker.wakeUp(shared_from_this());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -3,7 +3,7 @@
|
||||||
#include "nix/store/build/worker.hh"
|
#include "nix/store/build/worker.hh"
|
||||||
#include "nix/store/build/substitution-goal.hh"
|
#include "nix/store/build/substitution-goal.hh"
|
||||||
#include "nix/util/callback.hh"
|
#include "nix/util/callback.hh"
|
||||||
#include "nix/store/store-open.hh"
|
#include "nix/store/build/build-trace-goal.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
@ -20,67 +20,11 @@ Goal::Co DrvOutputSubstitutionGoal::init()
|
||||||
{
|
{
|
||||||
trace("init");
|
trace("init");
|
||||||
|
|
||||||
/* If the derivation already exists, we’re done */
|
auto goal0 = worker.makeBuildTraceGoal({
|
||||||
if (worker.store.queryRealisation(id)) {
|
makeConstantStorePathRef(id.drvPath),
|
||||||
co_return amDone(ecSuccess);
|
id.outputName,
|
||||||
}
|
});
|
||||||
|
co_await await(Goals{upcast_goal(goal0)});
|
||||||
auto subs = settings.useSubstitutes ? getDefaultSubstituters() : std::list<ref<Store>>();
|
|
||||||
|
|
||||||
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");
|
trace("output path substituted");
|
||||||
|
|
||||||
|
@ -89,32 +33,19 @@ Goal::Co DrvOutputSubstitutionGoal::init()
|
||||||
co_return amDone(nrNoSubstituters > 0 ? ecNoSubstituters : ecFailed);
|
co_return amDone(nrNoSubstituters > 0 ? ecNoSubstituters : ecFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
worker.store.registerDrvOutput({*outputInfo, id});
|
auto goal1 = worker.makePathSubstitutionGoal(goal0->outputInfo->outPath);
|
||||||
|
goal0.reset();
|
||||||
|
|
||||||
trace("finished");
|
goal1->preserveException = true;
|
||||||
co_return amDone(ecSuccess);
|
co_await await(Goals{upcast_goal(goal1)});
|
||||||
}
|
co_return amDone(goal1->exitCode, goal1->ex);
|
||||||
|
|
||||||
/* 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string DrvOutputSubstitutionGoal::key()
|
std::string DrvOutputSubstitutionGoal::key()
|
||||||
{
|
{
|
||||||
/* "a$" ensures substitution goals happen before derivation
|
/* "a$" ensures substitution goals happen before derivation
|
||||||
goals. */
|
goals. */
|
||||||
return "a$" + std::string(id.render(worker.store));
|
return "b$" + std::string(id.render(worker.store));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrvOutputSubstitutionGoal::handleEOF(Descriptor fd)
|
void DrvOutputSubstitutionGoal::handleEOF(Descriptor fd)
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#ifndef _WIN32 // TODO Enable building on Windows
|
#ifndef _WIN32 // TODO Enable building on Windows
|
||||||
# include "nix/store/build/hook-instance.hh"
|
# include "nix/store/build/hook-instance.hh"
|
||||||
#endif
|
#endif
|
||||||
|
#include "nix/store/build/build-trace-goal.hh"
|
||||||
|
#include "nix/store/build/derivation-resolution-goal.hh"
|
||||||
#include "nix/util/signals.hh"
|
#include "nix/util/signals.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
@ -103,6 +105,33 @@ std::shared_ptr<DrvOutputSubstitutionGoal> Worker::makeDrvOutputSubstitutionGoal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<BuildTraceGoal> Worker::makeBuildTraceGoal(
|
||||||
|
const SingleDerivedPath::Built & req)
|
||||||
|
{
|
||||||
|
std::weak_ptr<BuildTraceGoal> & goal_weak = buildTraceGoals.ensureSlot(req).value;
|
||||||
|
std::shared_ptr<BuildTraceGoal> goal = goal_weak.lock();
|
||||||
|
if (!goal) {
|
||||||
|
goal = std::make_shared<BuildTraceGoal>(req, *this);
|
||||||
|
goal_weak = goal;
|
||||||
|
wakeUp(goal);
|
||||||
|
}
|
||||||
|
return goal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::shared_ptr<DerivationResolutionGoal> Worker::makeDerivationResolutionGoal(const StorePath & drvPath)
|
||||||
|
{
|
||||||
|
std::weak_ptr<DerivationResolutionGoal> & goal_weak = derivationResolutionGoals[drvPath];
|
||||||
|
auto goal = goal_weak.lock(); // FIXME
|
||||||
|
if (!goal) {
|
||||||
|
goal = std::make_shared<DerivationResolutionGoal>(drvPath, *this);
|
||||||
|
goal_weak = goal;
|
||||||
|
wakeUp(goal);
|
||||||
|
}
|
||||||
|
return goal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
GoalPtr Worker::makeGoal(const DerivedPath & req, BuildMode buildMode)
|
GoalPtr Worker::makeGoal(const DerivedPath & req, BuildMode buildMode)
|
||||||
{
|
{
|
||||||
return std::visit(overloaded {
|
return std::visit(overloaded {
|
||||||
|
@ -576,4 +605,14 @@ GoalPtr upcast_goal(std::shared_ptr<DerivationGoal> subGoal)
|
||||||
return subGoal;
|
return subGoal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GoalPtr upcast_goal(std::shared_ptr<BuildTraceGoal> subGoal)
|
||||||
|
{
|
||||||
|
return subGoal;
|
||||||
|
}
|
||||||
|
|
||||||
|
GoalPtr upcast_goal(std::shared_ptr<DerivationResolutionGoal> subGoal)
|
||||||
|
{
|
||||||
|
return subGoal;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,11 @@ create table if not exists Realisations (
|
||||||
outputName text not null, -- symbolic output id, usually "out"
|
outputName text not null, -- symbolic output id, usually "out"
|
||||||
outputPath integer not null,
|
outputPath integer not null,
|
||||||
signatures text, -- space-separated list
|
signatures text, -- space-separated list
|
||||||
foreign key (outputPath) references ValidPaths(id) on delete cascade
|
|
||||||
|
-- No such foreign key because we may well want realisations for
|
||||||
|
-- garbage-collected dependencies
|
||||||
|
|
||||||
|
--foreign key (outputPath) references ValidPaths(id) on delete cascade
|
||||||
);
|
);
|
||||||
|
|
||||||
create index if not exists IndexRealisations on Realisations(drvPath, outputName);
|
create index if not exists IndexRealisations on Realisations(drvPath, outputName);
|
||||||
|
|
|
@ -52,7 +52,9 @@ typename DerivedPathMap<V>::ChildNode * DerivedPathMap<V>::findSlot(const Single
|
||||||
|
|
||||||
// instantiations
|
// instantiations
|
||||||
|
|
||||||
|
#include "nix/store/build/build-trace-goal.hh"
|
||||||
#include "nix/store/build/derivation-creation-and-realisation-goal.hh"
|
#include "nix/store/build/derivation-creation-and-realisation-goal.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
@ -69,7 +71,7 @@ std::strong_ordering DerivedPathMap<StringSet>::ChildNode::operator <=> (
|
||||||
template struct DerivedPathMap<StringSet>::ChildNode;
|
template struct DerivedPathMap<StringSet>::ChildNode;
|
||||||
template struct DerivedPathMap<StringSet>;
|
template struct DerivedPathMap<StringSet>;
|
||||||
|
|
||||||
|
template struct DerivedPathMap<std::weak_ptr<BuildTraceGoal>>;
|
||||||
template struct DerivedPathMap<std::map<OutputsSpec, std::weak_ptr<DerivationCreationAndRealisationGoal>>>;
|
template struct DerivedPathMap<std::map<OutputsSpec, std::weak_ptr<DerivationCreationAndRealisationGoal>>>;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
54
src/libstore/include/nix/store/build/build-trace-goal.hh
Normal file
54
src/libstore/include/nix/store/build/build-trace-goal.hh
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#pragma once
|
||||||
|
///@file
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
|
#include "nix/store/store-api.hh"
|
||||||
|
#include "nix/store/build/goal.hh"
|
||||||
|
#include "nix/store/realisation.hh"
|
||||||
|
#include "nix/util/muxable-pipe.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
class Worker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to recursively obtain build trace key-value pairs in order to
|
||||||
|
* resolve the given output deriving path.
|
||||||
|
*/
|
||||||
|
class BuildTraceGoal : public Goal
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The output derivation path we're trying to reasolve.
|
||||||
|
*/
|
||||||
|
SingleDerivedPath::Built id;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BuildTraceGoal(const SingleDerivedPath::Built & id, Worker & worker);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The realisation corresponding to the given output id.
|
||||||
|
* Will be filled once we can get it.
|
||||||
|
*/
|
||||||
|
std::shared_ptr<const UnkeyedRealisation> outputInfo;
|
||||||
|
|
||||||
|
Co init();
|
||||||
|
|
||||||
|
void timedOut(Error && ex) override
|
||||||
|
{
|
||||||
|
unreachable();
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string key() override;
|
||||||
|
|
||||||
|
void handleEOF(Descriptor fd) override;
|
||||||
|
|
||||||
|
JobCategory jobCategory() const override
|
||||||
|
{
|
||||||
|
return JobCategory::Substitution;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
#pragma once
|
||||||
|
///@file
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
|
#include "nix/store/store-api.hh"
|
||||||
|
#include "nix/store/build/goal.hh"
|
||||||
|
#include "nix/store/realisation.hh"
|
||||||
|
#include "nix/util/muxable-pipe.hh"
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
class Worker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The purpose of this is to resolve the given derivation, so that it
|
||||||
|
* only has constant deriving paths as inputs.
|
||||||
|
*/
|
||||||
|
class DerivationResolutionGoal : public Goal
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The derivation we're trying to substitute
|
||||||
|
*/
|
||||||
|
StorePath drvPath;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DerivationResolutionGoal(const StorePath & storePath, Worker & worker);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The resolved derivation, if we succeeded.
|
||||||
|
*/
|
||||||
|
std::shared_ptr<BasicDerivation> resolvedDrv;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The path to derivation above, if we succeeded.
|
||||||
|
*
|
||||||
|
* Garbage that should not be read otherwise.
|
||||||
|
*/
|
||||||
|
StorePath resolvedDrvPath = StorePath::dummy;
|
||||||
|
|
||||||
|
Co init();
|
||||||
|
|
||||||
|
void timedOut(Error && ex) override
|
||||||
|
{
|
||||||
|
unreachable();
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string key() override;
|
||||||
|
|
||||||
|
void handleEOF(Descriptor fd) override;
|
||||||
|
|
||||||
|
JobCategory jobCategory() const override
|
||||||
|
{
|
||||||
|
return JobCategory::Substitution;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -35,12 +35,6 @@ public:
|
||||||
RepairFlag repair = NoRepair,
|
RepairFlag repair = NoRepair,
|
||||||
std::optional<ContentAddress> ca = std::nullopt);
|
std::optional<ContentAddress> ca = std::nullopt);
|
||||||
|
|
||||||
/**
|
|
||||||
* The realisation corresponding to the given output id.
|
|
||||||
* Will be filled once we can get it.
|
|
||||||
*/
|
|
||||||
std::shared_ptr<const UnkeyedRealisation> outputInfo;
|
|
||||||
|
|
||||||
Co init();
|
Co init();
|
||||||
|
|
||||||
void timedOut(Error && ex) override
|
void timedOut(Error && ex) override
|
||||||
|
|
|
@ -19,6 +19,8 @@ struct DerivationGoal;
|
||||||
struct DerivationBuildingGoal;
|
struct DerivationBuildingGoal;
|
||||||
struct PathSubstitutionGoal;
|
struct PathSubstitutionGoal;
|
||||||
class DrvOutputSubstitutionGoal;
|
class DrvOutputSubstitutionGoal;
|
||||||
|
class BuildTraceGoal;
|
||||||
|
class DerivationResolutionGoal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Workaround for not being able to declare a something like
|
* Workaround for not being able to declare a something like
|
||||||
|
@ -35,6 +37,8 @@ class DrvOutputSubstitutionGoal;
|
||||||
GoalPtr upcast_goal(std::shared_ptr<PathSubstitutionGoal> subGoal);
|
GoalPtr upcast_goal(std::shared_ptr<PathSubstitutionGoal> subGoal);
|
||||||
GoalPtr upcast_goal(std::shared_ptr<DrvOutputSubstitutionGoal> subGoal);
|
GoalPtr upcast_goal(std::shared_ptr<DrvOutputSubstitutionGoal> subGoal);
|
||||||
GoalPtr upcast_goal(std::shared_ptr<DerivationGoal> subGoal);
|
GoalPtr upcast_goal(std::shared_ptr<DerivationGoal> subGoal);
|
||||||
|
GoalPtr upcast_goal(std::shared_ptr<BuildTraceGoal> subGoal);
|
||||||
|
GoalPtr upcast_goal(std::shared_ptr<DerivationResolutionGoal> subGoal);
|
||||||
|
|
||||||
typedef std::chrono::time_point<std::chrono::steady_clock> steady_time_point;
|
typedef std::chrono::time_point<std::chrono::steady_clock> steady_time_point;
|
||||||
|
|
||||||
|
@ -108,12 +112,14 @@ private:
|
||||||
* same derivation / path.
|
* same derivation / path.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
DerivedPathMap<std::weak_ptr<BuildTraceGoal>> buildTraceGoals;
|
||||||
DerivedPathMap<std::map<OutputsSpec, std::weak_ptr<DerivationCreationAndRealisationGoal>>> derivationCreationAndRealisationGoals;
|
DerivedPathMap<std::map<OutputsSpec, std::weak_ptr<DerivationCreationAndRealisationGoal>>> derivationCreationAndRealisationGoals;
|
||||||
|
|
||||||
std::map<StorePath, std::map<OutputName, std::weak_ptr<DerivationGoal>>> derivationGoals;
|
std::map<StorePath, std::map<OutputName, std::weak_ptr<DerivationGoal>>> derivationGoals;
|
||||||
std::map<StorePath, std::weak_ptr<DerivationBuildingGoal>> derivationBuildingGoals;
|
std::map<StorePath, std::weak_ptr<DerivationBuildingGoal>> derivationBuildingGoals;
|
||||||
std::map<StorePath, std::weak_ptr<PathSubstitutionGoal>> substitutionGoals;
|
std::map<StorePath, std::weak_ptr<PathSubstitutionGoal>> substitutionGoals;
|
||||||
std::map<DrvOutput, std::weak_ptr<DrvOutputSubstitutionGoal>> drvOutputSubstitutionGoals;
|
std::map<DrvOutput, std::weak_ptr<DrvOutputSubstitutionGoal>> drvOutputSubstitutionGoals;
|
||||||
|
std::map<StorePath, std::weak_ptr<DerivationResolutionGoal>> derivationResolutionGoals;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Goals waiting for busy paths to be unlocked.
|
* Goals waiting for busy paths to be unlocked.
|
||||||
|
@ -230,11 +236,26 @@ public:
|
||||||
BuildMode buildMode = bmNormal);
|
BuildMode buildMode = bmNormal);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ref PathSubstitutionGoal "substitution goal"
|
* @ref PathSubstitutionGoal "path substitution goal"
|
||||||
*/
|
*/
|
||||||
std::shared_ptr<PathSubstitutionGoal> makePathSubstitutionGoal(const StorePath & storePath, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
|
std::shared_ptr<PathSubstitutionGoal> makePathSubstitutionGoal(const StorePath & storePath, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ref DrvOutputSubstitutionGoal "derivation output substitution goal"
|
||||||
|
*/
|
||||||
std::shared_ptr<DrvOutputSubstitutionGoal> makeDrvOutputSubstitutionGoal(const DrvOutput & id, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
|
std::shared_ptr<DrvOutputSubstitutionGoal> makeDrvOutputSubstitutionGoal(const DrvOutput & id, RepairFlag repair = NoRepair, std::optional<ContentAddress> ca = std::nullopt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ref BuildTraceGoal "derivation output substitution goal"
|
||||||
|
*/
|
||||||
|
std::shared_ptr<BuildTraceGoal> makeBuildTraceGoal(
|
||||||
|
const SingleDerivedPath::Built & key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ref DerivationResolutionGoal "derivation resolution goal"
|
||||||
|
*/
|
||||||
|
std::shared_ptr<DerivationResolutionGoal> makeDerivationResolutionGoal(const StorePath & drvPath);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a goal corresponding to the `DerivedPath`.
|
* Make a goal corresponding to the `DerivedPath`.
|
||||||
*
|
*
|
||||||
|
|
|
@ -12,10 +12,12 @@ config_pub_h = configure_file(
|
||||||
headers = [config_pub_h] + files(
|
headers = [config_pub_h] + files(
|
||||||
'binary-cache-store.hh',
|
'binary-cache-store.hh',
|
||||||
'build-result.hh',
|
'build-result.hh',
|
||||||
|
'build/build-trace-goal.hh',
|
||||||
'build/derivation-goal.hh',
|
'build/derivation-goal.hh',
|
||||||
'build/derivation-building-goal.hh',
|
'build/derivation-building-goal.hh',
|
||||||
'build/derivation-building-misc.hh',
|
'build/derivation-building-misc.hh',
|
||||||
'build/derivation-creation-and-realisation-goal.hh',
|
'build/derivation-creation-and-realisation-goal.hh',
|
||||||
|
'build/derivation-resolution-goal.hh',
|
||||||
'build/drv-output-substitution-goal.hh',
|
'build/drv-output-substitution-goal.hh',
|
||||||
'build/goal.hh',
|
'build/goal.hh',
|
||||||
'build/substitution-goal.hh',
|
'build/substitution-goal.hh',
|
||||||
|
|
|
@ -253,9 +253,12 @@ subdir('nix-meson-build-support/common')
|
||||||
sources = files(
|
sources = files(
|
||||||
'binary-cache-store.cc',
|
'binary-cache-store.cc',
|
||||||
'build-result.cc',
|
'build-result.cc',
|
||||||
|
'build/build-trace-goal.cc',
|
||||||
'build/derivation-goal.cc',
|
'build/derivation-goal.cc',
|
||||||
'build/derivation-building-goal.cc',
|
'build/derivation-building-goal.cc',
|
||||||
'build/derivation-creation-and-realisation-goal.cc',
|
'build/derivation-creation-and-realisation-goal.cc',
|
||||||
|
'build/derivation-goal.cc',
|
||||||
|
'build/derivation-resolution-goal.cc',
|
||||||
'build/drv-output-substitution-goal.cc',
|
'build/drv-output-substitution-goal.cc',
|
||||||
'build/entry-points.cc',
|
'build/entry-points.cc',
|
||||||
'build/goal.cc',
|
'build/goal.cc',
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue