Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/libexpr/primops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2360,6 +2360,23 @@ static RegisterPrimOp primop_hashFile({
.fun = prim_hashFile,
});

static RegisterPrimOp primop_narHash({
.name = "__narHash",
.args = {"p"},
.doc = R"(
Return an SRI representation of the SHA-256 hash of the NAR serialisation of the path *p*.
)",
.fun =
[](EvalState & state, const PosIdx pos, Value ** args, Value & v) {
auto path = state.realisePath(pos, *args[0]);
auto hash =
fetchToStore2(state.fetchSettings, *state.store, path.resolveSymlinks(), FetchMode::DryRun).second;
v.mkString(hash.to_string(HashFormat::SRI, true), state.mem);
},
// FIXME: may be useful to expose to the user.
.internal = true,
});

static const Value & fileTypeToString(EvalState & state, SourceAccessor::Type type)
{
struct Constants
Expand Down
6 changes: 5 additions & 1 deletion src/libexpr/primops/fetchTree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,16 @@ void emitTreeAttrs(
{
auto attrs = state.buildBindings(100);

state.mkStorePathString(storePath, attrs.alloc(state.s.outPath));
auto & vStorePath = attrs.alloc(state.s.outPath);
state.mkStorePathString(storePath, vStorePath);

// FIXME: support arbitrary input attributes.

if (auto narHash = input.getNarHash())
attrs.alloc("narHash").mkString(narHash->to_string(HashFormat::SRI, true), state.mem);
else
// Lazily compute the NAR hash for backward compatibility.
attrs.alloc("narHash").mkApp(*get(state.internalPrimOps, "narHash"), &vStorePath);

if (input.getType() == "git")
attrs.alloc("submodules").mkBool(fetchers::maybeGetBoolAttr(input.attrs, "submodules").value_or(false));
Expand Down
18 changes: 15 additions & 3 deletions src/libflake/flake-primops.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,16 @@ namespace nix::flake::primops {
PrimOp getFlake(const Settings & settings)
{
auto prim_getFlake = [&settings](EvalState & state, const PosIdx pos, Value ** args, Value & v) {
NixStringContext context;
std::string flakeRefS(
state.forceStringNoCtx(*args[0], pos, "while evaluating the argument passed to builtins.getFlake"));
state.forceString(*args[0], context, pos, "while evaluating the argument passed to builtins.getFlake"));
auto rewrites = state.realiseContext(context);
flakeRefS = state.devirtualize(rewriteStrings(flakeRefS, rewrites), context);
if (hasContext(context))
// FIXME: this should really be an error.
warn(
"In 'builtins.getFlake', the flakeref '%s' has string context, but that's not allowed. This may become a fatal error in the future.",
flakeRefS);
auto flakeRef = nix::parseFlakeRef(state.fetchSettings, flakeRefS, {}, true);
if (state.settings.pureEval && !flakeRef.input.isLocked(state.fetchSettings))
throw Error(
Expand Down Expand Up @@ -125,7 +133,9 @@ static void prim_flakeRefToString(EvalState & state, const PosIdx pos, Value **
{
state.forceAttrs(*args[0], noPos, "while evaluating the argument passed to builtins.flakeRefToString");
fetchers::Attrs attrs;
NixStringContext context;
for (const auto & attr : *args[0]->attrs()) {
state.forceValue(*attr.value, attr.pos);
auto t = attr.value->type();
if (t == nInt) {
auto intValue = attr.value->integer().value;
Expand All @@ -142,7 +152,9 @@ static void prim_flakeRefToString(EvalState & state, const PosIdx pos, Value **
} else if (t == nBool) {
attrs.emplace(state.symbols[attr.name], Explicit<bool>{attr.value->boolean()});
} else if (t == nString) {
attrs.emplace(state.symbols[attr.name], std::string(attr.value->string_view()));
auto s = state.forceString(
*attr.value, context, attr.pos, "while evaluating an attribute in 'builtins.flakeRefToString'");
attrs.emplace(state.symbols[attr.name], std::string(s));
} else {
state
.error<EvalError>(
Expand All @@ -154,7 +166,7 @@ static void prim_flakeRefToString(EvalState & state, const PosIdx pos, Value **
}
}
auto flakeRef = FlakeRef::fromAttrs(state.fetchSettings, attrs);
v.mkString(flakeRef.to_string(), state.mem);
v.mkString(flakeRef.to_string(), context, state.mem);
}

nix::PrimOp flakeRefToString({
Expand Down
21 changes: 21 additions & 0 deletions tests/functional/flakes/get-flake.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash

source ./common.sh

createFlake1

mkdir -p "$flake1Dir/subflake"
cat > "$flake1Dir/subflake/flake.nix" <<EOF
{
outputs = { self }:
let
parentFlake = builtins.getFlake (builtins.flakeRefToString { type = "path"; path = self.sourceInfo.outPath; narHash = self.narHash; });
in {
x = parentFlake.number;
};
}
EOF
git -C "$flake1Dir" add subflake/flake.nix

expectStderr 0 nix eval "$flake1Dir/subflake#x" | grepQuiet "This may become a fatal error in the future"
[[ $(nix eval "$flake1Dir/subflake#x") = 123 ]]
1 change: 1 addition & 0 deletions tests/functional/flakes/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ suites += {
'build-time-flake-inputs.sh',
'substitution.sh',
'shallow.sh',
'get-flake.sh',
],
'workdir' : meson.current_source_dir(),
}