diff options
Diffstat (limited to 'src/libcmd/installables.cc')
-rw-r--r-- | src/libcmd/installables.cc | 179 |
1 files changed, 126 insertions, 53 deletions
diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 0f0fcf39e..b7623d4ba 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -12,6 +12,7 @@ #include "eval-cache.hh" #include "url.hh" #include "registry.hh" +#include "build-result.hh" #include <regex> #include <queue> @@ -97,7 +98,7 @@ MixFlakeOptions::MixFlakeOptions() lockFlags.writeLockFile = false; lockFlags.inputOverrides.insert_or_assign( flake::parseInputPath(inputPath), - parseFlakeRef(flakeRef, absPath("."))); + parseFlakeRef(flakeRef, absPath("."), true)); }} }); @@ -158,7 +159,10 @@ SourceExprCommand::SourceExprCommand() Strings SourceExprCommand::getDefaultFlakeAttrPaths() { - return {"defaultPackage." + settings.thisSystem.get()}; + return { + "packages." + settings.thisSystem.get() + ".default", + "defaultPackage." + settings.thisSystem.get() + }; } Strings SourceExprCommand::getDefaultFlakeAttrPathPrefixes() @@ -191,18 +195,21 @@ void SourceExprCommand::completeInstallable(std::string_view prefix) auto sep = prefix_.rfind('.'); std::string searchWord; if (sep != std::string::npos) { - searchWord = prefix_.substr(sep, std::string::npos); + searchWord = prefix_.substr(sep + 1, std::string::npos); prefix_ = prefix_.substr(0, sep); } else { searchWord = prefix_; prefix_ = ""; } - Value &v1(*findAlongAttrPath(*state, prefix_, *autoArgs, root).first); - state->forceValue(v1); + auto [v, pos] = findAlongAttrPath(*state, prefix_, *autoArgs, root); + Value &v1(*v); + state->forceValue(v1, pos); Value v2; state->autoCallFunction(*autoArgs, v1, v2); + completionType = ctAttrs; + if (v2.type() == nAttrs) { for (auto & i : *v2.attrs) { std::string name = i.name; @@ -232,7 +239,9 @@ void completeFlakeRefWithFragment( prefix. */ try { auto hash = prefix.find('#'); - if (hash != std::string::npos) { + if (hash == std::string::npos) { + completeFlakeRef(evalState->store, prefix); + } else { auto fragment = prefix.substr(hash + 1); auto flakeRefS = std::string(prefix.substr(0, hash)); // FIXME: do tilde expansion. @@ -248,6 +257,8 @@ void completeFlakeRefWithFragment( flake. */ attrPathPrefixes.push_back(""); + completionType = ctAttrs; + for (auto & attrPathPrefixS : attrPathPrefixes) { auto attrPathPrefix = parseAttrPath(*evalState, attrPathPrefixS); auto attrPathS = attrPathPrefixS + std::string(fragment); @@ -262,9 +273,9 @@ void completeFlakeRefWithFragment( auto attr = root->findAlongAttrPath(attrPath); if (!attr) continue; - for (auto & attr2 : attr->getAttrs()) { + for (auto & attr2 : (*attr)->getAttrs()) { if (hasPrefix(attr2, lastAttr)) { - auto attrPath2 = attr->getAttrPath(attr2); + auto attrPath2 = (*attr)->getAttrPath(attr2); /* Strip the attrpath prefix. */ attrPath2.erase(attrPath2.begin(), attrPath2.begin() + attrPathPrefix.size()); completions->add(flakeRefS + "#" + concatStringsSep(".", attrPath2)); @@ -285,12 +296,13 @@ void completeFlakeRefWithFragment( } catch (Error & e) { warn(e.msg()); } - - completeFlakeRef(evalState->store, prefix); } void completeFlakeRef(ref<Store> store, std::string_view prefix) { + if (!settings.isExperimentalFeatureEnabled(Xp::Flakes)) + return; + if (prefix == "") completions->add("."); @@ -338,6 +350,18 @@ Installable::getCursor(EvalState & state) return cursors[0]; } +static StorePath getDeriver( + ref<Store> store, + const Installable & i, + const StorePath & drvPath) +{ + auto derivers = store->queryValidDerivers(drvPath); + if (derivers.empty()) + throw Error("'%s' does not have a known deriver", i.what()); + // FIXME: use all derivers? + return *derivers.begin(); +} + struct InstallableStorePath : Installable { ref<Store> store; @@ -346,7 +370,7 @@ struct InstallableStorePath : Installable InstallableStorePath(ref<Store> store, StorePath && storePath) : store(store), storePath(std::move(storePath)) { } - std::string what() override { return store->printStorePath(storePath); } + std::string what() const override { return store->printStorePath(storePath); } DerivedPaths toDerivedPaths() override { @@ -367,6 +391,15 @@ struct InstallableStorePath : Installable } } + StorePathSet toDrvPaths(ref<Store> store) override + { + if (storePath.isDerivation()) { + return {storePath}; + } else { + return {getDeriver(store, *this, storePath)}; + } + } + std::optional<StorePath> getStorePath() override { return storePath; @@ -395,6 +428,14 @@ DerivedPaths InstallableValue::toDerivedPaths() return res; } +StorePathSet InstallableValue::toDrvPaths(ref<Store> store) +{ + StorePathSet res; + for (auto & drv : toDerivations()) + res.insert(drv.drvPath); + return res; +} + struct InstallableAttrPath : InstallableValue { SourceExprCommand & cmd; @@ -405,12 +446,12 @@ struct InstallableAttrPath : InstallableValue : InstallableValue(state), cmd(cmd), v(allocRootValue(v)), attrPath(attrPath) { } - std::string what() override { return attrPath; } + std::string what() const override { return attrPath; } std::pair<Value *, Pos> toValue(EvalState & state) override { auto [vRes, pos] = findAlongAttrPath(state, attrPath, *cmd.getAutoArgs(state), **v); - state.forceValue(*vRes); + state.forceValue(*vRes, pos); return {vRes, pos}; } @@ -428,11 +469,10 @@ std::vector<InstallableValue::DerivationInfo> InstallableAttrPath::toDerivations std::vector<DerivationInfo> res; for (auto & drvInfo : drvInfos) { - res.push_back({ - state->store->parseStorePath(drvInfo.queryDrvPath()), - state->store->maybeParseStorePath(drvInfo.queryOutPath()), - drvInfo.queryOutputName() - }); + auto drvPath = drvInfo.queryDrvPath(); + if (!drvPath) + throw Error("'%s' is not a derivation", what()); + res.push_back({ *drvPath, drvInfo.queryOutputName() }); } return res; @@ -460,7 +500,7 @@ Value * InstallableFlake::getFlakeOutputs(EvalState & state, const flake::Locked auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs")); assert(aOutputs); - state.forceValue(*aOutputs->value); + state.forceValue(*aOutputs->value, [&]() { return aOutputs->value->determinePos(noPos); }); return aOutputs->value; } @@ -485,7 +525,7 @@ ref<eval_cache::EvalCache> openEvalCache( auto vFlake = state.allocValue(); flake::callFlake(state, *lockedFlake, *vFlake); - state.forceAttrs(*vFlake); + state.forceAttrs(*vFlake, noPos); auto aOutputs = vFlake->attrs->get(state.symbols.create("outputs")); assert(aOutputs); @@ -508,13 +548,14 @@ InstallableFlake::InstallableFlake( SourceExprCommand * cmd, ref<EvalState> state, FlakeRef && flakeRef, - Strings && attrPaths, - Strings && prefixes, + std::string_view fragment, + Strings attrPaths, + Strings prefixes, const flake::LockFlags & lockFlags) : InstallableValue(state), flakeRef(flakeRef), - attrPaths(attrPaths), - prefixes(prefixes), + attrPaths(fragment == "" ? attrPaths : Strings{(std::string) fragment}), + prefixes(fragment == "" ? Strings{} : prefixes), lockFlags(lockFlags) { if (cmd && cmd->getAutoArgs(*state)->size()) @@ -528,29 +569,37 @@ std::tuple<std::string, FlakeRef, InstallableValue::DerivationInfo> InstallableF auto cache = openEvalCache(*state, lockedFlake); auto root = cache->getRoot(); + Suggestions suggestions; + for (auto & attrPath : getActualAttrPaths()) { - auto attr = root->findAlongAttrPath( + debug("trying flake output attribute '%s'", attrPath); + + auto attrOrSuggestions = root->findAlongAttrPath( parseAttrPath(*state, attrPath), true ); - if (!attr) continue; + if (!attrOrSuggestions) { + suggestions += attrOrSuggestions.getSuggestions(); + continue; + } + + auto attr = *attrOrSuggestions; if (!attr->isDerivation()) throw Error("flake output attribute '%s' is not a derivation", attrPath); auto drvPath = attr->forceDerivation(); - auto drvInfo = DerivationInfo{ + auto drvInfo = DerivationInfo { std::move(drvPath), - state->store->maybeParseStorePath(attr->getAttr(state->sOutPath)->getString()), attr->getAttr(state->sOutputName)->getString() }; return {attrPath, lockedFlake->flake.lockedRef, std::move(drvInfo)}; } - throw Error("flake '%s' does not provide attribute %s", + throw Error(suggestions, "flake '%s' does not provide attribute %s", flakeRef, showAttrPaths(getActualAttrPaths())); } @@ -569,17 +618,24 @@ std::pair<Value *, Pos> InstallableFlake::toValue(EvalState & state) auto emptyArgs = state.allocBindings(0); + Suggestions suggestions; + for (auto & attrPath : getActualAttrPaths()) { try { auto [v, pos] = findAlongAttrPath(state, attrPath, *emptyArgs, *vOutputs); - state.forceValue(*v); + state.forceValue(*v, pos); return {v, pos}; } catch (AttrPathNotFound & e) { + suggestions += e.info().suggestions; } } - throw Error("flake '%s' does not provide attribute %s", - flakeRef, showAttrPaths(getActualAttrPaths())); + throw Error( + suggestions, + "flake '%s' does not provide attribute %s", + flakeRef, + showAttrPaths(getActualAttrPaths()) + ); } std::vector<std::pair<std::shared_ptr<eval_cache::AttrCursor>, std::string>> @@ -594,7 +650,7 @@ InstallableFlake::getCursors(EvalState & state) for (auto & attrPath : getActualAttrPaths()) { auto attr = root->findAlongAttrPath(parseAttrPath(state, attrPath)); - if (attr) res.push_back({attr, attrPath}); + if (attr) res.push_back({*attr, attrPath}); } return res; @@ -671,7 +727,8 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables( this, getEvalState(), std::move(flakeRef), - fragment == "" ? getDefaultFlakeAttrPaths() : Strings{fragment}, + fragment, + getDefaultFlakeAttrPaths(), getDefaultFlakeAttrPathPrefixes(), lockFlags)); continue; @@ -713,8 +770,7 @@ BuiltPaths getBuiltPaths(ref<Store> evalStore, ref<Store> store, const DerivedPa throw Error( "the derivation '%s' doesn't have an output named '%s'", store->printStorePath(bfd.drvPath), output); - if (settings.isExperimentalFeatureEnabled( - "ca-derivations")) { + if (settings.isExperimentalFeatureEnabled(Xp::CaDerivations)) { auto outputId = DrvOutput{outputHashes.at(output), output}; auto realisation = @@ -743,7 +799,7 @@ BuiltPaths getBuiltPaths(ref<Store> evalStore, ref<Store> store, const DerivedPa return res; } -BuiltPaths build( +BuiltPaths Installable::build( ref<Store> evalStore, ref<Store> store, Realise mode, @@ -760,15 +816,36 @@ BuiltPaths build( pathsToBuild.insert(pathsToBuild.end(), b.begin(), b.end()); } - if (mode == Realise::Nothing || mode == Realise::Derivation) + switch (mode) { + case Realise::Nothing: + case Realise::Derivation: printMissing(store, pathsToBuild, lvlError); - else if (mode == Realise::Outputs) - store->buildPaths(pathsToBuild, bMode, evalStore); - - return getBuiltPaths(evalStore, store, pathsToBuild); + return getBuiltPaths(evalStore, store, pathsToBuild); + case Realise::Outputs: { + BuiltPaths res; + for (auto & buildResult : store->buildPathsWithResults(pathsToBuild, bMode, evalStore)) { + if (!buildResult.success()) + buildResult.rethrow(); + std::visit(overloaded { + [&](const DerivedPath::Built & bfd) { + std::map<std::string, StorePath> outputs; + for (auto & path : buildResult.builtOutputs) + outputs.emplace(path.first.outputName, path.second.outPath); + res.push_back(BuiltPath::Built { bfd.drvPath, outputs }); + }, + [&](const DerivedPath::Opaque & bo) { + res.push_back(BuiltPath::Opaque { bo.path }); + }, + }, buildResult.path.raw()); + } + return res; + } + default: + assert(false); + } } -BuiltPaths toBuiltPaths( +BuiltPaths Installable::toBuiltPaths( ref<Store> evalStore, ref<Store> store, Realise mode, @@ -776,19 +853,19 @@ BuiltPaths toBuiltPaths( const std::vector<std::shared_ptr<Installable>> & installables) { if (operateOn == OperateOn::Output) - return build(evalStore, store, mode, installables); + return Installable::build(evalStore, store, mode, installables); else { if (mode == Realise::Nothing) settings.readOnlyMode = true; BuiltPaths res; - for (auto & drvPath : toDerivations(store, installables, true)) + for (auto & drvPath : Installable::toDerivations(store, installables, true)) res.push_back(BuiltPath::Opaque{drvPath}); return res; } } -StorePathSet toStorePaths( +StorePathSet Installable::toStorePaths( ref<Store> evalStore, ref<Store> store, Realise mode, OperateOn operateOn, @@ -802,7 +879,7 @@ StorePathSet toStorePaths( return outPaths; } -StorePath toStorePath( +StorePath Installable::toStorePath( ref<Store> evalStore, ref<Store> store, Realise mode, OperateOn operateOn, @@ -816,7 +893,7 @@ StorePath toStorePath( return *paths.begin(); } -StorePathSet toDerivations( +StorePathSet Installable::toDerivations( ref<Store> store, const std::vector<std::shared_ptr<Installable>> & installables, bool useDeriver) @@ -829,11 +906,7 @@ StorePathSet toDerivations( [&](const DerivedPath::Opaque & bo) { if (!useDeriver) throw Error("argument '%s' did not evaluate to a derivation", i->what()); - auto derivers = store->queryValidDerivers(bo.path); - if (derivers.empty()) - throw Error("'%s' does not have a known deriver", i->what()); - // FIXME: use all derivers? - drvPaths.insert(*derivers.begin()); + drvPaths.insert(getDeriver(store, *i, bo.path)); }, [&](const DerivedPath::Built & bfd) { drvPaths.insert(bfd.drvPath); |