diff --git a/src/nix/flake-prefetch-inputs.md b/src/nix/flake-prefetch-inputs.md new file mode 100644 index 000000000..a69f7d367 --- /dev/null +++ b/src/nix/flake-prefetch-inputs.md @@ -0,0 +1,17 @@ +R""( + +# Examples + +* Fetch the inputs of the `hydra` flake: + + ```console + # nix flake prefetch-inputs github:NixOS/hydra + ``` + +# Description + +Fetch the inputs of a flake. This ensures that they are already available for any subsequent evaluation of the flake. + +This operation is recursive: it will fetch not just the direct inputs of the top-level flake, but also transitive inputs. + +)"" diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 48e2ae392..c2aa442bc 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -19,6 +19,8 @@ #include "nix/util/users.hh" #include "nix/fetchers/fetch-to-store.hh" #include "nix/store/local-fs-store.hh" +#include "nix/util/thread-pool.hh" +#include "nix/store/filetransfer.hh" #include #include @@ -1140,6 +1142,59 @@ struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun } }; +struct CmdFlakePrefetchInputs : FlakeCommand +{ + std::string description() override + { + return "fetch the inputs of a flake"; + } + + std::string doc() override + { + return + #include "flake-prefetch-inputs.md" + ; + } + + void run(nix::ref store) override + { + auto flake = lockFlake(); + + ThreadPool pool{fileTransferSettings.httpConnections}; + + struct State + { + std::set done; + }; + + Sync state_; + + std::function visit; + visit = [&](const Node & node) + { + if (!state_.lock()->done.insert(&node).second) + return; + + if (auto lockedNode = dynamic_cast(&node)) { + Activity act(*logger, lvlInfo, actUnknown, + fmt("fetching '%s'", lockedNode->lockedRef)); + auto accessor = lockedNode->lockedRef.input.getAccessor(store).first; + if (!evalSettings.lazyTrees) + fetchToStore(*store, accessor, FetchMode::Copy, lockedNode->lockedRef.input.getName()); + } + + for (auto & [inputName, input] : node.inputs) { + if (auto inputNode = std::get_if<0>(&input)) + pool.enqueue(std::bind(visit, **inputNode)); + } + }; + + pool.enqueue(std::bind(visit, *flake.lockFile.root)); + + pool.process(); + } +}; + struct CmdFlakeShow : FlakeCommand, MixJSON { bool showLegacy = false; @@ -1543,6 +1598,7 @@ struct CmdFlake : NixMultiCommand {"new", []() { return make_ref(); }}, {"clone", []() { return make_ref(); }}, {"archive", []() { return make_ref(); }}, + {"prefetch-inputs", []() { return make_ref(); }}, {"show", []() { return make_ref(); }}, {"prefetch", []() { return make_ref(); }}, })