mirror of
https://github.com/NixOS/nix
synced 2025-06-24 22:11:15 +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
|
||||
substitution goals and inner derivation goals always happen before
|
||||
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,
|
||||
.outputs = wantedOutputs,
|
||||
}.to_string(worker.store);
|
||||
|
|
|
@ -50,7 +50,7 @@ std::string DerivationGoal::key()
|
|||
i.e. a derivation named "aardvark" always comes before
|
||||
"baboon". And substitution goals always happen before
|
||||
derivation goals (due to "b$"). */
|
||||
return "b$" + std::string(drvPath.name()) + "$" + SingleDerivedPath::Built{
|
||||
return "c$" + std::string(drvPath.name()) + "$" + SingleDerivedPath::Built{
|
||||
.drvPath = makeConstantStorePathRef(drvPath),
|
||||
.output = wantedOutput,
|
||||
}.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/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, we’re 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)
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#ifndef _WIN32 // TODO Enable building on Windows
|
||||
# include "nix/store/build/hook-instance.hh"
|
||||
#endif
|
||||
#include "nix/store/build/build-trace-goal.hh"
|
||||
#include "nix/store/build/derivation-resolution-goal.hh"
|
||||
#include "nix/util/signals.hh"
|
||||
|
||||
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)
|
||||
{
|
||||
return std::visit(overloaded {
|
||||
|
@ -576,4 +605,14 @@ GoalPtr upcast_goal(std::shared_ptr<DerivationGoal> 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"
|
||||
outputPath integer not null,
|
||||
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);
|
||||
|
|
|
@ -52,7 +52,9 @@ typename DerivedPathMap<V>::ChildNode * DerivedPathMap<V>::findSlot(const Single
|
|||
|
||||
// instantiations
|
||||
|
||||
#include "nix/store/build/build-trace-goal.hh"
|
||||
#include "nix/store/build/derivation-creation-and-realisation-goal.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
template<>
|
||||
|
@ -69,7 +71,7 @@ std::strong_ordering DerivedPathMap<StringSet>::ChildNode::operator <=> (
|
|||
template struct DerivedPathMap<StringSet>::ChildNode;
|
||||
template struct DerivedPathMap<StringSet>;
|
||||
|
||||
template struct DerivedPathMap<std::weak_ptr<BuildTraceGoal>>;
|
||||
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,
|
||||
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();
|
||||
|
||||
void timedOut(Error && ex) override
|
||||
|
|
|
@ -19,6 +19,8 @@ struct DerivationGoal;
|
|||
struct DerivationBuildingGoal;
|
||||
struct PathSubstitutionGoal;
|
||||
class DrvOutputSubstitutionGoal;
|
||||
class BuildTraceGoal;
|
||||
class DerivationResolutionGoal;
|
||||
|
||||
/**
|
||||
* 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<DrvOutputSubstitutionGoal> 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;
|
||||
|
||||
|
@ -108,12 +112,14 @@ private:
|
|||
* same derivation / path.
|
||||
*/
|
||||
|
||||
DerivedPathMap<std::weak_ptr<BuildTraceGoal>> buildTraceGoals;
|
||||
DerivedPathMap<std::map<OutputsSpec, std::weak_ptr<DerivationCreationAndRealisationGoal>>> derivationCreationAndRealisationGoals;
|
||||
|
||||
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<PathSubstitutionGoal>> substitutionGoals;
|
||||
std::map<DrvOutput, std::weak_ptr<DrvOutputSubstitutionGoal>> drvOutputSubstitutionGoals;
|
||||
std::map<StorePath, std::weak_ptr<DerivationResolutionGoal>> derivationResolutionGoals;
|
||||
|
||||
/**
|
||||
* Goals waiting for busy paths to be unlocked.
|
||||
|
@ -230,11 +236,26 @@ public:
|
|||
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);
|
||||
|
||||
/**
|
||||
* @ref DrvOutputSubstitutionGoal "derivation output substitution goal"
|
||||
*/
|
||||
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`.
|
||||
*
|
||||
|
|
|
@ -12,10 +12,12 @@ config_pub_h = configure_file(
|
|||
headers = [config_pub_h] + files(
|
||||
'binary-cache-store.hh',
|
||||
'build-result.hh',
|
||||
'build/build-trace-goal.hh',
|
||||
'build/derivation-goal.hh',
|
||||
'build/derivation-building-goal.hh',
|
||||
'build/derivation-building-misc.hh',
|
||||
'build/derivation-creation-and-realisation-goal.hh',
|
||||
'build/derivation-resolution-goal.hh',
|
||||
'build/drv-output-substitution-goal.hh',
|
||||
'build/goal.hh',
|
||||
'build/substitution-goal.hh',
|
||||
|
|
|
@ -253,9 +253,12 @@ subdir('nix-meson-build-support/common')
|
|||
sources = files(
|
||||
'binary-cache-store.cc',
|
||||
'build-result.cc',
|
||||
'build/build-trace-goal.cc',
|
||||
'build/derivation-goal.cc',
|
||||
'build/derivation-building-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/entry-points.cc',
|
||||
'build/goal.cc',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue