|
| 1 | +#include "derivation-creation-and-realisation-goal.hh" |
| 2 | +#include "worker.hh" |
| 3 | + |
| 4 | +namespace nix { |
| 5 | + |
| 6 | +DerivationCreationAndRealisationGoal::DerivationCreationAndRealisationGoal( |
| 7 | + ref<SingleDerivedPath> drvReq, const OutputsSpec & wantedOutputs, Worker & worker, BuildMode buildMode) |
| 8 | + : Goal(worker, DerivedPath::Built{.drvPath = drvReq, .outputs = wantedOutputs}) |
| 9 | + , drvReq(drvReq) |
| 10 | + , wantedOutputs(wantedOutputs) |
| 11 | + , buildMode(buildMode) |
| 12 | +{ |
| 13 | + name = |
| 14 | + fmt("outer obtaining drv from '%s' and then building outputs %s", |
| 15 | + drvReq->to_string(worker.store), |
| 16 | + std::visit( |
| 17 | + overloaded{ |
| 18 | + [&](const OutputsSpec::All) -> std::string { return "* (all of them)"; }, |
| 19 | + [&](const OutputsSpec::Names os) { return concatStringsSep(", ", quoteStrings(os)); }, |
| 20 | + }, |
| 21 | + wantedOutputs.raw)); |
| 22 | + trace("created outer"); |
| 23 | + |
| 24 | + worker.updateProgress(); |
| 25 | +} |
| 26 | + |
| 27 | +DerivationCreationAndRealisationGoal::~DerivationCreationAndRealisationGoal() {} |
| 28 | + |
| 29 | +static StorePath pathPartOfReq(const SingleDerivedPath & req) |
| 30 | +{ |
| 31 | + return std::visit( |
| 32 | + overloaded{ |
| 33 | + [&](const SingleDerivedPath::Opaque & bo) { return bo.path; }, |
| 34 | + [&](const SingleDerivedPath::Built & bfd) { return pathPartOfReq(*bfd.drvPath); }, |
| 35 | + }, |
| 36 | + req.raw()); |
| 37 | +} |
| 38 | + |
| 39 | +std::string DerivationCreationAndRealisationGoal::key() |
| 40 | +{ |
| 41 | + /* Ensure that derivations get built in order of their name, |
| 42 | + i.e. a derivation named "aardvark" always comes before "baboon". And |
| 43 | + substitution goals and inner derivation goals always happen before |
| 44 | + derivation goals (due to "b$"). */ |
| 45 | + return "c$" + std::string(pathPartOfReq(*drvReq).name()) + "$" + drvReq->to_string(worker.store); |
| 46 | +} |
| 47 | + |
| 48 | +void DerivationCreationAndRealisationGoal::timedOut(Error && ex) {} |
| 49 | + |
| 50 | +void DerivationCreationAndRealisationGoal::addWantedOutputs(const OutputsSpec & outputs) |
| 51 | +{ |
| 52 | + /* If we already want all outputs, there is nothing to do. */ |
| 53 | + auto newWanted = wantedOutputs.union_(outputs); |
| 54 | + bool needRestart = !newWanted.isSubsetOf(wantedOutputs); |
| 55 | + wantedOutputs = newWanted; |
| 56 | + |
| 57 | + if (!needRestart) |
| 58 | + return; |
| 59 | + |
| 60 | + if (!optDrvPath) |
| 61 | + // haven't started steps where the outputs matter yet |
| 62 | + return; |
| 63 | + worker.makeDerivationGoal(*optDrvPath, outputs, buildMode); |
| 64 | +} |
| 65 | + |
| 66 | +Goal::Co DerivationCreationAndRealisationGoal::init() |
| 67 | +{ |
| 68 | + trace("outer init"); |
| 69 | + |
| 70 | + /* The first thing to do is to make sure that the derivation |
| 71 | + exists. If it doesn't, it may be created through a |
| 72 | + substitute. */ |
| 73 | + if (auto optDrvPath = [this]() -> std::optional<StorePath> { |
| 74 | + if (buildMode != bmNormal) |
| 75 | + return std::nullopt; |
| 76 | + |
| 77 | + auto drvPath = StorePath::dummy; |
| 78 | + try { |
| 79 | + drvPath = resolveDerivedPath(worker.store, *drvReq); |
| 80 | + } catch (MissingRealisation &) { |
| 81 | + return std::nullopt; |
| 82 | + } |
| 83 | + auto cond = worker.evalStore.isValidPath(drvPath) || worker.store.isValidPath(drvPath); |
| 84 | + return cond ? std::optional{drvPath} : std::nullopt; |
| 85 | + }()) { |
| 86 | + trace( |
| 87 | + fmt("already have drv '%s' for '%s', can go straight to building", |
| 88 | + worker.store.printStorePath(*optDrvPath), |
| 89 | + drvReq->to_string(worker.store))); |
| 90 | + } else { |
| 91 | + trace("need to obtain drv we want to build"); |
| 92 | + addWaitee(worker.makeGoal(DerivedPath::fromSingle(*drvReq))); |
| 93 | + co_await Suspend{}; |
| 94 | + } |
| 95 | + |
| 96 | + trace("outer load and build derivation"); |
| 97 | + |
| 98 | + if (nrFailed != 0) { |
| 99 | + co_return amDone(ecFailed, Error("cannot build missing derivation '%s'", drvReq->to_string(worker.store))); |
| 100 | + } |
| 101 | + |
| 102 | + StorePath drvPath = resolveDerivedPath(worker.store, *drvReq); |
| 103 | + /* Build this step! */ |
| 104 | + concreteDrvGoal = worker.makeDerivationGoal(drvPath, wantedOutputs, buildMode); |
| 105 | + { |
| 106 | + auto g = upcast_goal(concreteDrvGoal); |
| 107 | + /* We will finish with it ourselves, as if we were the derivational goal. */ |
| 108 | + g->preserveException = true; |
| 109 | + } |
| 110 | + optDrvPath = std::move(drvPath); |
| 111 | + addWaitee(upcast_goal(concreteDrvGoal)); |
| 112 | + co_await Suspend{}; |
| 113 | + |
| 114 | + trace("outer build done"); |
| 115 | + |
| 116 | + buildResult = upcast_goal(concreteDrvGoal) |
| 117 | + ->getBuildResult(DerivedPath::Built{ |
| 118 | + .drvPath = drvReq, |
| 119 | + .outputs = wantedOutputs, |
| 120 | + }); |
| 121 | + |
| 122 | + auto g = upcast_goal(concreteDrvGoal); |
| 123 | + co_return amDone(g->exitCode, g->ex); |
| 124 | +} |
| 125 | + |
| 126 | +} |
0 commit comments