Skip to content

Commit

Permalink
Create outputOf primop.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ericson2314 committed Jan 24, 2023
1 parent bdd9151 commit e57531c
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 0 deletions.
44 changes: 44 additions & 0 deletions src/libexpr/primops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1765,6 +1765,50 @@ 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)
{
PathSet context;
Path path = state.coerceToPath(pos, *args[0], context, "while evaluating the first argument to builtins.outputOf");

std::string_view outputName = state.forceStringNoCtx(*args[1], pos, "while evaluating teh second argument to builtins.outputOf");

Path path2;
try {
auto p = DownstreamPlaceholder::parse(path);
path2 = DownstreamPlaceholder { p, outputName }.render();
} catch (BadHash &) {
path2 = DownstreamPlaceholder { state.store->parseStorePath(path), outputName }.render();
}

if (context.size() != 1)
throw EvalError({
.msg = hintfmt("path '%s' should have exactly one item in string context, but has", context.size()),
.errPos = state.positions[pos],
});
const std::string & ctxRaw = *context.begin();
size_t off = ctxRaw[0] == '=' || ctxRaw[0] == '!' ? 1 : 0;
PathSet context2 = { "!" + outputName + "!" + ctxRaw[off] };

v.mkString(path2, context2);
}

static RegisterPrimOp primop_outputOf({
.name = "__outputOf",
.args = {"drv path", "output name"},
.doc = R"(
Return path (actually placeholder path) to the output of the given drv.
The drv path may itself be a placeholder, which permits chaining this primop.
For instance, `builtins.outputOf (builtins.outputOf myDrv "out) "out"`
will return a placeholder for the output of the output of `myDrv`,
interpreted as a derivation.
It may help to compare to the `->` operator in C, which can also by
chained. E.g. compare the above example to `drv->out->out`.
)",
.fun = prim_outputOf,
});

/*************************************************************
* Creating files
Expand Down
8 changes: 8 additions & 0 deletions src/libstore/derivations.cc
Original file line number Diff line number Diff line change
Expand Up @@ -859,6 +859,14 @@ std::string DownstreamPlaceholder::render() const
}


DownstreamPlaceholder DownstreamPlaceholder::parse(std::string_view s)
{
assert(s[0] == '/');
s = s.substr(1);
return { Hash::parseNonSRIUnprefixed(s, htSHA256) };
}


inline Hash DownstreamPlaceholder::worker1(const StorePath & drvPath, std::string_view outputName)
{
auto drvNameWithExtension = drvPath.name();
Expand Down
3 changes: 3 additions & 0 deletions src/libstore/derivations.hh
Original file line number Diff line number Diff line change
Expand Up @@ -345,13 +345,16 @@ public:
dependency which is a CA derivation. */
std::string render() const;

static DownstreamPlaceholder parse(std::string_view);

// For CA derivations
DownstreamPlaceholder(const StorePath & drvPath, std::string_view outputName);

// For computed derivations
DownstreamPlaceholder(const DownstreamPlaceholder & placeholder, std::string_view outputName);

private:
DownstreamPlaceholder(Hash && h) : hash(std::move(h)) {}
static inline Hash worker1(const StorePath & drvPath, std::string_view outputName);
static inline Hash worker2(const DownstreamPlaceholder & placeholder, std::string_view outputName);
};
Expand Down
13 changes: 13 additions & 0 deletions tests/dyn-drv/dep-built-drv.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash

source common.sh

feats=(--experimental-features 'nix-command ca-derivations')

out1=$(nix-build "${feats[@]}" ./text-hashed-output.nix -A root --no-out-link)

clearStore

out2=$(nix-build "${feats[@]}" ./text-hashed-output.nix -A wrapper --no-out-link)

diff -r $out1 $out2
37 changes: 37 additions & 0 deletions tests/dyn-drv/eval-outputOf.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env bash

source common.sh

feats=(--experimental-features 'nix-command ca-derivations')

nix eval "${feats[@]}" --impure --expr \
'with (import ./text-hashed-output.nix); let
a = root.outPath;
b = builtins.outputOf root.drvPath "out";
in builtins.trace a
(builtins.trace b
(assert a == b; null))'

nix eval "${feats[@]}" --impure --expr \
'with (import ./text-hashed-output.nix); let
a = dependent.outPath;
b = builtins.outputOf dependent.drvPath "out";
in builtins.trace a
(builtins.trace b
(assert a == b; null))'

nix eval "${feats[@]}" --impure --expr \
'with (import ./text-hashed-output.nix); let
a = builtins.outputOf dependent.outPath "out";
b = builtins.outputOf dependent.out "out";
in builtins.trace a
(builtins.trace b
(assert a == b; null))'

nix eval "${feats[@]}" --impure --expr \
'with (import ./text-hashed-output.nix); let
a = builtins.outputOf dependent.out "out";
b = builtins.outputOf (builtins.outputOf dependent.drvPath "out") "out";
in builtins.trace a
(builtins.trace b
(assert a == b; null))'
10 changes: 10 additions & 0 deletions tests/dyn-drv/text-hashed-output.nix
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,14 @@ rec {
outputHashMode = "text";
outputHashAlgo = "sha256";
};
wrapper = mkDerivation {
name = "put-it-all-together";
buildCommand = ''
echo "Copying the output of the dynamic derivation"
cp -r ${builtins.outputOf dependent.out "out"} $out
'';
__contentAddressed = true;
outputHashMode = "recursive";
outputHashAlgo = "sha256";
};
}
2 changes: 2 additions & 0 deletions tests/local.mk
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ nix_tests = \
ca/import-derivation.sh \
dyn-drv/text-hashed-output.sh \
dyn-drv/build-built-drv.sh \
dyn-drv/eval-outputOf.sh \
dyn-drv/dep-built-drv.sh \
nix_path.sh \
case-hack.sh \
placeholders.sh \
Expand Down

0 comments on commit e57531c

Please sign in to comment.