nix: Add --derivation flag to operate on .drv paths

For instance, 'nix why-depends --use-derivation nixpkgs#hello
nixpkgs#glibc' shows why hello's .drv depends on glibc's .drv.
This commit is contained in:
Eelco Dolstra 2020-07-15 20:22:52 +02:00
parent dfe8f3ebc6
commit 3624c042ac
6 changed files with 46 additions and 14 deletions

View file

@ -63,7 +63,7 @@ void StorePathsCommand::run(ref<Store> store)
} }
else { else {
for (auto & p : toStorePaths(store, realiseMode, installables)) for (auto & p : toStorePaths(store, realiseMode, operateOn, installables))
storePaths.push_back(p); storePaths.push_back(p);
if (recursive) { if (recursive) {
@ -80,7 +80,7 @@ void StorePathsCommand::run(ref<Store> store)
void StorePathCommand::run(ref<Store> store) void StorePathCommand::run(ref<Store> store)
{ {
auto storePaths = toStorePaths(store, Realise::Nothing, installables); auto storePaths = toStorePaths(store, Realise::Nothing, operateOn, installables);
if (storePaths.size() != 1) if (storePaths.size() != 1)
throw UsageError("this command requires exactly one store path"); throw UsageError("this command requires exactly one store path");

View file

@ -50,11 +50,22 @@ struct MixFlakeOptions : virtual Args, EvalCommand
{ return {}; } { 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 struct SourceExprCommand : virtual Args, MixFlakeOptions
{ {
std::optional<Path> file; std::optional<Path> file;
std::optional<std::string> expr; std::optional<std::string> expr;
// FIXME: move this; not all commands (e.g. 'nix run') use it.
OperateOn operateOn = OperateOn::Output;
SourceExprCommand(); SourceExprCommand();
std::vector<std::shared_ptr<Installable>> parseInstallables( std::vector<std::shared_ptr<Installable>> parseInstallables(
@ -176,10 +187,12 @@ static RegisterCommand registerCommand(const std::string & name)
Buildables build(ref<Store> store, Realise mode, Buildables build(ref<Store> store, Realise mode,
std::vector<std::shared_ptr<Installable>> installables); std::vector<std::shared_ptr<Installable>> installables);
std::set<StorePath> toStorePaths(ref<Store> store, Realise mode, std::set<StorePath> toStorePaths(ref<Store> store,
Realise mode, OperateOn operateOn,
std::vector<std::shared_ptr<Installable>> installables); std::vector<std::shared_ptr<Installable>> installables);
StorePath toStorePath(ref<Store> store, Realise mode, StorePath toStorePath(ref<Store> store,
Realise mode, OperateOn operateOn,
std::shared_ptr<Installable> installable); std::shared_ptr<Installable> installable);
std::set<StorePath> toDerivations(ref<Store> store, std::set<StorePath> toDerivations(ref<Store> store,

View file

@ -321,7 +321,8 @@ struct CmdDevelop : Common, MixEnvironment
Strings{"legacyPackages." + settings.thisSystem.get() + "."}, Strings{"legacyPackages." + settings.thisSystem.get() + "."},
lockFlags); 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 &) { } catch (Error &) {
ignoreException(); ignoreException();
} }

View file

@ -128,6 +128,12 @@ SourceExprCommand::SourceExprCommand()
.labels = {"expr"}, .labels = {"expr"},
.handler = {&expr} .handler = {&expr}
}); });
addFlag({
.longName ="derivation",
.description = "operate on the store derivation rather than its outputs",
.handler = {&operateOn, OperateOn::Derivation},
});
} }
Strings SourceExprCommand::getDefaultFlakeAttrPaths() Strings SourceExprCommand::getDefaultFlakeAttrPaths()
@ -667,22 +673,34 @@ Buildables build(ref<Store> store, Realise mode,
return buildables; return buildables;
} }
StorePathSet toStorePaths(ref<Store> store, Realise mode, StorePathSet toStorePaths(ref<Store> store,
Realise mode, OperateOn operateOn,
std::vector<std::shared_ptr<Installable>> installables) std::vector<std::shared_ptr<Installable>> installables)
{ {
StorePathSet outPaths; StorePathSet outPaths;
for (auto & b : build(store, mode, installables)) if (operateOn == OperateOn::Output) {
for (auto & output : b.outputs) for (auto & b : build(store, mode, installables))
outPaths.insert(output.second); 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; return outPaths;
} }
StorePath toStorePath(ref<Store> store, Realise mode, StorePath toStorePath(ref<Store> store,
Realise mode, OperateOn operateOn,
std::shared_ptr<Installable> installable) std::shared_ptr<Installable> installable)
{ {
auto paths = toStorePaths(store, mode, {installable}); auto paths = toStorePaths(store, mode, operateOn, {installable});
if (paths.size() != 1) if (paths.size() != 1)
throw Error("argument '%s' should evaluate to one store path", installable->what()); throw Error("argument '%s' should evaluate to one store path", installable->what());

View file

@ -104,7 +104,7 @@ struct CmdShell : InstallablesCommand, RunCommon, MixEnvironment
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
auto outPaths = toStorePaths(store, Realise::Outputs, installables); auto outPaths = toStorePaths(store, Realise::Outputs, OperateOn::Output, installables);
auto accessor = store->getFSAccessor(); auto accessor = store->getFSAccessor();

View file

@ -73,9 +73,9 @@ struct CmdWhyDepends : SourceExprCommand
void run(ref<Store> store) override void run(ref<Store> store) override
{ {
auto package = parseInstallable(store, _package); 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 dependency = parseInstallable(store, _dependency);
auto dependencyPath = toStorePath(store, Realise::Derivation, dependency); auto dependencyPath = toStorePath(store, Realise::Derivation, operateOn, dependency);
auto dependencyPathHash = dependencyPath.hashPart(); auto dependencyPathHash = dependencyPath.hashPart();
StorePathSet closure; StorePathSet closure;