diff options
author | Eelco Dolstra <edolstra@gmail.com> | 2021-05-17 16:28:14 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-17 16:28:14 +0200 |
commit | bd6cf25952a42afabea822141798566e0f0583b3 (patch) | |
tree | 1ce3a864ec0f6792f0d25cdb1a7646defd57ff87 /src/nix/app.cc | |
parent | 6849ae82de4512a98697b730f1fe70e6eed7a32c (diff) | |
parent | f46adb783c939c61a087cdfd8af964f4ad6f9816 (diff) |
Merge pull request #4819 from NixOS/ca/fix-nix-run
Resolve the program path in `nix run`
Diffstat (limited to 'src/nix/app.cc')
-rw-r--r-- | src/nix/app.cc | 94 |
1 files changed, 78 insertions, 16 deletions
diff --git a/src/nix/app.cc b/src/nix/app.cc index cf147c631..1e30deb34 100644 --- a/src/nix/app.cc +++ b/src/nix/app.cc @@ -3,9 +3,61 @@ #include "eval-inline.hh" #include "eval-cache.hh" #include "names.hh" +#include "command.hh" namespace nix { +struct InstallableDerivedPath : Installable +{ + ref<Store> store; + const DerivedPath derivedPath; + + InstallableDerivedPath(ref<Store> store, const DerivedPath & derivedPath) + : store(store) + , derivedPath(derivedPath) + { + } + + + std::string what() override { return derivedPath.to_string(*store); } + + DerivedPaths toDerivedPaths() override + { + return {derivedPath}; + } + + std::optional<StorePath> getStorePath() override + { + return std::nullopt; + } +}; + +/** + * Return the rewrites that are needed to resolve a string whose context is + * included in `dependencies` + */ +StringPairs resolveRewrites(Store & store, const BuiltPaths dependencies) +{ + StringPairs res; + for (auto & dep : dependencies) + if (auto drvDep = std::get_if<BuiltPathBuilt>(&dep)) + for (auto & [ outputName, outputPath ] : drvDep->outputs) + res.emplace( + downstreamPlaceholder(store, drvDep->drvPath, outputName), + store.printStorePath(outputPath) + ); + return res; +} + +/** + * Resolve the given string assuming the given context + */ +std::string resolveString(Store & store, const std::string & toResolve, const BuiltPaths dependencies) +{ + auto rewrites = resolveRewrites(store, dependencies); + return rewriteStrings(toResolve, rewrites); +} + App Installable::toApp(EvalState & state) { auto [cursor, attrPath] = getCursor(state); @@ -18,19 +70,21 @@ App Installable::toApp(EvalState & state) throw Error("app program '%s' is not in the Nix store", program); }; - if (type == "app") { - auto [program, context] = cursor->getAttr("program")->getStringWithContext(); + std::vector<std::shared_ptr<Installable>> context; + std::string unresolvedProgram; - checkProgram(program); - std::vector<StorePathWithOutputs> context2; - for (auto & [path, name] : context) - context2.push_back({state.store->parseStorePath(path), {name}}); + if (type == "app") { + auto [program, context_] = cursor->getAttr("program")->getStringWithContext(); + unresolvedProgram = program; - return App { - .context = std::move(context2), - .program = program, - }; + for (auto & [path, name] : context_) + context.push_back(std::make_shared<InstallableDerivedPath>( + state.store, + DerivedPathBuilt{ + .drvPath = state.store->parseStorePath(path), + .outputs = {name}, + })); } else if (type == "derivation") { @@ -44,16 +98,24 @@ App Installable::toApp(EvalState & state) aMainProgram ? aMainProgram->getString() : DrvName(name).name; - auto program = outPath + "/bin/" + mainProgram; - checkProgram(program); - return App { - .context = { { drvPath, {outputName} } }, - .program = program, - }; + unresolvedProgram = outPath + "/bin/" + mainProgram; + context = {std::make_shared<InstallableDerivedPath>( + state.store, + DerivedPathBuilt{ + .drvPath = drvPath, + .outputs = {outputName}, + })}; } else throw Error("attribute '%s' has unsupported type '%s'", attrPath, type); + + auto builtContext = build(state.store, Realise::Outputs, context); + auto program = resolveString(*state.store, unresolvedProgram, builtContext); + checkProgram(program); + return App { + .program = program, + }; } } |