From d599b4f77367a6c4e841688f51ce973cb93cf9a3 Mon Sep 17 00:00:00 2001 From: Guillaume Maudoux Date: Mon, 16 Sep 2024 00:24:16 +0200 Subject: [PATCH] Introduce `nix derivation instantiate` This is simmilar to `nix-instantiate` with support for installables (and flakes). --- src/nix/derivation-instantiate.cc | 93 ++++++++++++++++++++++ src/nix/derivation-instantiate.md | 39 +++++++++ src/nix/meson.build | 1 + tests/functional/derivation-instantiate.sh | 44 ++++++++++ tests/functional/local.mk | 1 + tests/functional/meson.build | 1 + 6 files changed, 179 insertions(+) create mode 100644 src/nix/derivation-instantiate.cc create mode 100644 src/nix/derivation-instantiate.md create mode 100755 tests/functional/derivation-instantiate.sh diff --git a/src/nix/derivation-instantiate.cc b/src/nix/derivation-instantiate.cc new file mode 100644 index 00000000000..9e2f40c043a --- /dev/null +++ b/src/nix/derivation-instantiate.cc @@ -0,0 +1,93 @@ +#include "command.hh" +#include "common-args.hh" +#include "store-api.hh" +#include "derivations.hh" +#include "local-fs-store.hh" +#include "progress-bar.hh" + +#include + +using namespace nix; + +static nlohmann::json storePathSetToJSON(const StorePathSet & paths, Store & store) +{ + auto res = nlohmann::json::object(); + for (auto & path : paths) { + res[store.printStorePath(path)] = nlohmann::json::object(); + } + return res; +} + +// TODO deduplicate with other code also setting such out links. +static void +createOutLinks(const std::filesystem::path & outLink, const StorePathSet & derivations, LocalFSStore & store) +{ + for (const auto & [_i, drv] : enumerate(derivations)) { + auto i = _i; + auto symlink = outLink; + + if (i) + symlink += fmt("-%d", i); + store.addPermRoot(drv, absPath(symlink.string())); + } +} + +struct CmdDerivationInstantiate : InstallablesCommand, MixJSON +{ + Path outLink = "drv"; + bool printOutputPaths = false; + + CmdDerivationInstantiate() + { + addFlag( + {.longName = "out-link", + .shortName = 'o', + .description = "Use *path* as prefix for the symlinks to the evaluation results. It defaults to `drv`.", + .labels = {"path"}, + .handler = {&outLink}, + .completer = completePath}); + + addFlag({ + .longName = "no-link", + .description = "Do not create symlinks to the evaluation results.", + .handler = {&outLink, Path("")}, + }); + } + + std::string description() override + { + return "Force the evaluation of the expression and return the corresponding .drv"; + } + + std::string doc() override + { + return +#include "derivation-instantiate.md" + ; + } + + Category category() override + { + return catSecondary; + } + + void run(ref store, Installables && installables) override + { + auto drvPaths = Installable::toDerivations(store, installables, false); + + if (outLink != "") + if (auto store2 = store.dynamic_pointer_cast()) + createOutLinks(outLink, drvPaths, *store2); + + if (json) { + logger->cout("%s", storePathSetToJSON(drvPaths, *store).dump()); + } else { + stopProgressBar(); + for (auto & path : drvPaths) { + logger->cout(store->printStorePath(path)); + } + } + } +}; + +static auto rCmdDerivationInstantiate = registerCommand2({"derivation", "instantiate"}); diff --git a/src/nix/derivation-instantiate.md b/src/nix/derivation-instantiate.md new file mode 100644 index 00000000000..8470e06f8cb --- /dev/null +++ b/src/nix/derivation-instantiate.md @@ -0,0 +1,39 @@ +R""( + +# Name + +`nix derivation instantiate` - instantiate store derivations + +# Synopsis + +`nix derivation instantiate` + [`--out-link` *link prefix*] + [`--json`] + [`--no-link`] + *installables…* + +# Description + +The command `nix derivation instantiate` produces [store derivation]s from +installables. Each top-level expression should evaluate to a derivation, a list +of derivations, or a set of derivations. The paths of the resulting store +derivations are printed on standard output. + +[store derivation]: @docroot@/glossary.md#gloss-store-derivation + +# Options + +- `--out-link` *link prefix* + + The prefix used for gc roots. + +- `--no-link` + + Do not create garbage collector roots for the generated store derivations. + +- `--json` + + Dump a JSON object whose keys are the generated store derivations instread of + printing them directly on the output. + +)"" diff --git a/src/nix/meson.build b/src/nix/meson.build index 6edb768e31c..95814c7fffe 100644 --- a/src/nix/meson.build +++ b/src/nix/meson.build @@ -78,6 +78,7 @@ nix_sources = [config_h] + files( 'config.cc', 'copy.cc', 'derivation-add.cc', + 'derivation-instantiate.cc', 'derivation-show.cc', 'derivation.cc', 'develop.cc', diff --git a/tests/functional/derivation-instantiate.sh b/tests/functional/derivation-instantiate.sh new file mode 100755 index 00000000000..b46b177bc75 --- /dev/null +++ b/tests/functional/derivation-instantiate.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +source common.sh + +TODO_NixOS + +clearStore + +drvPath=$(nix derivation instantiate --no-link --file simple.nix) +test -f "$drvPath" +nix-store --delete "$drvPath" +if test -f "$drvPath"; then false; fi + +drvPath=$(nix derivation instantiate --file simple.nix) +test -f "$drvPath" +test -e drv +nix-store --gc --print-roots | grep "$drvPath" +nix-store --gc --print-live | grep "$drvPath" +if nix-store --delete "$drvPath"; then false; fi +test -f "$drvPath" +[ "$(nix-store -q --roots "$drvPath")" = "$(realpath --no-symlinks drv) -> $drvPath" ] +rm drv +nix-store --delete "$drvPath" +if test -f "$drvPath"; then false; fi + +drvPath=$(nix derivation instantiate --out-link foobar --file simple.nix) +test -e foobar +[ "$(nix-store -q --roots "$drvPath")" = "$(realpath --no-symlinks foobar) -> $drvPath" ] +rm foobar +nix-store --delete "$drvPath" + +drvPathJson=$(nix derivation instantiate --json --no-link --file simple.nix) +[ "$drvPathJson" = "{\"$drvPath\":{}}" ] +nix-store --delete "$drvPath" + +mapfile -t drvPaths < <(nix derivation instantiate --json --out-link multidrv --file check.nix | jq 'keys|.[]' -r) +roots=(./multidrv*) +[ "${#roots[@]}" -gt 1 ] +[ "${#roots[@]}" -eq "${#drvPaths[@]}" ] +mapfile -t rootedPaths < <(readlink "${roots[@]}") +[ "${rootedPaths[*]}" = "${drvPaths[*]}" ] +rm -f multidrv* + +nix-collect-garbage diff --git a/tests/functional/local.mk b/tests/functional/local.mk index 3f796291a56..3f472ce21b0 100644 --- a/tests/functional/local.mk +++ b/tests/functional/local.mk @@ -88,6 +88,7 @@ nix_tests = \ why-depends.sh \ derivation-json.sh \ derivation-advanced-attributes.sh \ + derivation-instantiate.sh \ import-from-derivation.sh \ nix_path.sh \ nars.sh \ diff --git a/tests/functional/meson.build b/tests/functional/meson.build index 69b6d31949e..4188386a919 100644 --- a/tests/functional/meson.build +++ b/tests/functional/meson.build @@ -157,6 +157,7 @@ suites = [ 'why-depends.sh', 'derivation-json.sh', 'derivation-advanced-attributes.sh', + 'derivation-instantiate.sh', 'import-from-derivation.sh', 'nix_path.sh', 'nars.sh',