From 3c54e9ba011a42c454ce401b861735a2dbee0d79 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 30 Jan 2020 00:58:55 +0100 Subject: [PATCH] Add 'nix flake archive' command This copies a flake and all its inputs recursively to a store (e.g. a binary cache). This is intended to enable long-term reproducibility for flakes. However this will also require #3253. Example: $ nix flake archive --json --to file:///tmp/my-cache nixops {"path":"/nix/store/272igzkgl1gdzmabsjvb2kb2zqbphb3p-source","inputs":{"nixops-aws":{"path":"/nix/store/ybcykw13gr7iq1pzg18iyibbcv8k9q1v-source","inputs":{}},"nixops-hetzner":{"path":"/nix/store/6yn0205x3nz55w8ms3335p2841javz2d-source","inputs":{}},"nixpkgs":{"path":"/nix/store/li3lkr2ajrzphqqz3jj2avndnyd3i5lc-source","inputs":{}}}} $ ll /tmp/my-cache total 16 -rw-r--r-- 1 eelco users 403 Jan 30 01:01 272igzkgl1gdzmabsjvb2kb2zqbphb3p.narinfo -rw-r--r-- 1 eelco users 403 Jan 30 01:01 6yn0205x3nz55w8ms3335p2841javz2d.narinfo -rw-r--r-- 1 eelco users 408 Jan 30 01:01 li3lkr2ajrzphqqz3jj2avndnyd3i5lc.narinfo drwxr-xr-x 2 eelco users 6 Jan 30 01:01 nar -rw-r--r-- 1 eelco users 21 Jan 30 01:01 nix-cache-info -rw-r--r-- 1 eelco users 404 Jan 30 01:01 ybcykw13gr7iq1pzg18iyibbcv8k9q1v.narinfo Fixes #3336. --- src/nix/flake.cc | 77 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 49c0d30f0..295383681 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -11,6 +11,7 @@ #include "attr-path.hh" #include "fetchers/fetchers.hh" #include "fetchers/registry.hh" +#include "json.hh" #include #include @@ -213,7 +214,7 @@ struct CmdFlakeInfo : FlakeCommand, MixJSON } }; -struct CmdFlakeCheck : FlakeCommand, MixJSON +struct CmdFlakeCheck : FlakeCommand { bool build = true; @@ -604,6 +605,79 @@ struct CmdFlakeClone : FlakeCommand } }; +struct CmdFlakeArchive : FlakeCommand, MixJSON, MixDryRun +{ + std::string dstUri; + + CmdFlakeArchive() + { + mkFlag() + .longName("to") + .labels({"store-uri"}) + .description("URI of the destination Nix store") + .dest(&dstUri); + } + + std::string description() override + { + return "copy a flake and all its inputs to a store"; + } + + Examples examples() override + { + return { + Example{ + "To copy the dwarffs flake and its dependencies to a binary cache:", + "nix flake archive --to file:///tmp/my-cache dwarffs" + }, + Example{ + "To fetch the dwarffs flake and its dependencies to the local Nix store:", + "nix flake archive dwarffs" + }, + Example{ + "To print the store paths of the flake sources of NixOps without fetching them:", + "nix flake archive --json --dry-run nixops" + }, + }; + } + + void run(nix::ref store) override + { + auto flake = lockFlake(); + + auto jsonRoot = json ? std::optional(std::cout) : std::optional(); + + StorePathSet sources; + + sources.insert(flake.flake.sourceInfo->storePath.clone()); + if (jsonRoot) + jsonRoot->attr("path", store->printStorePath(flake.flake.sourceInfo->storePath)); + + std::function & jsonObj)> traverse; + traverse = [&](const LockedInputs & inputs, std::optional & jsonObj) + { + auto jsonObj2 = jsonObj ? jsonObj->object("inputs") : std::optional(); + for (auto & input : inputs.inputs) { + auto jsonObj3 = jsonObj2 ? jsonObj2->object(input.first) : std::optional(); + if (!dryRun) + input.second.ref.input->fetchTree(store); + auto storePath = input.second.computeStorePath(*store); + if (jsonObj3) + jsonObj3->attr("path", store->printStorePath(storePath)); + sources.insert(std::move(storePath)); + traverse(input.second, jsonObj3); + } + }; + + traverse(flake.lockFile, jsonRoot); + + if (!dryRun && !dstUri.empty()) { + ref dstStore = dstUri.empty() ? openStore() : openStore(dstUri); + copyPaths(store, dstStore, sources); + } + } +}; + struct CmdFlake : virtual MultiCommand, virtual Command { CmdFlake() @@ -617,6 +691,7 @@ struct CmdFlake : virtual MultiCommand, virtual Command {"pin", []() { return make_ref(); }}, {"init", []() { return make_ref(); }}, {"clone", []() { return make_ref(); }}, + {"archive", []() { return make_ref(); }}, }) { }