aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorregnat <rg@regnat.ovh>2021-05-17 09:48:51 +0200
committerregnat <rg@regnat.ovh>2021-05-17 09:48:51 +0200
commitf0c0052d4b16d13d2a826a2839b680b729651179 (patch)
treedfd07bc2a5a644324e0ea74c6798d479612055b3 /src
parent21050846457f356346204dd52fb7a6d49f710688 (diff)
Resolve the program path in `nix run`
Fix #4768
Diffstat (limited to 'src')
-rw-r--r--src/nix/app.cc94
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,
+ };
}
}