From bc23a44c54510c23dcbba030c39e8a1f3169c869 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Sat, 4 Feb 2023 12:03:47 -0500 Subject: [PATCH] Make command infra less stateful and more regular Already, we had classes like `BuiltPathsCommand` and `StorePathsCommand` which provided alternative `run` virtual functions providing the implementation with more arguments. This was a very nice and easy way to make writing command; just fill in the virtual functions and it is fairly clear what to do. However, exception to this pattern were `Installable{,s}Command`. These two classes instead just had a field where the installables would be stored, and various side-effecting `prepare` and `load` machinery too fill them in. Command would wish out those fields. This isn't so clear to use. What this commit does is make those command classes like the others, with richer `run` functions. Not only does this restore the pattern making commands easier to write, it has a number of other benefits: - `prepare` and `load` are gone entirely! One command just hands just hands off to the next. - `useDefaultInstallables` because `defaultInstallables`. This takes over `prepare` for the one case that needs it, and provides enough flexiblity to handle `nix repl`'s idiosyncratic migration. - We can use `ref` instead of `std::shared_ptr`. The former must be initialized (so it is like Rust's `Box` rather than `Option`, This expresses the invariant that the installable are in fact initialized much better. This is possible because since we just have local variables not fields, we can stop worrying about the not-yet-initialized case. - Fewer lines of code! (Finally I have a large refactor that makes the number go down not up...) - `nix repl` is now implemented in a clearer way. The last item deserves further mention. `nix repl` is not like the other installable commands because instead working from once-loaded installables, it needs to be able to load them again and again. To properly support this, we make a new superclass `RawInstallablesCommand`. This class has the argument parsing and completion logic, but does *not* hand off parsed installables but instead just the raw string arguments. This is exactly what `nix repl` needs, and allows us to instead of having the logic awkwardly split between `prepare`, `useDefaultInstallables,` and `load`, have everything right next to each other. I think this will enable future simplifications of that argument defaulting logic, but I am saving those for a future PR --- best to keep code motion and more complicated boolean expression rewriting separate steps. The "diagnostic ignored `-Woverloaded-virtual`" pragma helps because C++ doesn't like our many `run` methods. In our case, we don't mind the shadowing it all --- it is *intentional* that the derived class only provides a `run` method, and doesn't call any of the overridden `run` methods. Helps with https://github.com/NixOS/rfcs/pull/134 --- src/libcmd/command.cc | 6 +-- src/libcmd/command.hh | 54 +++++++++++---------- src/libcmd/installables.cc | 79 ++++++++++++++++++------------- src/libcmd/installables.hh | 19 ++++---- src/libutil/args.hh | 1 - src/nix/app.cc | 4 +- src/nix/build.cc | 2 +- src/nix/bundle.cc | 2 +- src/nix/copy.cc | 2 - src/nix/develop.cc | 19 ++++---- src/nix/edit.cc | 2 +- src/nix/eval.cc | 2 +- src/nix/flake.cc | 1 - src/nix/hash.cc | 1 - src/nix/log.cc | 2 +- src/nix/main.cc | 1 - src/nix/make-content-addressed.cc | 1 - src/nix/nar.cc | 1 - src/nix/profile.cc | 15 +++--- src/nix/realisation.cc | 1 - src/nix/registry.cc | 1 - src/nix/repl.cc | 41 ++++++++-------- src/nix/run.cc | 4 +- src/nix/search.cc | 2 +- src/nix/show-derivation.cc | 2 +- src/nix/sigs.cc | 1 - src/nix/store-copy-log.cc | 2 +- src/nix/store-delete.cc | 2 +- src/nix/store-repair.cc | 2 +- src/nix/store.cc | 1 - 30 files changed, 137 insertions(+), 136 deletions(-) diff --git a/src/libcmd/command.cc b/src/libcmd/command.cc index ab51c229dd6..bedf11e2c28 100644 --- a/src/libcmd/command.cc +++ b/src/libcmd/command.cc @@ -165,7 +165,7 @@ BuiltPathsCommand::BuiltPathsCommand(bool recursive) }); } -void BuiltPathsCommand::run(ref store) +void BuiltPathsCommand::run(ref store, Installables && installables) { BuiltPaths paths; if (all) { @@ -211,7 +211,7 @@ void StorePathsCommand::run(ref store, BuiltPaths && paths) run(store, std::move(sorted)); } -void StorePathCommand::run(ref store, std::vector && storePaths) +void StorePathCommand::run(ref store, StorePaths && storePaths) { if (storePaths.size() != 1) throw UsageError("this command requires exactly one store path"); @@ -246,7 +246,7 @@ void MixProfile::updateProfile(const BuiltPaths & buildables) { if (!profile) return; - std::vector result; + StorePaths result; for (auto & buildable : buildables) { std::visit(overloaded { diff --git a/src/libcmd/command.hh b/src/libcmd/command.hh index 0d84c8395af..874ca3249b4 100644 --- a/src/libcmd/command.hh +++ b/src/libcmd/command.hh @@ -29,6 +29,9 @@ struct NixMultiCommand : virtual MultiCommand, virtual Command nlohmann::json toJSON() override; }; +// For the overloaded run methods +#pragma GCC diagnostic ignored "-Woverloaded-virtual" + /* A command that requires a Nix store. */ struct StoreCommand : virtual Command { @@ -97,10 +100,10 @@ struct SourceExprCommand : virtual Args, MixFlakeOptions SourceExprCommand(); - std::vector> parseInstallables( + Installables parseInstallables( ref store, std::vector ss); - std::shared_ptr parseInstallable( + ref parseInstallable( ref store, const std::string & installable); virtual Strings getDefaultFlakeAttrPaths(); @@ -115,36 +118,43 @@ struct MixReadOnlyOption : virtual Args MixReadOnlyOption(); }; -/* A command that operates on a list of "installables", which can be - store paths, attribute paths, Nix expressions, etc. */ -struct InstallablesCommand : virtual Args, SourceExprCommand +/* Like InstallablesCommand but the installables are not loaded */ +struct RawInstallablesCommand : virtual Args, SourceExprCommand { - std::vector> installables; + RawInstallablesCommand(); - InstallablesCommand(); + virtual void run(ref store, std::vector && rawInstallables) = 0; - void prepare() override; - Installables load(); + void run(ref store) override; - virtual bool useDefaultInstallables() { return true; } + // FIXME make const after CmdRepl's override is fixed up + virtual void applyDefaultInstallables(std::vector & rawInstallables); bool readFromStdIn = false; std::vector getFlakesForCompletion() override; -protected: +private: + + std::vector rawInstallables; +}; +/* A command that operates on a list of "installables", which can be + store paths, attribute paths, Nix expressions, etc. */ +struct InstallablesCommand : RawInstallablesCommand +{ + virtual void run(ref store, Installables && installables) = 0; - std::vector _installables; + void run(ref store, std::vector && rawInstallables) override; }; /* A command that operates on exactly one "installable" */ struct InstallableCommand : virtual Args, SourceExprCommand { - std::shared_ptr installable; - InstallableCommand(); - void prepare() override; + virtual void run(ref store, ref installable) = 0; + + void run(ref store) override; std::vector getFlakesForCompletion() override { @@ -179,22 +189,18 @@ public: BuiltPathsCommand(bool recursive = false); - using StoreCommand::run; - virtual void run(ref store, BuiltPaths && paths) = 0; - void run(ref store) override; + void run(ref store, Installables && installables) override; - bool useDefaultInstallables() override { return !all; } + void applyDefaultInstallables(std::vector & rawInstallables) override; }; struct StorePathsCommand : public BuiltPathsCommand { StorePathsCommand(bool recursive = false); - using BuiltPathsCommand::run; - - virtual void run(ref store, std::vector && storePaths) = 0; + virtual void run(ref store, StorePaths && storePaths) = 0; void run(ref store, BuiltPaths && paths) override; }; @@ -202,11 +208,9 @@ struct StorePathsCommand : public BuiltPathsCommand /* A command that operates on exactly one store path. */ struct StorePathCommand : public StorePathsCommand { - using StorePathsCommand::run; - virtual void run(ref store, const StorePath & storePath) = 0; - void run(ref store, std::vector && storePaths) override; + void run(ref store, StorePaths && storePaths) override; }; /* A helper class for registering commands globally. */ diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 5ecf6293ffb..5cbf26b88ae 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -422,10 +422,10 @@ ref openEvalCache( }); } -std::vector> SourceExprCommand::parseInstallables( +Installables SourceExprCommand::parseInstallables( ref store, std::vector ss) { - std::vector> result; + Installables result; if (file || expr) { if (file && expr) @@ -451,7 +451,7 @@ std::vector> SourceExprCommand::parseInstallables( for (auto & s : ss) { auto [prefix, extendedOutputsSpec] = ExtendedOutputsSpec::parse(s); result.push_back( - std::make_shared( + make_ref( InstallableAttrPath::parse( state, *this, vFile, prefix, extendedOutputsSpec))); } @@ -468,7 +468,7 @@ std::vector> SourceExprCommand::parseInstallables( if (prefix.find('/') != std::string::npos) { try { - result.push_back(std::make_shared( + result.push_back(make_ref( InstallableDerivedPath::parse(store, prefix, extendedOutputsSpec))); continue; } catch (BadStorePath &) { @@ -480,7 +480,7 @@ std::vector> SourceExprCommand::parseInstallables( try { auto [flakeRef, fragment] = parseFlakeRefWithFragment(std::string { prefix }, absPath(".")); - result.push_back(std::make_shared( + result.push_back(make_ref( this, getEvalState(), std::move(flakeRef), @@ -501,7 +501,7 @@ std::vector> SourceExprCommand::parseInstallables( return result; } -std::shared_ptr SourceExprCommand::parseInstallable( +ref SourceExprCommand::parseInstallable( ref store, const std::string & installable) { auto installables = parseInstallables(store, {installable}); @@ -513,7 +513,7 @@ std::vector Installable::build( ref evalStore, ref store, Realise mode, - const std::vector> & installables, + const Installables & installables, BuildMode bMode) { std::vector res; @@ -522,11 +522,11 @@ std::vector Installable::build( return res; } -std::vector, BuiltPathWithResult>> Installable::build2( +std::vector, BuiltPathWithResult>> Installable::build2( ref evalStore, ref store, Realise mode, - const std::vector> & installables, + const Installables & installables, BuildMode bMode) { if (mode == Realise::Nothing) @@ -535,7 +535,7 @@ std::vector, BuiltPathWithResult>> Instal struct Aux { ExtraPathInfo info; - std::shared_ptr installable; + ref installable; }; std::vector pathsToBuild; @@ -548,7 +548,7 @@ std::vector, BuiltPathWithResult>> Instal } } - std::vector, BuiltPathWithResult>> res; + std::vector, BuiltPathWithResult>> res; switch (mode) { @@ -620,7 +620,7 @@ BuiltPaths Installable::toBuiltPaths( ref store, Realise mode, OperateOn operateOn, - const std::vector> & installables) + const Installables & installables) { if (operateOn == OperateOn::Output) { BuiltPaths res; @@ -642,7 +642,7 @@ StorePathSet Installable::toStorePaths( ref evalStore, ref store, Realise mode, OperateOn operateOn, - const std::vector> & installables) + const Installables & installables) { StorePathSet outPaths; for (auto & path : toBuiltPaths(evalStore, store, mode, operateOn, installables)) { @@ -656,7 +656,7 @@ StorePath Installable::toStorePath( ref evalStore, ref store, Realise mode, OperateOn operateOn, - std::shared_ptr installable) + ref installable) { auto paths = toStorePaths(evalStore, store, mode, operateOn, {installable}); @@ -668,7 +668,7 @@ StorePath Installable::toStorePath( StorePathSet Installable::toDerivations( ref store, - const std::vector> & installables, + const Installables & installables, bool useDeriver) { StorePathSet drvPaths; @@ -692,9 +692,8 @@ StorePathSet Installable::toDerivations( return drvPaths; } -InstallablesCommand::InstallablesCommand() +RawInstallablesCommand::RawInstallablesCommand() { - addFlag({ .longName = "stdin", .description = "Read installables from the standard input.", @@ -703,40 +702,45 @@ InstallablesCommand::InstallablesCommand() expectArgs({ .label = "installables", - .handler = {&_installables}, + .handler = {&rawInstallables}, .completer = {[&](size_t, std::string_view prefix) { completeInstallable(prefix); }} }); } -void InstallablesCommand::prepare() -{ - installables = load(); -} - -Installables InstallablesCommand::load() +void RawInstallablesCommand::applyDefaultInstallables(std::vector & rawInstallables) { - if (_installables.empty() && useDefaultInstallables() && !readFromStdIn) + if (rawInstallables.empty()) { // FIXME: commands like "nix profile install" should not have a // default, probably. - _installables.push_back("."); + rawInstallables.push_back("."); + } +} +void RawInstallablesCommand::run(ref store) +{ if (readFromStdIn && !isatty(STDIN_FILENO)) { std::string word; while (std::cin >> word) { - _installables.emplace_back(std::move(word)); + rawInstallables.emplace_back(std::move(word)); } } - return parseInstallables(getStore(), _installables); + applyDefaultInstallables(rawInstallables); + run(store, std::move(rawInstallables)); } -std::vector InstallablesCommand::getFlakesForCompletion() +std::vector RawInstallablesCommand::getFlakesForCompletion() { - if (_installables.empty() && useDefaultInstallables()) - return {"."}; - return _installables; + applyDefaultInstallables(rawInstallables); + return rawInstallables; +} + +void InstallablesCommand::run(ref store, std::vector && rawInstallables) +{ + auto installables = parseInstallables(store, rawInstallables); + run(store, std::move(installables)); } InstallableCommand::InstallableCommand() @@ -752,9 +756,16 @@ InstallableCommand::InstallableCommand() }); } -void InstallableCommand::prepare() +void InstallableCommand::run(ref store) +{ + auto installable = parseInstallable(store, _installable); + run(store, std::move(installable)); +} + +void BuiltPathsCommand::applyDefaultInstallables(std::vector & rawInstallables) { - installable = parseInstallable(getStore(), _installable); + if (rawInstallables.empty() && !all) + rawInstallables.push_back("."); } } diff --git a/src/libcmd/installables.hh b/src/libcmd/installables.hh index be77fdc81ac..6c2922d89d7 100644 --- a/src/libcmd/installables.hh +++ b/src/libcmd/installables.hh @@ -79,6 +79,9 @@ struct BuiltPathWithResult typedef std::vector DerivedPathsWithInfo; +struct Installable; +typedef std::vector> Installables; + struct Installable { virtual ~Installable() { } @@ -122,14 +125,14 @@ struct Installable ref evalStore, ref store, Realise mode, - const std::vector> & installables, + const Installables & installables, BuildMode bMode = bmNormal); - static std::vector, BuiltPathWithResult>> build2( + static std::vector, BuiltPathWithResult>> build2( ref evalStore, ref store, Realise mode, - const std::vector> & installables, + const Installables & installables, BuildMode bMode = bmNormal); static std::set toStorePaths( @@ -137,18 +140,18 @@ struct Installable ref store, Realise mode, OperateOn operateOn, - const std::vector> & installables); + const Installables & installables); static StorePath toStorePath( ref evalStore, ref store, Realise mode, OperateOn operateOn, - std::shared_ptr installable); + ref installable); static std::set toDerivations( ref store, - const std::vector> & installables, + const Installables & installables, bool useDeriver = false); static BuiltPaths toBuiltPaths( @@ -156,9 +159,7 @@ struct Installable ref store, Realise mode, OperateOn operateOn, - const std::vector> & installables); + const Installables & installables); }; -typedef std::vector> Installables; - } diff --git a/src/libutil/args.hh b/src/libutil/args.hh index 84866f12b4a..7211ee307b1 100644 --- a/src/libutil/args.hh +++ b/src/libutil/args.hh @@ -198,7 +198,6 @@ struct Command : virtual public Args virtual ~Command() { } - virtual void prepare() { }; virtual void run() = 0; typedef int Category; diff --git a/src/nix/app.cc b/src/nix/app.cc index 5cd65136f53..bfd75e27889 100644 --- a/src/nix/app.cc +++ b/src/nix/app.cc @@ -119,11 +119,11 @@ App UnresolvedApp::resolve(ref evalStore, ref store) { auto res = unresolved; - std::vector> installableContext; + Installables installableContext; for (auto & ctxElt : unresolved.context) installableContext.push_back( - std::make_shared(store, DerivedPath { ctxElt })); + make_ref(store, DerivedPath { ctxElt })); auto builtContext = Installable::build(evalStore, store, Realise::Outputs, installableContext); res.program = resolveString(*store, unresolved.program, builtContext); diff --git a/src/nix/build.cc b/src/nix/build.cc index f4f2ec81dbb..f8593135e68 100644 --- a/src/nix/build.cc +++ b/src/nix/build.cc @@ -89,7 +89,7 @@ struct CmdBuild : InstallablesCommand, MixDryRun, MixJSON, MixProfile ; } - void run(ref store) override + void run(ref store, Installables && installables) override { if (dryRun) { std::vector pathsToBuild; diff --git a/src/nix/bundle.cc b/src/nix/bundle.cc index dcf9a6f2d1f..973bbd42334 100644 --- a/src/nix/bundle.cc +++ b/src/nix/bundle.cc @@ -70,7 +70,7 @@ struct CmdBundle : InstallableCommand return res; } - void run(ref store) override + void run(ref store, ref installable) override { auto evalState = getEvalState(); diff --git a/src/nix/copy.cc b/src/nix/copy.cc index 8730a9a5c33..151d282772f 100644 --- a/src/nix/copy.cc +++ b/src/nix/copy.cc @@ -10,8 +10,6 @@ struct CmdCopy : virtual CopyCommand, virtual BuiltPathsCommand SubstituteFlag substitute = NoSubstitute; - using BuiltPathsCommand::run; - CmdCopy() : BuiltPathsCommand(true) { diff --git a/src/nix/develop.cc b/src/nix/develop.cc index 0ee533e85bc..f06ade00896 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -374,7 +374,7 @@ struct Common : InstallableCommand, MixProfile return res; } - StorePath getShellOutPath(ref store) + StorePath getShellOutPath(ref store, ref installable) { auto path = installable->getStorePath(); if (path && hasSuffix(path->to_string(), "-env")) @@ -392,9 +392,10 @@ struct Common : InstallableCommand, MixProfile } } - std::pair getBuildEnvironment(ref store) + std::pair + getBuildEnvironment(ref store, ref installable) { - auto shellOutPath = getShellOutPath(store); + auto shellOutPath = getShellOutPath(store, installable); auto strPath = store->printStorePath(shellOutPath); @@ -480,9 +481,9 @@ struct CmdDevelop : Common, MixEnvironment ; } - void run(ref store) override + void run(ref store, ref installable) override { - auto [buildEnvironment, gcroot] = getBuildEnvironment(store); + auto [buildEnvironment, gcroot] = getBuildEnvironment(store, installable); auto [rcFileFd, rcFilePath] = createTempFile("nix-shell"); @@ -537,7 +538,7 @@ struct CmdDevelop : Common, MixEnvironment nixpkgsLockFlags.inputOverrides = {}; nixpkgsLockFlags.inputUpdates = {}; - auto bashInstallable = std::make_shared( + auto bashInstallable = make_ref( this, state, installable->nixpkgsFlakeRef(), @@ -573,7 +574,7 @@ struct CmdDevelop : Common, MixEnvironment // Need to chdir since phases assume in flake directory if (phase) { // chdir if installable is a flake of type git+file or path - auto installableFlake = std::dynamic_pointer_cast(installable); + auto installableFlake = installable.dynamic_pointer_cast(); if (installableFlake) { auto sourcePath = installableFlake->getLockedFlake()->flake.resolvedRef.input.getSourcePath(); if (sourcePath) { @@ -604,9 +605,9 @@ struct CmdPrintDevEnv : Common, MixJSON Category category() override { return catUtility; } - void run(ref store) override + void run(ref store, ref installable) override { - auto buildEnvironment = getBuildEnvironment(store).first; + auto buildEnvironment = getBuildEnvironment(store, installable).first; stopProgressBar(); diff --git a/src/nix/edit.cc b/src/nix/edit.cc index dfe75fbdf92..c46c1c23c39 100644 --- a/src/nix/edit.cc +++ b/src/nix/edit.cc @@ -25,7 +25,7 @@ struct CmdEdit : InstallableCommand Category category() override { return catSecondary; } - void run(ref store) override + void run(ref store, ref installable) override { auto state = getEvalState(); diff --git a/src/nix/eval.cc b/src/nix/eval.cc index 209fd3ed2e2..6c2b604276f 100644 --- a/src/nix/eval.cc +++ b/src/nix/eval.cc @@ -54,7 +54,7 @@ struct CmdEval : MixJSON, InstallableCommand, MixReadOnlyOption Category category() override { return catSecondary; } - void run(ref store) override + void run(ref store, ref installable) override { if (raw && json) throw UsageError("--raw and --json are mutually exclusive"); diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 3fe093fc7fd..0a66163962c 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -1329,7 +1329,6 @@ struct CmdFlake : NixMultiCommand if (!command) throw UsageError("'nix flake' requires a sub-command."); settings.requireExperimentalFeature(Xp::Flakes); - command->second->prepare(); command->second->run(); } }; diff --git a/src/nix/hash.cc b/src/nix/hash.cc index 60d9593a772..6d95c04553d 100644 --- a/src/nix/hash.cc +++ b/src/nix/hash.cc @@ -151,7 +151,6 @@ struct CmdHash : NixMultiCommand { if (!command) throw UsageError("'nix hash' requires a sub-command."); - command->second->prepare(); command->second->run(); } }; diff --git a/src/nix/log.cc b/src/nix/log.cc index 0c9f778f0e0..aaf82976404 100644 --- a/src/nix/log.cc +++ b/src/nix/log.cc @@ -23,7 +23,7 @@ struct CmdLog : InstallableCommand Category category() override { return catSecondary; } - void run(ref store) override + void run(ref store, ref installable) override { settings.readOnlyMode = true; diff --git a/src/nix/main.cc b/src/nix/main.cc index 53bf649d445..7b715f28101 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -394,7 +394,6 @@ void mainWrapped(int argc, char * * argv) if (args.command->second->forceImpureByDefault() && !evalSettings.pureEval.overridden) { evalSettings.pureEval = false; } - args.command->second->prepare(); args.command->second->run(); } diff --git a/src/nix/make-content-addressed.cc b/src/nix/make-content-addressed.cc index 6693c55acec..d9c988a9f5d 100644 --- a/src/nix/make-content-addressed.cc +++ b/src/nix/make-content-addressed.cc @@ -28,7 +28,6 @@ struct CmdMakeContentAddressed : virtual CopyCommand, virtual StorePathsCommand, ; } - using StorePathsCommand::run; void run(ref srcStore, StorePaths && storePaths) override { auto dstStore = dstUri.empty() ? openStore() : openStore(dstUri); diff --git a/src/nix/nar.cc b/src/nix/nar.cc index dbb043d9b9d..9815410cfc0 100644 --- a/src/nix/nar.cc +++ b/src/nix/nar.cc @@ -25,7 +25,6 @@ struct CmdNar : NixMultiCommand { if (!command) throw UsageError("'nix nar' requires a sub-command."); - command->second->prepare(); command->second->run(); } }; diff --git a/src/nix/profile.cc b/src/nix/profile.cc index eef33b3d916..d72dd1a136c 100644 --- a/src/nix/profile.cc +++ b/src/nix/profile.cc @@ -256,11 +256,11 @@ struct ProfileManifest static std::map> builtPathsPerInstallable( - const std::vector, BuiltPathWithResult>> & builtPaths) + const std::vector, BuiltPathWithResult>> & builtPaths) { std::map> res; for (auto & [installable, builtPath] : builtPaths) { - auto & r = res[installable.get()]; + auto & r = res[&*installable]; /* Note that there could be conflicting info (e.g. meta.priority fields) if the installable returned multiple derivations. So pick one arbitrarily. FIXME: @@ -296,7 +296,7 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile ; } - void run(ref store) override + void run(ref store, Installables && installables) override { ProfileManifest manifest(*getEvalState(), *profile); @@ -307,7 +307,7 @@ struct CmdProfileInstall : InstallablesCommand, MixDefaultProfile for (auto & installable : installables) { ProfileElement element; - auto & [res, info] = builtPaths[installable.get()]; + auto & [res, info] = builtPaths[&*installable]; if (info.originalRef && info.resolvedRef && info.attrPath && info.extendedOutputsSpec) { element.source = ProfileElementSource { @@ -513,7 +513,7 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf auto matchers = getMatchers(store); - std::vector> installables; + Installables installables; std::vector indices; auto upgradedCount = 0; @@ -529,7 +529,7 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf Activity act(*logger, lvlChatty, actUnknown, fmt("checking '%s' for updates", element.source->attrPath)); - auto installable = std::make_shared( + auto installable = make_ref( this, getEvalState(), FlakeRef(element.source->originalRef), @@ -582,7 +582,7 @@ struct CmdProfileUpgrade : virtual SourceExprCommand, MixDefaultProfile, MixProf for (size_t i = 0; i < installables.size(); ++i) { auto & installable = installables.at(i); auto & element = manifest.elements[indices.at(i)]; - element.updateStorePaths(getEvalStore(), store, builtPaths[installable.get()].first); + element.updateStorePaths(getEvalStore(), store, builtPaths[&*installable].first); } updateProfile(manifest.build(store)); @@ -798,7 +798,6 @@ struct CmdProfile : NixMultiCommand { if (!command) throw UsageError("'nix profile' requires a sub-command."); - command->second->prepare(); command->second->run(); } }; diff --git a/src/nix/realisation.cc b/src/nix/realisation.cc index 0d34665154d..13db8028296 100644 --- a/src/nix/realisation.cc +++ b/src/nix/realisation.cc @@ -21,7 +21,6 @@ struct CmdRealisation : virtual NixMultiCommand { if (!command) throw UsageError("'nix realisation' requires a sub-command."); - command->second->prepare(); command->second->run(); } }; diff --git a/src/nix/registry.cc b/src/nix/registry.cc index b5bdfba9517..1f4f820aca5 100644 --- a/src/nix/registry.cc +++ b/src/nix/registry.cc @@ -227,7 +227,6 @@ struct CmdRegistry : virtual NixMultiCommand settings.requireExperimentalFeature(Xp::Flakes); if (!command) throw UsageError("'nix registry' requires a sub-command."); - command->second->prepare(); command->second->run(); } }; diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 679bdea7781..51d3074b4bb 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -5,26 +5,12 @@ namespace nix { -struct CmdRepl : InstallablesCommand +struct CmdRepl : RawInstallablesCommand { CmdRepl() { evalSettings.pureEval = false; } - void prepare() override - { - if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && this->_installables.size() >= 1) { - warn("future versions of Nix will require using `--file` to load a file"); - if (this->_installables.size() > 1) - warn("more than one input file is not currently supported"); - auto filePath = this->_installables[0].data(); - file = std::optional(filePath); - _installables.front() = _installables.back(); - _installables.pop_back(); - } - installables = InstallablesCommand::load(); - } - std::vector files; Strings getDefaultFlakeAttrPaths() override @@ -32,11 +18,6 @@ struct CmdRepl : InstallablesCommand return {""}; } - bool useDefaultInstallables() override - { - return file.has_value() or expr.has_value(); - } - bool forceImpureByDefault() override { return true; @@ -54,11 +35,27 @@ struct CmdRepl : InstallablesCommand ; } - void run(ref store) override + void applyDefaultInstallables(std::vector & rawInstallables) override + { + if (!settings.isExperimentalFeatureEnabled(Xp::ReplFlake) && !(file) && rawInstallables.size() >= 1) { + warn("future versions of Nix will require using `--file` to load a file"); + if (rawInstallables.size() > 1) + warn("more than one input file is not currently supported"); + auto filePath = rawInstallables[0].data(); + file = std::optional(filePath); + rawInstallables.front() = rawInstallables.back(); + rawInstallables.pop_back(); + } + if (rawInstallables.empty() && (file.has_value() || expr.has_value())) { + rawInstallables.push_back("."); + } + } + + void run(ref store, std::vector && rawInstallables) override { auto state = getEvalState(); auto getValues = [&]()->AbstractNixRepl::AnnotatedValues{ - auto installables = load(); + auto installables = parseInstallables(store, rawInstallables); AbstractNixRepl::AnnotatedValues values; for (auto & installable: installables){ auto what = installable->what(); diff --git a/src/nix/run.cc b/src/nix/run.cc index 6fca6804794..56605d9d530 100644 --- a/src/nix/run.cc +++ b/src/nix/run.cc @@ -97,7 +97,7 @@ struct CmdShell : InstallablesCommand, MixEnvironment ; } - void run(ref store) override + void run(ref store, Installables && installables) override { auto outPaths = Installable::toStorePaths(getEvalStore(), store, Realise::Outputs, OperateOn::Output, installables); @@ -183,7 +183,7 @@ struct CmdRun : InstallableCommand return res; } - void run(ref store) override + void run(ref store, ref installable) override { auto state = getEvalState(); diff --git a/src/nix/search.cc b/src/nix/search.cc index 2e38f7e4b9a..994ec44c2e6 100644 --- a/src/nix/search.cc +++ b/src/nix/search.cc @@ -61,7 +61,7 @@ struct CmdSearch : InstallableCommand, MixJSON }; } - void run(ref store) override + void run(ref store, ref installable) override { settings.readOnlyMode = true; evalSettings.enableImportFromDerivation.setDefault(false); diff --git a/src/nix/show-derivation.cc b/src/nix/show-derivation.cc index 520e8b1ce4b..4a406ae08cd 100644 --- a/src/nix/show-derivation.cc +++ b/src/nix/show-derivation.cc @@ -39,7 +39,7 @@ struct CmdShowDerivation : InstallablesCommand Category category() override { return catUtility; } - void run(ref store) override + void run(ref store, Installables && installables) override { auto drvPaths = Installable::toDerivations(store, installables, true); diff --git a/src/nix/sigs.cc b/src/nix/sigs.cc index 1431652e01c..45cd2e1a6c2 100644 --- a/src/nix/sigs.cc +++ b/src/nix/sigs.cc @@ -219,7 +219,6 @@ struct CmdKey : NixMultiCommand { if (!command) throw UsageError("'nix key' requires a sub-command."); - command->second->prepare(); command->second->run(); } }; diff --git a/src/nix/store-copy-log.cc b/src/nix/store-copy-log.cc index d5fab5f2f38..1dda8c0b8f7 100644 --- a/src/nix/store-copy-log.cc +++ b/src/nix/store-copy-log.cc @@ -26,7 +26,7 @@ struct CmdCopyLog : virtual CopyCommand, virtual InstallablesCommand Category category() override { return catUtility; } - void run(ref srcStore) override + void run(ref srcStore, Installables && installables) override { auto & srcLogStore = require(*srcStore); diff --git a/src/nix/store-delete.cc b/src/nix/store-delete.cc index ca43f1530ee..6719227dfe7 100644 --- a/src/nix/store-delete.cc +++ b/src/nix/store-delete.cc @@ -32,7 +32,7 @@ struct CmdStoreDelete : StorePathsCommand ; } - void run(ref store, std::vector && storePaths) override + void run(ref store, StorePaths && storePaths) override { auto & gcStore = require(*store); diff --git a/src/nix/store-repair.cc b/src/nix/store-repair.cc index 8fcb3639a43..895e3968507 100644 --- a/src/nix/store-repair.cc +++ b/src/nix/store-repair.cc @@ -17,7 +17,7 @@ struct CmdStoreRepair : StorePathsCommand ; } - void run(ref store, std::vector && storePaths) override + void run(ref store, StorePaths && storePaths) override { for (auto & path : storePaths) store->repairPath(path); diff --git a/src/nix/store.cc b/src/nix/store.cc index 44e53c7c758..2879e03b350 100644 --- a/src/nix/store.cc +++ b/src/nix/store.cc @@ -18,7 +18,6 @@ struct CmdStore : virtual NixMultiCommand { if (!command) throw UsageError("'nix store' requires a sub-command."); - command->second->prepare(); command->second->run(); } };