From 7d764670c82308f061027a7e5beacfb9c17273bb Mon Sep 17 00:00:00 2001 From: Tom Hubrecht Date: Fri, 16 Jan 2026 18:09:13 +0100 Subject: [PATCH] nix/path-info: Don't print missing paths as no fetch can be done Fixes #323 Let's now all go an a little rant about spaghetti code... The result of this code is that the missing paths are not printed anymore. The basic issue was that the parent class of this command is StorePathsCommand, which inherits from BuiltPathsCommand, and their purpose is to work on path that are clearly in the store, building them if needed (and ofc telling the user about what's missing), the sequance of calls is: - BuiltPathsCommand::run(ref store, Installables && installables) - Installable::toBuiltPaths( *getEvaluator()->begin(aio()), getEvalStore(), store, realiseMode, operateOn, installables); where operateOn is Output by default, realiseMode is Derivation, so the only thing that can be built are the derivations for the required installables - Installable::build(state, evalStore, store, mode, installables) - Installable::build2(state, evalStore, store, mode, installables, bMode) And that final call has the following: ``` switch (mode) { case Realise::Nothing: case Realise::Derivation: state.aio.blockOn(printMissing(store, pathsToBuild, lvlError)); ``` So there were two options, hack a new spaghetti in the existing spaghetti code, or condense all those calls that are actually useless in our case because they mostly transform a list of installables into a map from installables to their BuiltPath which are then iterated to retrieve the final outputs, whereas it is possible to directly get the required paths in a much more efficient manner and without printing unrequired stuff through a multitude of intertwined function calls by simply replacing one method that was previously inherited from the grandparent class Change-Id: I1d2baaef5a099cd98b63b5346f2613914c6cd2ac --- doc/manual/rl-next/path-info-missing.md | 11 ++++++ lix/libcmd/command.hh | 4 +- lix/nix/path-info.cc | 52 +++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) create mode 100644 doc/manual/rl-next/path-info-missing.md diff --git a/doc/manual/rl-next/path-info-missing.md b/doc/manual/rl-next/path-info-missing.md new file mode 100644 index 000000000..f31800a07 --- /dev/null +++ b/doc/manual/rl-next/path-info-missing.md @@ -0,0 +1,11 @@ +--- +synopsis: "nix path-info no longer lies to the user about fetching paths" +cls: [4866] +issues: [fj#323] +category: "Improvements" +credits: [thubrecht] +--- + +When running `nix path-info` with an installable that is not present in the store, Lix no longer +tells the user which paths are missing and that they will be fetched, as the documentation clearly +states that this command does not fetch missing paths. diff --git a/lix/libcmd/command.hh b/lix/libcmd/command.hh index 0482af0cd..85c2269aa 100644 --- a/lix/libcmd/command.hh +++ b/lix/libcmd/command.hh @@ -220,13 +220,11 @@ struct MixOperateOnOptions : virtual Args */ struct BuiltPathsCommand : InstallablesCommand, virtual MixOperateOnOptions { -private: +protected: bool recursive = false; bool all = false; -protected: - Realise realiseMode = Realise::Derivation; public: diff --git a/lix/nix/path-info.cc b/lix/nix/path-info.cc index 4ee1183a2..56f4769dd 100644 --- a/lix/nix/path-info.cc +++ b/lix/nix/path-info.cc @@ -80,6 +80,58 @@ struct CmdPathInfo : StorePathsCommand, MixJSON std::cout << fmt("\t%6.1f%c", res, idents.at(power)); } + void run(ref store, Installables && installables) override + { + StorePathSet paths; + + if (all) { + if (installables.size()) { + throw UsageError("'--all' does not expect arguments"); + } + + paths = aio().blockOn(store->queryAllValidPaths()); + } else { + auto state = getEvaluator()->begin(aio()); + + if (operateOn == OperateOn::Output) { + for (auto i : installables) { + for (auto b : i->toDerivedPaths(*state)) { + std::visit( + overloaded{ + [&](const DerivedPath::Built & bfd) { + for (auto & [_, output] : + aio().blockOn(resolveDerivedPath(*store, bfd, &*getEvalStore()))) + { + paths.insert(output); + } + }, + [&](const DerivedPath::Opaque & bo) { paths.insert(bo.path); }, + }, + b.path.raw() + ); + } + } + } else { + auto drvPaths = Installable::toDerivations(*state, store, installables, true); + paths.insert(drvPaths.begin(), drvPaths.end()); + } + + if (recursive) { + // XXX: This only computes the store path closure, ignoring + // intermediate realisations + StorePathSet closure; + aio().blockOn(store->computeFSClosure(paths, closure)); + + paths.insert(closure.begin(), closure.end()); + } + } + + auto sorted = aio().blockOn(store->topoSortPaths(paths)); + std::reverse(sorted.begin(), sorted.end()); + + run(store, std::move(sorted)); + } + void run(ref store, StorePaths && storePaths) override { // Wipe the progress bar to prevent interference with the output.