From 8499f32fb2e7fdf09e97d0beb1fe78bef5900d93 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 12 Feb 2021 21:51:36 +0000 Subject: [PATCH 01/14] New "indexed" installable syntax: `!` Being conservative and only doing a single output name for now. --- src/libcmd/installables.cc | 42 +++++++++++++++++++++++++++++++++- src/nix/nix.md | 10 ++++++++ tests/build-explicit-output.sh | 17 ++++++++++++++ tests/build.sh | 5 ++-- tests/local.mk | 1 + 5 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 tests/build-explicit-output.sh diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 5d3026c1a8c..cf7681d0d08 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -349,6 +349,31 @@ struct InstallableStorePath : Installable } }; +struct InstallableIndexedStorePath : Installable +{ + ref store; + DerivedPath::Built req; + + InstallableIndexedStorePath(ref store, DerivedPath::Built && req) + : store(store), req(std::move(req)) + { } + + std::string what() override + { + return req.to_string(*store); + } + + DerivedPathsWithHints toDerivedPathsWithHints() override + { + std::map> outputs; + for (auto & output : req.outputs) + outputs.insert_or_assign(output, std::nullopt); + return { + DerivedPathWithHints { DerivedPathWithHints::Built { req.drvPath, std::move(outputs) } } + }; + } +}; + DerivedPathsWithHints InstallableValue::toDerivedPathsWithHints() { DerivedPathsWithHints res; @@ -638,7 +663,22 @@ std::vector> SourceExprCommand::parseInstallables( ex = std::current_exception(); } - if (s.find('/') != std::string::npos) { + auto found = s.rfind('!'); + if (found != std::string::npos) { + try { + result.push_back(std::make_shared( + store, + DerivedPath::Built::parse(*store, s))); + continue; + } catch (BadStorePath &) { + } catch (...) { + if (!ex) + ex = std::current_exception(); + } + } + + found = s.find('/'); + if (found != std::string::npos) { try { result.push_back(std::make_shared(store, store->followLinksToStorePath(s))); continue; diff --git a/src/nix/nix.md b/src/nix/nix.md index d10de7c01b1..22cc9d4767d 100644 --- a/src/nix/nix.md +++ b/src/nix/nix.md @@ -94,6 +94,16 @@ the Nix store. Here are the recognised types of installables: If you want to operate on the store derivation itself, pass the `--derivation` flag. +* **Indexed store derivations**: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv!out` + + Store derivations can be indexed with a specific output name. This + allows finer control versus just specifying a derivation (without + `--derivation`) and getting all the outputs. + + This is especially useful for (currently unstable) floating content + addressed derivations, which do not have precomputed output paths that + can be used instead. + * **Nix attributes**: `--file /path/to/nixpkgs hello` When the `-f` / `--file` *path* option is given, installables are diff --git a/tests/build-explicit-output.sh b/tests/build-explicit-output.sh new file mode 100644 index 00000000000..17930c2c09a --- /dev/null +++ b/tests/build-explicit-output.sh @@ -0,0 +1,17 @@ +source common.sh + +drv=$(nix eval -f multiple-outputs.nix --raw a.drvPath) +if nix build "$drv!not-an-output" --json; then + fail "'not-an-output' should fail to build" +fi + +nix build "$drv!first" --json | jq --exit-status ' + (.[0] | + (.drvPath | match(".*multiple-outputs-a.drv")) and + (.outputs | + .first and + (has("second") | not))) +' +# TODO use +# (.first | match(".*multiple-outputs-a-first")) and +# once we make it put the result paths in the buildables. diff --git a/tests/build.sh b/tests/build.sh index aa54b88eb8a..5a281933677 100644 --- a/tests/build.sh +++ b/tests/build.sh @@ -4,8 +4,9 @@ expectedJSONRegex='\[\{"drvPath":".*multiple-outputs-a.drv","outputs":\{"first": nix build -f multiple-outputs.nix --json a.all b.all | jq --exit-status ' (.[0] | (.drvPath | match(".*multiple-outputs-a.drv")) and - (.outputs.first | match(".*multiple-outputs-a-first")) and - (.outputs.second | match(".*multiple-outputs-a-second"))) + (.outputs | + (.first | match(".*multiple-outputs-a-first")) and + (.second | match(".*multiple-outputs-a-second")))) and (.[1] | (.drvPath | match(".*multiple-outputs-b.drv")) and (.outputs.out | match(".*multiple-outputs-b"))) diff --git a/tests/local.mk b/tests/local.mk index e7e85f97eed..1d3e8949983 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -41,6 +41,7 @@ nix_tests = \ describe-stores.sh \ flakes.sh \ build.sh \ + build-explicit-output.sh \ compute-levels.sh \ ca/build.sh \ ca/substitute.sh \ From 6951b26ed0a806c03ad73069ccc925ef6ac158e6 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 1 Apr 2022 03:57:51 +0000 Subject: [PATCH 02/14] Require (new) computed-derivations experimental feature for ! installable --- src/libcmd/installables.cc | 1 + src/libutil/experimental-features.cc | 1 + src/libutil/experimental-features.hh | 1 + tests/build-explicit-output.sh | 3 +++ 4 files changed, 6 insertions(+) diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 1d44ffe84bf..ab13f11dff4 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -740,6 +740,7 @@ std::vector> SourceExprCommand::parseInstallables( result.push_back(std::make_shared( store, DerivedPath::Built::parse(*store, s))); + settings.requireExperimentalFeature(Xp::ComputedDerivations); continue; } catch (BadStorePath &) { } catch (...) { diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc index e033a41165e..c1e574c0d5e 100644 --- a/src/libutil/experimental-features.cc +++ b/src/libutil/experimental-features.cc @@ -13,6 +13,7 @@ std::map stringifiedXpFeatures = { { Xp::RecursiveNix, "recursive-nix" }, { Xp::NoUrlLiterals, "no-url-literals" }, { Xp::FetchClosure, "fetch-closure" }, + { Xp::ComputedDerivations, "computed-derivations" }, }; const std::optional parseExperimentalFeature(const std::string_view & name) diff --git a/src/libutil/experimental-features.hh b/src/libutil/experimental-features.hh index 3a254b42330..58e082c72a5 100644 --- a/src/libutil/experimental-features.hh +++ b/src/libutil/experimental-features.hh @@ -22,6 +22,7 @@ enum struct ExperimentalFeature RecursiveNix, NoUrlLiterals, FetchClosure, + ComputedDerivations, // RFC 92 }; /** diff --git a/tests/build-explicit-output.sh b/tests/build-explicit-output.sh index fcb263913f7..0f2f428db03 100644 --- a/tests/build-explicit-output.sh +++ b/tests/build-explicit-output.sh @@ -1,5 +1,8 @@ source common.sh +enableFeatures "computed-derivations" +restartDaemon + drv=$(nix eval -f multiple-outputs.nix --raw a.drvPath) if nix build "$drv!not-an-output" --json; then fail "'not-an-output' should fail to build" From fda2224b591c2667d18fb815f117f48b45a54cb1 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 7 Apr 2022 19:45:38 +0000 Subject: [PATCH 03/14] Add release notes mark experimental --- doc/manual/src/release-notes/rl-next.md | 3 +++ src/nix/nix.md | 2 ++ 2 files changed, 5 insertions(+) diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md index 8c8c0fd416a..97627cc9640 100644 --- a/doc/manual/src/release-notes/rl-next.md +++ b/doc/manual/src/release-notes/rl-next.md @@ -40,3 +40,6 @@ As before, the old output will continue to work, but `nix flake check` will issue a warning about it. + +* Add experimental *indexed store derivations* installable syntax, part of the + the `computed-derivations` experimental feature. diff --git a/src/nix/nix.md b/src/nix/nix.md index 4919763c478..691aa137bc1 100644 --- a/src/nix/nix.md +++ b/src/nix/nix.md @@ -132,6 +132,8 @@ the Nix store. Here are the recognised types of installables: * **Indexed store derivations**: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv!out` + *(Experimental, part of by the `computed-derivations` experimental feature.)* + Store derivations can be indexed with a specific output name. This allows finer control versus just specifying a derivation (without `--derivation`) and getting all the outputs. From 49ad315c0357116787ef45a1249009b6bc00301f Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 12 May 2022 20:10:02 +0000 Subject: [PATCH 04/14] Use `^` not `!` in indexed store derivations installable syntax Match the other syntax that was recently added --- src/libcmd/installables.cc | 8 +++++--- src/libstore/derived-path.cc | 11 ++++------- src/libstore/derived-path.hh | 2 +- src/nix/nix.md | 2 +- tests/build-explicit-output.sh | 4 ++-- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index e0a95118dcd..575e7f69678 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -799,11 +799,12 @@ std::vector> SourceExprCommand::parseInstallables( for (auto & s : ss) { std::exception_ptr ex; - if (s.rfind('!') != std::string::npos) { + auto found = s.rfind('^'); + if (found != std::string::npos) { try { result.push_back(std::make_shared( store, - DerivedPath::Built::parse(*store, s))); + DerivedPath::Built::parse(*store, s.substr(0, found), s.substr(found + 1)))); settings.requireExperimentalFeature(Xp::ComputedDerivations); continue; } catch (BadStorePath &) { @@ -813,7 +814,8 @@ std::vector> SourceExprCommand::parseInstallables( } } - if (s.find('/') != std::string::npos) { + found = s.find('/'); + if (found != std::string::npos) { try { result.push_back(std::make_shared(store, store->followLinksToStorePath(s))); continue; diff --git a/src/libstore/derived-path.cc b/src/libstore/derived-path.cc index 44587ae789f..11a3f5e23d6 100644 --- a/src/libstore/derived-path.cc +++ b/src/libstore/derived-path.cc @@ -93,12 +93,9 @@ DerivedPath::Opaque DerivedPath::Opaque::parse(const Store & store, std::string_ return {store.parseStorePath(s)}; } -DerivedPath::Built DerivedPath::Built::parse(const Store & store, std::string_view s) +DerivedPath::Built DerivedPath::Built::parse(const Store & store, std::string_view drvS, std::string_view outputsS) { - size_t n = s.find("!"); - assert(n != s.npos); - auto drvPath = store.parseStorePath(s.substr(0, n)); - auto outputsS = s.substr(n + 1); + auto drvPath = store.parseStorePath(drvS); std::set outputs; if (outputsS != "*") outputs = tokenizeString>(outputsS, ","); @@ -107,10 +104,10 @@ DerivedPath::Built DerivedPath::Built::parse(const Store & store, std::string_vi DerivedPath DerivedPath::parse(const Store & store, std::string_view s) { - size_t n = s.find("!"); + size_t n = s.rfind("!"); return n == s.npos ? (DerivedPath) DerivedPath::Opaque::parse(store, s) - : (DerivedPath) DerivedPath::Built::parse(store, s); + : (DerivedPath) DerivedPath::Built::parse(store, s.substr(0, n), s.substr(n + 1)); } RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const diff --git a/src/libstore/derived-path.hh b/src/libstore/derived-path.hh index 24a0ae77359..fab1292a797 100644 --- a/src/libstore/derived-path.hh +++ b/src/libstore/derived-path.hh @@ -47,7 +47,7 @@ struct DerivedPathBuilt { std::set outputs; std::string to_string(const Store & store) const; - static DerivedPathBuilt parse(const Store & store, std::string_view); + static DerivedPathBuilt parse(const Store & store, std::string_view, std::string_view); nlohmann::json toJSON(ref store) const; bool operator < (const DerivedPathBuilt & b) const diff --git a/src/nix/nix.md b/src/nix/nix.md index 34c763c699a..32112d38d1b 100644 --- a/src/nix/nix.md +++ b/src/nix/nix.md @@ -130,7 +130,7 @@ the Nix store. Here are the recognised types of installables: If you want to operate on the store derivation itself, pass the `--derivation` flag. -* **Indexed store derivations**: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv!out` +* **Indexed store derivations**: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv^out` *(Experimental, part of by the `computed-derivations` experimental feature.)* diff --git a/tests/build-explicit-output.sh b/tests/build-explicit-output.sh index 0f2f428db03..68fd2f128f9 100644 --- a/tests/build-explicit-output.sh +++ b/tests/build-explicit-output.sh @@ -4,11 +4,11 @@ enableFeatures "computed-derivations" restartDaemon drv=$(nix eval -f multiple-outputs.nix --raw a.drvPath) -if nix build "$drv!not-an-output" --json; then +if nix build "$drv^not-an-output" --json; then fail "'not-an-output' should fail to build" fi -nix build "$drv!first" --json | jq --exit-status ' +nix build "$drv^first" --json | jq --exit-status ' (.[0] | (.drvPath | match(".*multiple-outputs-a.drv")) and (.outputs | From f3262bc2165af90fd20f04f74243aa75137767a2 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 14 Jul 2022 16:36:00 -0400 Subject: [PATCH 05/14] Combine `InstallableStorePath` with `InstallableIndexedStorePath` No behavior should be changed, the `isDerivation` logic is moved from the methods to the constructor. --- src/libcmd/installables.cc | 82 +++++++++++++++++--------------------- 1 file changed, 37 insertions(+), 45 deletions(-) diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index b78581a7cdc..7b8860a882c 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -395,53 +395,21 @@ static StorePath getDeriver( struct InstallableStorePath : Installable { ref store; - StorePath storePath; + DerivedPath req; InstallableStorePath(ref store, StorePath && storePath) - : store(store), storePath(std::move(storePath)) { } - - std::string what() const override { return store->printStorePath(storePath); } - - DerivedPaths toDerivedPaths() override - { - if (storePath.isDerivation()) { - auto drv = store->readDerivation(storePath); - return { - DerivedPath::Built { - .drvPath = storePath, - .outputs = drv.outputNames(), - } - }; - } else { - return { - DerivedPath::Opaque { - .path = storePath, - } - }; - } - } - - StorePathSet toDrvPaths(ref store) override - { - if (storePath.isDerivation()) { - return {storePath}; - } else { - return {getDeriver(store, *this, storePath)}; - } - } - - std::optional getStorePath() override - { - return storePath; - } -}; - -struct InstallableIndexedStorePath : Installable -{ - ref store; - DerivedPath::Built req; + : store(store), + req(storePath.isDerivation() + ? (DerivedPath) DerivedPath::Built { + .drvPath = std::move(storePath), + .outputs = {}, + } + : (DerivedPath) DerivedPath::Opaque { + .path = std::move(storePath), + }) + { } - InstallableIndexedStorePath(ref store, DerivedPath::Built && req) + InstallableStorePath(ref store, DerivedPath && req) : store(store), req(std::move(req)) { } @@ -454,6 +422,30 @@ struct InstallableIndexedStorePath : Installable { return { req }; } + + StorePathSet toDrvPaths(ref store) override + { + return std::visit(overloaded { + [&](const DerivedPath::Built & bfd) -> StorePathSet { + return { bfd.drvPath }; + }, + [&](const DerivedPath::Opaque & bo) -> StorePathSet { + return { getDeriver(store, *this, bo.path) }; + }, + }, req.raw()); + } + + std::optional getStorePath() override + { + return std::visit(overloaded { + [&](const DerivedPath::Built & bfd) { + return bfd.drvPath; + }, + [&](const DerivedPath::Opaque & bo) { + return bo.path; + }, + }, req.raw()); + } }; DerivedPaths InstallableValue::toDerivedPaths() @@ -819,7 +811,7 @@ std::vector> SourceExprCommand::parseInstallables( auto found = s.rfind('^'); if (found != std::string::npos) { try { - result.push_back(std::make_shared( + result.push_back(std::make_shared( store, DerivedPath::Built::parse(*store, s.substr(0, found), s.substr(found + 1)))); settings.requireExperimentalFeature(Xp::ComputedDerivations); From 8735f55decab03ecf3571f756a22abc3b3dc6304 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 14 Jul 2022 20:22:46 -0400 Subject: [PATCH 06/14] Fix bug, test more, document more --- src/libstore/derived-path.cc | 6 +++++- src/nix/nix.md | 5 +++-- tests/build-explicit-output.sh | 32 ++++++++++++++++++++++++++++++-- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/src/libstore/derived-path.cc b/src/libstore/derived-path.cc index 11a3f5e23d6..f6a0c01df10 100644 --- a/src/libstore/derived-path.cc +++ b/src/libstore/derived-path.cc @@ -97,8 +97,12 @@ DerivedPath::Built DerivedPath::Built::parse(const Store & store, std::string_vi { auto drvPath = store.parseStorePath(drvS); std::set outputs; - if (outputsS != "*") + if (outputsS != "*") { outputs = tokenizeString>(outputsS, ","); + if (outputs.empty()) + throw Error( + "Explicit list of wanted outputs '%s' must not be empty. Consider using '*' as a wildcard meaning all outputs if no output in particular is wanted.", outputsS); + } return {drvPath, outputs}; } diff --git a/src/nix/nix.md b/src/nix/nix.md index 32112d38d1b..5d669e8b1b9 100644 --- a/src/nix/nix.md +++ b/src/nix/nix.md @@ -134,8 +134,9 @@ the Nix store. Here are the recognised types of installables: *(Experimental, part of by the `computed-derivations` experimental feature.)* - Store derivations can be indexed with a specific output name. This - allows finer control versus just specifying a derivation (without + Store derivations can be indexed with a non-empty comma-separated list + of specific output names, or `*` meaning all ouptuts. This allows + finer control versus just specifying a derivation (without `--derivation`) and getting all the outputs. This is especially useful for (currently unstable) floating content diff --git a/tests/build-explicit-output.sh b/tests/build-explicit-output.sh index 68fd2f128f9..a4cb1c5ad0d 100644 --- a/tests/build-explicit-output.sh +++ b/tests/build-explicit-output.sh @@ -1,14 +1,24 @@ source common.sh +set -o pipefail + enableFeatures "computed-derivations" restartDaemon drv=$(nix eval -f multiple-outputs.nix --raw a.drvPath) -if nix build "$drv^not-an-output" --json; then +if nix build "$drv^not-an-output" --no-link --json; then fail "'not-an-output' should fail to build" fi -nix build "$drv^first" --json | jq --exit-status ' +if nix build "$drv^" --no-link --json; then + fail "'empty outputs list' should fail to build" +fi + +if nix build "$drv^*nope" --no-link --json; then + fail "'* must be entire string' should fail to build" +fi + +nix build "$drv^first" --no-link --json | jq --exit-status ' (.[0] | (.drvPath | match(".*multiple-outputs-a.drv")) and (.outputs | @@ -16,3 +26,21 @@ nix build "$drv^first" --json | jq --exit-status ' (.first | match(".*multiple-outputs-a-first")) and (has("second") | not))) ' + +nix build "$drv^first,second" --no-link --json | jq --exit-status ' + (.[0] | + (.drvPath | match(".*multiple-outputs-a.drv")) and + (.outputs | + (keys | length == 2) and + (.first | match(".*multiple-outputs-a-first")) and + (.second | match(".*multiple-outputs-a-second")))) +' + +nix build "$drv^*" --no-link --json | jq --exit-status ' + (.[0] | + (.drvPath | match(".*multiple-outputs-a.drv")) and + (.outputs | + (keys | length == 2) and + (.first | match(".*multiple-outputs-a-first")) and + (.second | match(".*multiple-outputs-a-second")))) +' From 279ecf7cdee94b3b5e37e4ade3af3a6d20ca9cde Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 15 Jul 2022 13:29:15 +0000 Subject: [PATCH 07/14] Remove `computed-derivations` experimental feature We don't need it yet. --- doc/manual/src/release-notes/rl-next.md | 3 +-- src/libcmd/installables.cc | 1 - src/libutil/experimental-features.cc | 1 - src/libutil/experimental-features.hh | 1 - src/nix/nix.md | 2 -- tests/build-explicit-output.sh | 3 --- 6 files changed, 1 insertion(+), 10 deletions(-) diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md index 3bb12c01393..7047e242193 100644 --- a/doc/manual/src/release-notes/rl-next.md +++ b/doc/manual/src/release-notes/rl-next.md @@ -1,4 +1,3 @@ # Release X.Y (202?-??-??) -* Add experimental *indexed store derivations* installable syntax, part of the - the `computed-derivations` experimental feature. +* Add *indexed store derivations* installable syntax. diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 7b8860a882c..0641e99ff66 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -814,7 +814,6 @@ std::vector> SourceExprCommand::parseInstallables( result.push_back(std::make_shared( store, DerivedPath::Built::parse(*store, s.substr(0, found), s.substr(found + 1)))); - settings.requireExperimentalFeature(Xp::ComputedDerivations); continue; } catch (BadStorePath &) { } catch (...) { diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc index 6b2dd02e6df..fa79cca6b2f 100644 --- a/src/libutil/experimental-features.cc +++ b/src/libutil/experimental-features.cc @@ -14,7 +14,6 @@ std::map stringifiedXpFeatures = { { Xp::NoUrlLiterals, "no-url-literals" }, { Xp::FetchClosure, "fetch-closure" }, { Xp::ReplFlake, "repl-flake" }, - { Xp::ComputedDerivations, "computed-derivations" }, }; const std::optional parseExperimentalFeature(const std::string_view & name) diff --git a/src/libutil/experimental-features.hh b/src/libutil/experimental-features.hh index 4cb2708ddf6..d09ab025c67 100644 --- a/src/libutil/experimental-features.hh +++ b/src/libutil/experimental-features.hh @@ -23,7 +23,6 @@ enum struct ExperimentalFeature NoUrlLiterals, FetchClosure, ReplFlake, - ComputedDerivations, // RFC 92 }; /** diff --git a/src/nix/nix.md b/src/nix/nix.md index 5d669e8b1b9..ede88ebde5e 100644 --- a/src/nix/nix.md +++ b/src/nix/nix.md @@ -132,8 +132,6 @@ the Nix store. Here are the recognised types of installables: * **Indexed store derivations**: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv^out` - *(Experimental, part of by the `computed-derivations` experimental feature.)* - Store derivations can be indexed with a non-empty comma-separated list of specific output names, or `*` meaning all ouptuts. This allows finer control versus just specifying a derivation (without diff --git a/tests/build-explicit-output.sh b/tests/build-explicit-output.sh index a4cb1c5ad0d..45320d6e3bc 100644 --- a/tests/build-explicit-output.sh +++ b/tests/build-explicit-output.sh @@ -2,9 +2,6 @@ source common.sh set -o pipefail -enableFeatures "computed-derivations" -restartDaemon - drv=$(nix eval -f multiple-outputs.nix --raw a.drvPath) if nix build "$drv^not-an-output" --no-link --json; then fail "'not-an-output' should fail to build" From 0e4ec98ae8a4ec60b24ebd676a9ace0f4ca81da8 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 15 Jul 2022 09:49:23 -0400 Subject: [PATCH 08/14] Fix typo in docs Thanks! Co-authored-by: Eelco Dolstra --- src/nix/nix.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nix/nix.md b/src/nix/nix.md index ede88ebde5e..29ad195aebd 100644 --- a/src/nix/nix.md +++ b/src/nix/nix.md @@ -133,7 +133,7 @@ the Nix store. Here are the recognised types of installables: * **Indexed store derivations**: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv^out` Store derivations can be indexed with a non-empty comma-separated list - of specific output names, or `*` meaning all ouptuts. This allows + of specific output names, or `*` meaning all outputs. This allows finer control versus just specifying a derivation (without `--derivation`) and getting all the outputs. From 12461e246b02371c6b6981b4e65985e9397474e1 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Fri, 15 Jul 2022 13:59:32 +0000 Subject: [PATCH 09/14] Leverage existing docs for new store-path^outputs syntax --- doc/manual/src/release-notes/rl-next.md | 2 +- src/nix/nix.md | 32 ++++++++++++++----------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md index 7047e242193..36b759a1080 100644 --- a/doc/manual/src/release-notes/rl-next.md +++ b/doc/manual/src/release-notes/rl-next.md @@ -1,3 +1,3 @@ # Release X.Y (202?-??-??) -* Add *indexed store derivations* installable syntax. +* Allow explicitly selecting outputs with *store derivations* installable syntax too. diff --git a/src/nix/nix.md b/src/nix/nix.md index 29ad195aebd..81193602495 100644 --- a/src/nix/nix.md +++ b/src/nix/nix.md @@ -130,17 +130,6 @@ the Nix store. Here are the recognised types of installables: If you want to operate on the store derivation itself, pass the `--derivation` flag. -* **Indexed store derivations**: `/nix/store/p7gp6lxdg32h4ka1q398wd9r2zkbbz2v-hello-2.10.drv^out` - - Store derivations can be indexed with a non-empty comma-separated list - of specific output names, or `*` meaning all outputs. This allows - finer control versus just specifying a derivation (without - `--derivation`) and getting all the outputs. - - This is especially useful for (currently unstable) floating content - addressed derivations, which do not have precomputed output paths that - can be used instead. - * **Nix attributes**: `--file /path/to/nixpkgs hello` When the `-f` / `--file` *path* option is given, installables are @@ -175,6 +164,13 @@ operate are determined as follows: … ``` + and likewise, using a store path to a "drv" file to specify the derivation: + + ```console + # nix build '/nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^dev,static' + … + ``` + * You can also specify that *all* outputs should be used using the syntax *installable*`^*`. For example, the following shows the size of all outputs of the `glibc` package in the binary cache: @@ -188,9 +184,17 @@ operate are determined as follows: /nix/store/q6580lr01jpcsqs4r5arlh4ki2c1m9rv-glibc-2.33-123-dev 44200560 ``` -* If you didn't specify the desired outputs, but the derivation has an - attribute `meta.outputsToInstall`, Nix will use those outputs. For - example, since the package `nixpkgs#libxml2` has this attribute: + and likewise, again using a store path to a "drv" file to specify the derivation: + + ```console + # nix path-info -S --eval-store auto --store https://cache.nixos.org '/nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^*' + … + ``` + +* If you didn't specify the desired outputs, but the derivation comes + from an expression which has an attribute `meta.outputsToInstall`, Nix + will use those outputs. For example, since the package + `nixpkgs#libxml2` has this attribute: ```console # nix eval 'nixpkgs#libxml2.meta.outputsToInstall' From dc075dcdd0306adec911ec8d898b723f464f7c0a Mon Sep 17 00:00:00 2001 From: John Ericson Date: Mon, 12 Dec 2022 16:26:10 -0500 Subject: [PATCH 10/14] Apply suggestions from code review Co-authored-by: Eelco Dolstra --- src/libstore/derived-path.cc | 2 +- src/nix/nix.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstore/derived-path.cc b/src/libstore/derived-path.cc index 7fe797aa11f..05c2303dbf7 100644 --- a/src/libstore/derived-path.cc +++ b/src/libstore/derived-path.cc @@ -93,7 +93,7 @@ DerivedPath::Built DerivedPath::Built::parse(const Store & store, std::string_vi DerivedPath DerivedPath::parse(const Store & store, std::string_view s) { - size_t n = s.rfind("!"); + size_t n = s.find("!"); return n == s.npos ? (DerivedPath) DerivedPath::Opaque::parse(store, s) : (DerivedPath) DerivedPath::Built::parse(store, s.substr(0, n), s.substr(n + 1)); diff --git a/src/nix/nix.md b/src/nix/nix.md index 81193602495..6ff27e479ff 100644 --- a/src/nix/nix.md +++ b/src/nix/nix.md @@ -187,7 +187,7 @@ operate are determined as follows: and likewise, again using a store path to a "drv" file to specify the derivation: ```console - # nix path-info -S --eval-store auto --store https://cache.nixos.org '/nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^*' + # nix path-info -S '/nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^*' … ``` From c7cce3e4e1dc82c504bb4d717e55dce3b1ae008a Mon Sep 17 00:00:00 2001 From: John Ericson Date: Mon, 12 Dec 2022 16:29:29 -0500 Subject: [PATCH 11/14] Improve release notes --- doc/manual/src/release-notes/rl-next.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md index a56dc25a248..15c309bdb60 100644 --- a/doc/manual/src/release-notes/rl-next.md +++ b/doc/manual/src/release-notes/rl-next.md @@ -3,4 +3,13 @@ * The `repeat` and `enforce-determinism` options have been removed since they had been broken under many circumstances for a long time. -* Allow explicitly selecting outputs with *store derivations* installable syntax too. \ No newline at end of file +* Allow explicitly selecting outputs in a store derivation installable, just like we can do with other sorts of installables. + For example, + ```shell-session + $ nix-build /nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^dev` + ``` + now works just as + ```shell-session + $ nix-build glibc^dev` + ``` + does already. From d8c1c24c78ebeb1f695e29a489be567118eb073e Mon Sep 17 00:00:00 2001 From: John Ericson Date: Mon, 12 Dec 2022 17:32:24 -0500 Subject: [PATCH 12/14] Adjust docs --- src/nix/nix.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/nix/nix.md b/src/nix/nix.md index 6ff27e479ff..529d5f7967a 100644 --- a/src/nix/nix.md +++ b/src/nix/nix.md @@ -190,11 +190,9 @@ operate are determined as follows: # nix path-info -S '/nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^*' … ``` - -* If you didn't specify the desired outputs, but the derivation comes - from an expression which has an attribute `meta.outputsToInstall`, Nix - will use those outputs. For example, since the package - `nixpkgs#libxml2` has this attribute: +* If you didn't specify the desired outputs, but the derivation hs an + attribute `meta.outputsToInstall`, Nix will use those outputs. For + example, since the package `nixpkgs#libxml2` has this attribute: ```console # nix eval 'nixpkgs#libxml2.meta.outputsToInstall' @@ -204,6 +202,9 @@ operate are determined as follows: a command like `nix shell nixpkgs#libxml2` will provide only those two outputs by default. + Note that a store derivation (given by `.drv` file store path) doesn't have + any attributes like `meta`, and thus this case doesn't apply to it. + * Otherwise, Nix will use all outputs of the derivation. # Nix stores From c886b1856184fc180603435197a10ea20df8bcfb Mon Sep 17 00:00:00 2001 From: John Ericson Date: Mon, 12 Dec 2022 17:34:57 -0500 Subject: [PATCH 13/14] Merge new tests into `build.sh` --- tests/build-explicit-output.sh | 43 ---------------------------------- tests/build.sh | 42 +++++++++++++++++++++++++++++++++ tests/local.mk | 1 - 3 files changed, 42 insertions(+), 44 deletions(-) delete mode 100644 tests/build-explicit-output.sh diff --git a/tests/build-explicit-output.sh b/tests/build-explicit-output.sh deleted file mode 100644 index 45320d6e3bc..00000000000 --- a/tests/build-explicit-output.sh +++ /dev/null @@ -1,43 +0,0 @@ -source common.sh - -set -o pipefail - -drv=$(nix eval -f multiple-outputs.nix --raw a.drvPath) -if nix build "$drv^not-an-output" --no-link --json; then - fail "'not-an-output' should fail to build" -fi - -if nix build "$drv^" --no-link --json; then - fail "'empty outputs list' should fail to build" -fi - -if nix build "$drv^*nope" --no-link --json; then - fail "'* must be entire string' should fail to build" -fi - -nix build "$drv^first" --no-link --json | jq --exit-status ' - (.[0] | - (.drvPath | match(".*multiple-outputs-a.drv")) and - (.outputs | - (keys | length == 1) and - (.first | match(".*multiple-outputs-a-first")) and - (has("second") | not))) -' - -nix build "$drv^first,second" --no-link --json | jq --exit-status ' - (.[0] | - (.drvPath | match(".*multiple-outputs-a.drv")) and - (.outputs | - (keys | length == 2) and - (.first | match(".*multiple-outputs-a-first")) and - (.second | match(".*multiple-outputs-a-second")))) -' - -nix build "$drv^*" --no-link --json | jq --exit-status ' - (.[0] | - (.drvPath | match(".*multiple-outputs-a.drv")) and - (.outputs | - (keys | length == 2) and - (.first | match(".*multiple-outputs-a-first")) and - (.second | match(".*multiple-outputs-a-second")))) -' diff --git a/tests/build.sh b/tests/build.sh index 3a3d773b1f3..036fb037e2c 100644 --- a/tests/build.sh +++ b/tests/build.sh @@ -58,6 +58,48 @@ nix build -f multiple-outputs.nix --json 'e^*' --no-link | jq --exit-status ' (.outputs | keys == ["a", "b", "c"])) ' +# Test building from raw store path to drv not expression. + +drv=$(nix eval -f multiple-outputs.nix --raw a.drvPath) +if nix build "$drv^not-an-output" --no-link --json; then + fail "'not-an-output' should fail to build" +fi + +if nix build "$drv^" --no-link --json; then + fail "'empty outputs list' should fail to build" +fi + +if nix build "$drv^*nope" --no-link --json; then + fail "'* must be entire string' should fail to build" +fi + +nix build "$drv^first" --no-link --json | jq --exit-status ' + (.[0] | + (.drvPath | match(".*multiple-outputs-a.drv")) and + (.outputs | + (keys | length == 1) and + (.first | match(".*multiple-outputs-a-first")) and + (has("second") | not))) +' + +nix build "$drv^first,second" --no-link --json | jq --exit-status ' + (.[0] | + (.drvPath | match(".*multiple-outputs-a.drv")) and + (.outputs | + (keys | length == 2) and + (.first | match(".*multiple-outputs-a-first")) and + (.second | match(".*multiple-outputs-a-second")))) +' + +nix build "$drv^*" --no-link --json | jq --exit-status ' + (.[0] | + (.drvPath | match(".*multiple-outputs-a.drv")) and + (.outputs | + (keys | length == 2) and + (.first | match(".*multiple-outputs-a-first")) and + (.second | match(".*multiple-outputs-a-second")))) +' + # Make sure that `--impure` works (regression test for https://github.com/NixOS/nix/issues/6488) nix build --impure -f multiple-outputs.nix --json e --no-link | jq --exit-status ' (.[0] | diff --git a/tests/local.mk b/tests/local.mk index aff595d3b1d..340817ec31d 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -98,7 +98,6 @@ nix_tests = \ ssh-relay.sh \ plugins.sh \ build.sh \ - build-explicit-output.sh \ ca/nix-run.sh \ selfref-gc.sh ca/selfref-gc.sh \ db-migration.sh \ From 32ae715db1771342fc356f1521cdda9ecd453358 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Mon, 12 Dec 2022 17:37:45 -0500 Subject: [PATCH 14/14] Fix typos in the docs Thanks! Co-authored-by: Valentin Gagarin --- src/nix/nix.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nix/nix.md b/src/nix/nix.md index 529d5f7967a..723d3c87e98 100644 --- a/src/nix/nix.md +++ b/src/nix/nix.md @@ -184,13 +184,13 @@ operate are determined as follows: /nix/store/q6580lr01jpcsqs4r5arlh4ki2c1m9rv-glibc-2.33-123-dev 44200560 ``` - and likewise, again using a store path to a "drv" file to specify the derivation: + and likewise, using a store path to a "drv" file to specify the derivation: ```console # nix path-info -S '/nix/store/gzaflydcr6sb3567hap9q6srzx8ggdgg-glibc-2.33-78.drv^*' … ``` -* If you didn't specify the desired outputs, but the derivation hs an +* If you didn't specify the desired outputs, but the derivation has an attribute `meta.outputsToInstall`, Nix will use those outputs. For example, since the package `nixpkgs#libxml2` has this attribute: