Skip to content

Commit d69e6ae

Browse files
authored
Merge pull request #337 from DeterminateSystems/fix-302
builtins.getFlake fixes
2 parents 0e0935f + 850279b commit d69e6ae

5 files changed

Lines changed: 59 additions & 4 deletions

File tree

src/libexpr/primops.cc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2360,6 +2360,23 @@ static RegisterPrimOp primop_hashFile({
23602360
.fun = prim_hashFile,
23612361
});
23622362

2363+
static RegisterPrimOp primop_narHash({
2364+
.name = "__narHash",
2365+
.args = {"p"},
2366+
.doc = R"(
2367+
Return an SRI representation of the SHA-256 hash of the NAR serialisation of the path *p*.
2368+
)",
2369+
.fun =
2370+
[](EvalState & state, const PosIdx pos, Value ** args, Value & v) {
2371+
auto path = state.realisePath(pos, *args[0]);
2372+
auto hash =
2373+
fetchToStore2(state.fetchSettings, *state.store, path.resolveSymlinks(), FetchMode::DryRun).second;
2374+
v.mkString(hash.to_string(HashFormat::SRI, true), state.mem);
2375+
},
2376+
// FIXME: may be useful to expose to the user.
2377+
.internal = true,
2378+
});
2379+
23632380
static const Value & fileTypeToString(EvalState & state, SourceAccessor::Type type)
23642381
{
23652382
struct Constants

src/libexpr/primops/fetchTree.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,16 @@ void emitTreeAttrs(
3030
{
3131
auto attrs = state.buildBindings(100);
3232

33-
state.mkStorePathString(storePath, attrs.alloc(state.s.outPath));
33+
auto & vStorePath = attrs.alloc(state.s.outPath);
34+
state.mkStorePathString(storePath, vStorePath);
3435

3536
// FIXME: support arbitrary input attributes.
3637

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

4044
if (input.getType() == "git")
4145
attrs.alloc("submodules").mkBool(fetchers::maybeGetBoolAttr(input.attrs, "submodules").value_or(false));

src/libflake/flake-primops.cc

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,16 @@ namespace nix::flake::primops {
3535
PrimOp getFlake(const Settings & settings)
3636
{
3737
auto prim_getFlake = [&settings](EvalState & state, const PosIdx pos, Value ** args, Value & v) {
38+
NixStringContext context;
3839
std::string flakeRefS(
39-
state.forceStringNoCtx(*args[0], pos, "while evaluating the argument passed to builtins.getFlake"));
40+
state.forceString(*args[0], context, pos, "while evaluating the argument passed to builtins.getFlake"));
41+
auto rewrites = state.realiseContext(context);
42+
flakeRefS = state.devirtualize(rewriteStrings(flakeRefS, rewrites), context);
43+
if (hasContext(context))
44+
// FIXME: this should really be an error.
45+
warn(
46+
"In 'builtins.getFlake', the flakeref '%s' has string context, but that's not allowed. This may become a fatal error in the future.",
47+
flakeRefS);
4048
auto flakeRef = nix::parseFlakeRef(state.fetchSettings, flakeRefS, {}, true);
4149
if (state.settings.pureEval && !flakeRef.input.isLocked(state.fetchSettings))
4250
throw Error(
@@ -125,7 +133,9 @@ static void prim_flakeRefToString(EvalState & state, const PosIdx pos, Value **
125133
{
126134
state.forceAttrs(*args[0], noPos, "while evaluating the argument passed to builtins.flakeRefToString");
127135
fetchers::Attrs attrs;
136+
NixStringContext context;
128137
for (const auto & attr : *args[0]->attrs()) {
138+
state.forceValue(*attr.value, attr.pos);
129139
auto t = attr.value->type();
130140
if (t == nInt) {
131141
auto intValue = attr.value->integer().value;
@@ -142,7 +152,9 @@ static void prim_flakeRefToString(EvalState & state, const PosIdx pos, Value **
142152
} else if (t == nBool) {
143153
attrs.emplace(state.symbols[attr.name], Explicit<bool>{attr.value->boolean()});
144154
} else if (t == nString) {
145-
attrs.emplace(state.symbols[attr.name], std::string(attr.value->string_view()));
155+
auto s = state.forceString(
156+
*attr.value, context, attr.pos, "while evaluating an attribute in 'builtins.flakeRefToString'");
157+
attrs.emplace(state.symbols[attr.name], std::string(s));
146158
} else {
147159
state
148160
.error<EvalError>(
@@ -154,7 +166,7 @@ static void prim_flakeRefToString(EvalState & state, const PosIdx pos, Value **
154166
}
155167
}
156168
auto flakeRef = FlakeRef::fromAttrs(state.fetchSettings, attrs);
157-
v.mkString(flakeRef.to_string(), state.mem);
169+
v.mkString(flakeRef.to_string(), context, state.mem);
158170
}
159171

160172
nix::PrimOp flakeRefToString({
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/usr/bin/env bash
2+
3+
source ./common.sh
4+
5+
createFlake1
6+
7+
mkdir -p "$flake1Dir/subflake"
8+
cat > "$flake1Dir/subflake/flake.nix" <<EOF
9+
{
10+
outputs = { self }:
11+
let
12+
parentFlake = builtins.getFlake (builtins.flakeRefToString { type = "path"; path = self.sourceInfo.outPath; narHash = self.narHash; });
13+
in {
14+
x = parentFlake.number;
15+
};
16+
}
17+
EOF
18+
git -C "$flake1Dir" add subflake/flake.nix
19+
20+
expectStderr 0 nix eval "$flake1Dir/subflake#x" | grepQuiet "This may become a fatal error in the future"
21+
[[ $(nix eval "$flake1Dir/subflake#x") = 123 ]]

tests/functional/flakes/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ suites += {
3737
'build-time-flake-inputs.sh',
3838
'substitution.sh',
3939
'shallow.sh',
40+
'get-flake.sh',
4041
],
4142
'workdir' : meson.current_source_dir(),
4243
}

0 commit comments

Comments
 (0)