diff --git a/src/nix/command.cc b/src/nix/command.cc index a4faccb6d..af36dda89 100644 --- a/src/nix/command.cc +++ b/src/nix/command.cc @@ -63,7 +63,7 @@ void StorePathsCommand::run(ref store) } else { - for (auto & p : toStorePaths(store, realiseMode, installables)) + for (auto & p : toStorePaths(store, realiseMode, operateOn, installables)) storePaths.push_back(p); if (recursive) { @@ -80,7 +80,7 @@ void StorePathsCommand::run(ref store) void StorePathCommand::run(ref store) { - auto storePaths = toStorePaths(store, Realise::Nothing, installables); + auto storePaths = toStorePaths(store, Realise::Nothing, operateOn, installables); if (storePaths.size() != 1) throw UsageError("this command requires exactly one store path"); diff --git a/src/nix/command.hh b/src/nix/command.hh index 5fa8f9333..1c7413300 100644 --- a/src/nix/command.hh +++ b/src/nix/command.hh @@ -50,11 +50,22 @@ struct MixFlakeOptions : virtual Args, EvalCommand { return {}; } }; +/* How to handle derivations in commands that operate on store paths. */ +enum class OperateOn { + /* Operate on the output path. */ + Output, + /* Operate on the .drv path. */ + Derivation +}; + struct SourceExprCommand : virtual Args, MixFlakeOptions { std::optional file; std::optional expr; + // FIXME: move this; not all commands (e.g. 'nix run') use it. + OperateOn operateOn = OperateOn::Output; + SourceExprCommand(); std::vector> parseInstallables( @@ -176,10 +187,12 @@ static RegisterCommand registerCommand(const std::string & name) Buildables build(ref store, Realise mode, std::vector> installables); -std::set toStorePaths(ref store, Realise mode, +std::set toStorePaths(ref store, + Realise mode, OperateOn operateOn, std::vector> installables); -StorePath toStorePath(ref store, Realise mode, +StorePath toStorePath(ref store, + Realise mode, OperateOn operateOn, std::shared_ptr installable); std::set toDerivations(ref store, diff --git a/src/nix/develop.cc b/src/nix/develop.cc index bf4890e95..a6d7d6add 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -321,7 +321,8 @@ struct CmdDevelop : Common, MixEnvironment Strings{"legacyPackages." + settings.thisSystem.get() + "."}, lockFlags); - shell = state->store->printStorePath(toStorePath(state->store, Realise::Outputs, bashInstallable)) + "/bin/bash"; + shell = state->store->printStorePath( + toStorePath(state->store, Realise::Outputs, OperateOn::Output, bashInstallable)) + "/bin/bash"; } catch (Error &) { ignoreException(); } diff --git a/src/nix/installables.cc b/src/nix/installables.cc index d464efc35..a13e5a3df 100644 --- a/src/nix/installables.cc +++ b/src/nix/installables.cc @@ -128,6 +128,12 @@ SourceExprCommand::SourceExprCommand() .labels = {"expr"}, .handler = {&expr} }); + + addFlag({ + .longName ="derivation", + .description = "operate on the store derivation rather than its outputs", + .handler = {&operateOn, OperateOn::Derivation}, + }); } Strings SourceExprCommand::getDefaultFlakeAttrPaths() @@ -667,22 +673,34 @@ Buildables build(ref store, Realise mode, return buildables; } -StorePathSet toStorePaths(ref store, Realise mode, +StorePathSet toStorePaths(ref store, + Realise mode, OperateOn operateOn, std::vector> installables) { StorePathSet outPaths; - for (auto & b : build(store, mode, installables)) - for (auto & output : b.outputs) - outPaths.insert(output.second); + if (operateOn == OperateOn::Output) { + for (auto & b : build(store, mode, installables)) + for (auto & output : b.outputs) + outPaths.insert(output.second); + } else { + if (mode == Realise::Nothing) + settings.readOnlyMode = true; + + for (auto & i : installables) + for (auto & b : i->toBuildables()) + if (b.drvPath) + outPaths.insert(*b.drvPath); + } return outPaths; } -StorePath toStorePath(ref store, Realise mode, +StorePath toStorePath(ref store, + Realise mode, OperateOn operateOn, std::shared_ptr installable) { - auto paths = toStorePaths(store, mode, {installable}); + auto paths = toStorePaths(store, mode, operateOn, {installable}); if (paths.size() != 1) throw Error("argument '%s' should evaluate to one store path", installable->what()); diff --git a/src/nix/run.cc b/src/nix/run.cc index a27538085..cbaba9d90 100644 --- a/src/nix/run.cc +++ b/src/nix/run.cc @@ -104,7 +104,7 @@ struct CmdShell : InstallablesCommand, RunCommon, MixEnvironment void run(ref store) override { - auto outPaths = toStorePaths(store, Realise::Outputs, installables); + auto outPaths = toStorePaths(store, Realise::Outputs, OperateOn::Output, installables); auto accessor = store->getFSAccessor(); diff --git a/src/nix/why-depends.cc b/src/nix/why-depends.cc index 55bb43f95..f854bedb2 100644 --- a/src/nix/why-depends.cc +++ b/src/nix/why-depends.cc @@ -73,9 +73,9 @@ struct CmdWhyDepends : SourceExprCommand void run(ref store) override { auto package = parseInstallable(store, _package); - auto packagePath = toStorePath(store, Realise::Outputs, package); + auto packagePath = toStorePath(store, Realise::Outputs, operateOn, package); auto dependency = parseInstallable(store, _dependency); - auto dependencyPath = toStorePath(store, Realise::Derivation, dependency); + auto dependencyPath = toStorePath(store, Realise::Derivation, operateOn, dependency); auto dependencyPathHash = dependencyPath.hashPart(); StorePathSet closure;