aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/manual/src/release-notes/rl-next.md3
-rw-r--r--src/libexpr/primops.cc39
-rw-r--r--src/nix/main.cc1
-rw-r--r--tests/dyn-drv/dep-built-drv.sh9
-rw-r--r--tests/dyn-drv/eval-outputOf.sh80
-rw-r--r--tests/dyn-drv/local.mk4
-rw-r--r--tests/dyn-drv/recursive-mod-json.sh2
-rw-r--r--tests/dyn-drv/text-hashed-output.nix10
8 files changed, 144 insertions, 4 deletions
diff --git a/doc/manual/src/release-notes/rl-next.md b/doc/manual/src/release-notes/rl-next.md
index be922f95a..7ddb5ca00 100644
--- a/doc/manual/src/release-notes/rl-next.md
+++ b/doc/manual/src/release-notes/rl-next.md
@@ -19,3 +19,6 @@
- The JSON output for derived paths with are store paths is now a string, not an object with a single `path` field.
This only affects `nix-build --json` when "building" non-derivation things like fetched sources, which is a no-op.
+
+- Introduce a new [`outputOf`](@docroot@/language/builtins.md#builtins-outputOf) builtin.
+ It is part of the [`dynamic-derivations`](@docroot@/contributing/experimental-features.md#xp-feature-dynamic-derivations) experimental feature.
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index be78bca02..283f99a48 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -1838,6 +1838,45 @@ static RegisterPrimOp primop_readDir({
.fun = prim_readDir,
});
+/* Extend single element string context with another output. */
+static void prim_outputOf(EvalState & state, const PosIdx pos, Value * * args, Value & v)
+{
+ SingleDerivedPath drvPath = state.coerceToSingleDerivedPath(pos, *args[0], "while evaluating the first argument to builtins.outputOf");
+
+ std::string_view outputName = state.forceStringNoCtx(*args[1], pos, "while evaluating the second argument to builtins.outputOf");
+
+ state.mkSingleDerivedPathString(
+ SingleDerivedPath::Built {
+ .drvPath = make_ref<SingleDerivedPath>(drvPath),
+ .output = std::string { outputName },
+ },
+ v);
+}
+
+static RegisterPrimOp primop_outputOf({
+ .name = "__outputOf",
+ .args = {"derivation-reference", "output-name"},
+ .doc = R"(
+ Return the output path of a derivation, literally or using a placeholder if needed.
+
+ If the derivation has a statically-known output path (i.e. the derivation output is input-addressed, or fixed content-addresed), the output path will just be returned.
+ But if the derivation is content-addressed or if the derivation is itself not-statically produced (i.e. is the output of another derivation), a placeholder will be returned instead.
+
+ *`derivation reference`* must be a string that may contain a regular store path to a derivation, or may be a placeholder reference. If the derivation is produced by a derivation, you must explicitly select `drv.outPath`.
+ This primop can be chained arbitrarily deeply.
+ For instance,
+ ```nix
+ builtins.outputOf
+ (builtins.outputOf myDrv "out)
+ "out"
+ ```
+ will return a placeholder for the output of the output of `myDrv`.
+
+ This primop corresponds to the `^` sigil for derivable paths, e.g. as part of installable syntax on the command line.
+ )",
+ .fun = prim_outputOf,
+ .experimentalFeature = Xp::DynamicDerivations,
+});
/*************************************************************
* Creating files
diff --git a/src/nix/main.cc b/src/nix/main.cc
index c5a9c8b33..d05bac68e 100644
--- a/src/nix/main.cc
+++ b/src/nix/main.cc
@@ -359,6 +359,7 @@ void mainWrapped(int argc, char * * argv)
experimentalFeatureSettings.experimentalFeatures = {
Xp::Flakes,
Xp::FetchClosure,
+ Xp::DynamicDerivations,
};
evalSettings.pureEval = false;
EvalState state({}, openStore("dummy://"));
diff --git a/tests/dyn-drv/dep-built-drv.sh b/tests/dyn-drv/dep-built-drv.sh
new file mode 100644
index 000000000..8c4a45e3b
--- /dev/null
+++ b/tests/dyn-drv/dep-built-drv.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+source common.sh
+
+out1=$(nix-build ./text-hashed-output.nix -A hello --no-out-link)
+
+clearStore
+
+expectStderr 1 nix-build ./text-hashed-output.nix -A wrapper --no-out-link | grepQuiet "Dependencies on the outputs of dynamic derivations are not yet supported"
diff --git a/tests/dyn-drv/eval-outputOf.sh b/tests/dyn-drv/eval-outputOf.sh
new file mode 100644
index 000000000..99d917c06
--- /dev/null
+++ b/tests/dyn-drv/eval-outputOf.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+
+source ./common.sh
+
+# Without the dynamic-derivations XP feature, we don't have the builtin.
+nix --experimental-features 'nix-command' eval --impure --expr \
+ 'assert ! (builtins ? outputOf); ""'
+
+# Test that a string is required.
+#
+# We currently require a string to be passed, rather than a derivation
+# object that could be coerced to a string. We might liberalise this in
+# the future so it does work, but there are some design questions to
+# resolve first. Adding a test so we don't liberalise it by accident.
+expectStderr 1 nix --experimental-features 'nix-command dynamic-derivations' eval --impure --expr \
+ 'builtins.outputOf (import ../dependencies.nix) "out"' \
+ | grepQuiet "value is a set while a string was expected"
+
+# Test that "DrvDeep" string contexts are not supported at this time
+#
+# Like the above, this is a restriction we could relax later.
+expectStderr 1 nix --experimental-features 'nix-command dynamic-derivations' eval --impure --expr \
+ 'builtins.outputOf (import ../dependencies.nix).drvPath "out"' \
+ | grepQuiet "has a context which refers to a complete source and binary closure. This is not supported at this time"
+
+# Test using `builtins.outputOf` with static derivations
+testStaticHello () {
+ nix eval --impure --expr \
+ 'with (import ./text-hashed-output.nix); let
+ a = hello.outPath;
+ b = builtins.outputOf (builtins.unsafeDiscardOutputDependency hello.drvPath) "out";
+ in builtins.trace a
+ (builtins.trace b
+ (assert a == b; null))'
+}
+
+# Test with a regular old input-addresed derivation
+#
+# `builtins.outputOf` works without ca-derivations and doesn't create a
+# placeholder but just returns the output path.
+testStaticHello
+
+# Test with content addressed derivation.
+NIX_TESTS_CA_BY_DEFAULT=1 testStaticHello
+
+# Test with derivation-producing derivation
+#
+# This is hardly different from the preceding cases, except that we're
+# only taking 1 outputOf out of 2 possible outputOfs. Note that
+# `.outPath` could be defined as `outputOf drvPath`, which is what we're
+# testing here. The other `outputOf` that we're not testing here is the
+# use of _dynamic_ derivations.
+nix eval --impure --expr \
+ 'with (import ./text-hashed-output.nix); let
+ a = producingDrv.outPath;
+ b = builtins.outputOf (builtins.builtins.unsafeDiscardOutputDependency producingDrv.drvPath) "out";
+ in builtins.trace a
+ (builtins.trace b
+ (assert a == b; null))'
+
+# Test with unbuilt output of derivation-producing derivation.
+#
+# This function similar to `testStaticHello` used above, but instead of
+# checking the property on a constant derivation, we check it on a
+# derivation that's from another derivation's output (outPath).
+testDynamicHello () {
+ nix eval --impure --expr \
+ 'with (import ./text-hashed-output.nix); let
+ a = builtins.outputOf producingDrv.outPath "out";
+ b = builtins.outputOf (builtins.outputOf (builtins.unsafeDiscardOutputDependency producingDrv.drvPath) "out") "out";
+ in builtins.trace a
+ (builtins.trace b
+ (assert a == b; null))'
+}
+
+# inner dynamic derivation is input-addressed
+testDynamicHello
+
+# inner dynamic derivation is content-addressed
+NIX_TESTS_CA_BY_DEFAULT=1 testDynamicHello
diff --git a/tests/dyn-drv/local.mk b/tests/dyn-drv/local.mk
index b087ecd1c..0ce7cd37d 100644
--- a/tests/dyn-drv/local.mk
+++ b/tests/dyn-drv/local.mk
@@ -1,7 +1,9 @@
dyn-drv-tests := \
$(d)/text-hashed-output.sh \
$(d)/recursive-mod-json.sh \
- $(d)/build-built-drv.sh
+ $(d)/build-built-drv.sh \
+ $(d)/eval-outputOf.sh \
+ $(d)/dep-built-drv.sh
install-tests-groups += dyn-drv
diff --git a/tests/dyn-drv/recursive-mod-json.sh b/tests/dyn-drv/recursive-mod-json.sh
index 070c5c2cb..0698b81bd 100644
--- a/tests/dyn-drv/recursive-mod-json.sh
+++ b/tests/dyn-drv/recursive-mod-json.sh
@@ -3,6 +3,8 @@ source common.sh
# FIXME
if [[ $(uname) != Linux ]]; then skipTest "Not running Linux"; fi
+export NIX_TESTS_CA_BY_DEFAULT=1
+
enableFeatures 'recursive-nix'
restartDaemon
diff --git a/tests/dyn-drv/text-hashed-output.nix b/tests/dyn-drv/text-hashed-output.nix
index a700fd102..99203b518 100644
--- a/tests/dyn-drv/text-hashed-output.nix
+++ b/tests/dyn-drv/text-hashed-output.nix
@@ -12,9 +12,6 @@ rec {
mkdir -p $out
echo "Hello World" > $out/hello
'';
- __contentAddressed = true;
- outputHashMode = "recursive";
- outputHashAlgo = "sha256";
};
producingDrv = mkDerivation {
name = "hello.drv";
@@ -26,4 +23,11 @@ rec {
outputHashMode = "text";
outputHashAlgo = "sha256";
};
+ wrapper = mkDerivation {
+ name = "use-dynamic-drv-in-non-dynamic-drv";
+ buildCommand = ''
+ echo "Copying the output of the dynamic derivation"
+ cp -r ${builtins.outputOf producingDrv.outPath "out"} $out
+ '';
+ };
}