aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/manual/src/release-notes/rl-next.md2
-rw-r--r--src/libcmd/installables.cc38
-rw-r--r--src/libstore/derived-path.cc11
-rw-r--r--src/libstore/derived-path.hh2
-rw-r--r--src/libutil/experimental-features.cc1
-rw-r--r--src/libutil/experimental-features.hh1
-rw-r--r--src/nix/nix.md12
-rw-r--r--tests/build-explicit-output.sh18
-rw-r--r--tests/build.sh12
-rw-r--r--tests/local.mk1
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 \