diff options
-rw-r--r-- | doc/manual/src/release-notes/rl-next.md | 2 | ||||
-rw-r--r-- | src/libcmd/installables.cc | 38 | ||||
-rw-r--r-- | src/libstore/derived-path.cc | 11 | ||||
-rw-r--r-- | src/libstore/derived-path.hh | 2 | ||||
-rw-r--r-- | src/libutil/experimental-features.cc | 1 | ||||
-rw-r--r-- | src/libutil/experimental-features.hh | 1 | ||||
-rw-r--r-- | src/nix/nix.md | 12 | ||||
-rw-r--r-- | tests/build-explicit-output.sh | 18 | ||||
-rw-r--r-- | tests/build.sh | 12 | ||||
-rw-r--r-- | tests/local.mk | 1 |
10 files changed, 84 insertions, 14 deletions
diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md index 78ae99f4b..3bb12c013 100644 --- a/doc/manual/src/release-notes/rl-next.md +++ b/doc/manual/src/release-notes/rl-next.md @@ -1,2 +1,4 @@ # Release X.Y (202?-??-??) +* Add experimental *indexed store derivations* installable syntax, part of the + the `computed-derivations` experimental feature. diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 59162c4df..b78581a7c 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -436,6 +436,26 @@ struct InstallableStorePath : Installable } }; +struct InstallableIndexedStorePath : Installable +{ + ref<Store> store; + DerivedPath::Built req; + + InstallableIndexedStorePath(ref<Store> store, DerivedPath::Built && req) + : store(store), req(std::move(req)) + { } + + std::string what() const override + { + return req.to_string(*store); + } + + DerivedPaths toDerivedPaths() override + { + return { req }; + } +}; + DerivedPaths InstallableValue::toDerivedPaths() { DerivedPaths res; @@ -796,7 +816,23 @@ std::vector<std::shared_ptr<Installable>> SourceExprCommand::parseInstallables( for (auto & s : ss) { std::exception_ptr ex; - if (s.find('/') != std::string::npos) { + auto found = s.rfind('^'); + if (found != std::string::npos) { + try { + result.push_back(std::make_shared<InstallableIndexedStorePath>( + store, + DerivedPath::Built::parse(*store, s.substr(0, found), s.substr(found + 1)))); + settings.requireExperimentalFeature(Xp::ComputedDerivations); + 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<InstallableStorePath>(store, store->followLinksToStorePath(s))); continue; diff --git a/src/libstore/derived-path.cc b/src/libstore/derived-path.cc index 44587ae78..11a3f5e23 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<std::string> outputs; if (outputsS != "*") outputs = tokenizeString<std::set<std::string>>(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 24a0ae773..fab1292a7 100644 --- a/src/libstore/derived-path.hh +++ b/src/libstore/derived-path.hh @@ -47,7 +47,7 @@ struct DerivedPathBuilt { std::set<std::string> 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> store) const; bool operator < (const DerivedPathBuilt & b) const diff --git a/src/libutil/experimental-features.cc b/src/libutil/experimental-features.cc index fa79cca6b..6b2dd02e6 100644 --- a/src/libutil/experimental-features.cc +++ b/src/libutil/experimental-features.cc @@ -14,6 +14,7 @@ std::map<ExperimentalFeature, std::string> stringifiedXpFeatures = { { Xp::NoUrlLiterals, "no-url-literals" }, { Xp::FetchClosure, "fetch-closure" }, { Xp::ReplFlake, "repl-flake" }, + { Xp::ComputedDerivations, "computed-derivations" }, }; const std::optional<ExperimentalFeature> parseExperimentalFeature(const std::string_view & name) diff --git a/src/libutil/experimental-features.hh b/src/libutil/experimental-features.hh index d09ab025c..4cb2708dd 100644 --- a/src/libutil/experimental-features.hh +++ b/src/libutil/experimental-features.hh @@ -23,6 +23,7 @@ enum struct ExperimentalFeature NoUrlLiterals, FetchClosure, ReplFlake, + ComputedDerivations, // RFC 92 }; /** diff --git a/src/nix/nix.md b/src/nix/nix.md index d48682a94..32112d38d 100644 --- a/src/nix/nix.md +++ b/src/nix/nix.md @@ -130,6 +130,18 @@ 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` + + *(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. + + 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 000000000..68fd2f128 --- /dev/null +++ b/tests/build-explicit-output.sh @@ -0,0 +1,18 @@ +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" +fi + +nix build "$drv^first" --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))) +' diff --git a/tests/build.sh b/tests/build.sh index fc6825e25..b3c572016 100644 --- a/tests/build.sh +++ b/tests/build.sh @@ -8,13 +8,15 @@ set -o pipefail nix build -f multiple-outputs.nix --json a b --no-link | jq --exit-status ' (.[0] | (.drvPath | match(".*multiple-outputs-a.drv")) and - (.outputs | keys | length == 2) and - (.outputs.first | match(".*multiple-outputs-a-first")) and - (.outputs.second | match(".*multiple-outputs-a-second"))) + (.outputs | + (keys | length == 2) and + (.first | match(".*multiple-outputs-a-first")) and + (.second | match(".*multiple-outputs-a-second")))) and (.[1] | (.drvPath | match(".*multiple-outputs-b.drv")) and - (.outputs | keys | length == 1) and - (.outputs.out | match(".*multiple-outputs-b"))) + (.outputs | + (keys | length == 1) and + (.out | match(".*multiple-outputs-b")))) ' # Test output selection using the '^' syntax. diff --git a/tests/local.mk b/tests/local.mk index dd4924f00..9734df08b 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -98,6 +98,7 @@ 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 \ |