From ca96f5219489c1002499bfe2c580fdd458219144 Mon Sep 17 00:00:00 2001 From: regnat Date: Mon, 17 May 2021 17:49:20 +0200 Subject: [PATCH] Split the parsing of an `App` and its resolving That way things (like `nix flake check`) can evaluate the `app` outputs without having to build anything --- src/libcmd/installables.hh | 8 ++++- src/nix/app.cc | 66 +++++++++++++++++++------------------- src/nix/bundle.cc | 3 +- src/nix/run.cc | 4 +-- 4 files changed, 42 insertions(+), 39 deletions(-) diff --git a/src/libcmd/installables.hh b/src/libcmd/installables.hh index 16bc4ae68..298fd48f8 100644 --- a/src/libcmd/installables.hh +++ b/src/libcmd/installables.hh @@ -23,6 +23,12 @@ struct App // FIXME: add args, sandbox settings, metadata, ... }; +struct UnresolvedApp +{ + App unresolved; + App resolve(ref); +}; + struct Installable { virtual ~Installable() { } @@ -33,7 +39,7 @@ struct Installable DerivedPath toDerivedPath(); - App toApp(EvalState & state); + UnresolvedApp toApp(EvalState & state); virtual std::pair toValue(EvalState & state) { diff --git a/src/nix/app.cc b/src/nix/app.cc index 1e30deb34..bdc64a886 100644 --- a/src/nix/app.cc +++ b/src/nix/app.cc @@ -58,33 +58,24 @@ std::string resolveString(Store & store, const std::string & toResolve, const Bu return rewriteStrings(toResolve, rewrites); } -App Installable::toApp(EvalState & state) +UnresolvedApp Installable::toApp(EvalState & state) { auto [cursor, attrPath] = getCursor(state); auto type = cursor->getAttr("type")->getString(); - auto checkProgram = [&](const Path & program) - { - if (!state.store->isInStore(program)) - throw Error("app program '%s' is not in the Nix store", program); - }; - - std::vector> context; - std::string unresolvedProgram; - - if (type == "app") { - auto [program, context_] = cursor->getAttr("program")->getStringWithContext(); - unresolvedProgram = program; + auto [program, context] = cursor->getAttr("program")->getStringWithContext(); - for (auto & [path, name] : context_) - context.push_back(std::make_shared( - state.store, - DerivedPathBuilt{ - .drvPath = state.store->parseStorePath(path), - .outputs = {name}, - })); + + std::vector context2; + for (auto & [path, name] : context) + context2.push_back({state.store->parseStorePath(path), {name}}); + + return UnresolvedApp{App { + .context = std::move(context2), + .program = program, + }}; } else if (type == "derivation") { @@ -98,24 +89,33 @@ App Installable::toApp(EvalState & state) aMainProgram ? aMainProgram->getString() : DrvName(name).name; - unresolvedProgram = outPath + "/bin/" + mainProgram; - context = {std::make_shared( - state.store, - DerivedPathBuilt{ - .drvPath = drvPath, - .outputs = {outputName}, - })}; + auto program = outPath + "/bin/" + mainProgram; + return UnresolvedApp { App { + .context = { { drvPath, {outputName} } }, + .program = program, + }}; } 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, - }; +App UnresolvedApp::resolve(ref store) +{ + auto res = unresolved; + + std::vector> installableContext; + + for (auto & ctxElt : unresolved.context) + installableContext.push_back( + std::make_shared(store, ctxElt.toDerivedPath())); + + auto builtContext = build(store, Realise::Outputs, installableContext); + res.program = resolveString(*store, unresolved.program, builtContext); + if (store->isInStore(res.program)) + throw Error("app program '%s' is not in the Nix store", res.program); + + return res; } } diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc index 53dccc63a..88bc3d1d1 100644 --- a/src/nix/bundle.cc +++ b/src/nix/bundle.cc @@ -69,8 +69,7 @@ struct CmdBundle : InstallableCommand { auto evalState = getEvalState(); - auto app = installable->toApp(*evalState); - store->buildPaths(toDerivedPaths(app.context)); + auto app = installable->toApp(*evalState).resolve(store); auto [bundlerFlakeRef, bundlerName] = parseFlakeRefWithFragment(bundler, absPath(".")); const flake::LockFlags lockFlags{ .writeLockFile = false }; diff --git a/src/nix/run.cc b/src/nix/run.cc index b5d8ab38a..f684c5ea4 100644 --- a/src/nix/run.cc +++ b/src/nix/run.cc @@ -178,9 +178,7 @@ struct CmdRun : InstallableCommand, RunCommon { auto state = getEvalState(); - auto app = installable->toApp(*state); - - state->store->buildPaths(toDerivedPaths(app.context)); + auto app = installable->toApp(*state).resolve(store); Strings allArgs{app.program}; for (auto & i : args) allArgs.push_back(i);