Skip to content

Commit 7bb167d

Browse files
authored
Merge pull request #108 from DeterminateSystems/fix-deep-overrides
Fix deep overrides
2 parents 3a8bd3b + 0e352a6 commit 7bb167d

File tree

2 files changed

+93
-14
lines changed

2 files changed

+93
-14
lines changed

src/libflake/flake.cc

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ static void parseFlakeInputAttr(
8585

8686
static FlakeInput parseFlakeInput(
8787
EvalState & state,
88-
std::string_view inputName,
8988
Value * value,
9089
const PosIdx pos,
9190
const InputAttrPath & lockRootAttrPath,
@@ -155,8 +154,8 @@ static FlakeInput parseFlakeInput(
155154
input.ref = parseFlakeRef(state.fetchSettings, *url, {}, true, input.isFlake, true);
156155
}
157156

158-
if (!input.follows && !input.ref)
159-
input.ref = FlakeRef::fromAttrs(state.fetchSettings, {{"type", "indirect"}, {"id", std::string(inputName)}});
157+
if (input.ref && input.follows)
158+
throw Error("flake input has both a flake reference and a follows attribute, at %s", state.positions[pos]);
160159

161160
return input;
162161
}
@@ -185,7 +184,6 @@ static std::pair<std::map<FlakeId, FlakeInput>, fetchers::Attrs> parseFlakeInput
185184
} else {
186185
inputs.emplace(inputName,
187186
parseFlakeInput(state,
188-
inputName,
189187
inputAttr.value,
190188
inputAttr.pos,
191189
lockRootAttrPath,
@@ -467,18 +465,27 @@ LockedFlake lockFlake(
467465

468466
/* Get the overrides (i.e. attributes of the form
469467
'inputs.nixops.inputs.nixpkgs.url = ...'). */
470-
for (auto & [id, input] : flakeInputs) {
468+
std::function<void(const FlakeInput & input, const InputAttrPath & prefix)> addOverrides;
469+
addOverrides = [&](const FlakeInput & input, const InputAttrPath & prefix)
470+
{
471471
for (auto & [idOverride, inputOverride] : input.overrides) {
472-
auto inputAttrPath(inputAttrPathPrefix);
473-
inputAttrPath.push_back(id);
472+
auto inputAttrPath(prefix);
474473
inputAttrPath.push_back(idOverride);
475-
overrides.emplace(inputAttrPath,
476-
OverrideTarget {
477-
.input = inputOverride,
478-
.sourcePath = sourcePath,
479-
.parentInputAttrPath = inputAttrPathPrefix
480-
});
474+
if (inputOverride.ref || inputOverride.follows)
475+
overrides.emplace(inputAttrPath,
476+
OverrideTarget {
477+
.input = inputOverride,
478+
.sourcePath = sourcePath,
479+
.parentInputAttrPath = inputAttrPathPrefix
480+
});
481+
addOverrides(inputOverride, inputAttrPath);
481482
}
483+
};
484+
485+
for (auto & [id, input] : flakeInputs) {
486+
auto inputAttrPath(inputAttrPathPrefix);
487+
inputAttrPath.push_back(id);
488+
addOverrides(input, inputAttrPath);
482489
}
483490

484491
/* Check whether this input has overrides for a
@@ -534,7 +541,8 @@ LockedFlake lockFlake(
534541
continue;
535542
}
536543

537-
assert(input.ref);
544+
if (!input.ref)
545+
input.ref = FlakeRef::fromAttrs(state.fetchSettings, {{"type", "indirect"}, {"id", std::string(id)}});
538546

539547
auto overridenParentPath =
540548
input.ref->input.isRelative()

tests/functional/flakes/follow-paths.sh

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,3 +359,74 @@ rm "$flakeFollowsCustomUrlA"/flake.lock
359359
json=$(nix flake metadata "$flakeFollowsCustomUrlA" --override-input B/C "$flakeFollowsCustomUrlD" --json)
360360
echo "$json" | jq .locks.nodes.C.original
361361
[[ $(echo "$json" | jq -r .locks.nodes.C.original.path) = './flakeC' ]]
362+
363+
# Test deep overrides, e.g. `inputs.B.inputs.C.inputs.D.follows = ...`.
364+
365+
cat <<EOF > $flakeFollowsD/flake.nix
366+
{ outputs = _: {}; }
367+
EOF
368+
cat <<EOF > $flakeFollowsC/flake.nix
369+
{
370+
inputs.D.url = "path:nosuchflake";
371+
outputs = _: {};
372+
}
373+
EOF
374+
cat <<EOF > $flakeFollowsB/flake.nix
375+
{
376+
inputs.C.url = "path:$flakeFollowsC";
377+
outputs = _: {};
378+
}
379+
EOF
380+
cat <<EOF > $flakeFollowsA/flake.nix
381+
{
382+
inputs.B.url = "path:$flakeFollowsB";
383+
inputs.D.url = "path:$flakeFollowsD";
384+
inputs.B.inputs.C.inputs.D.follows = "D";
385+
outputs = _: {};
386+
}
387+
EOF
388+
389+
nix flake lock $flakeFollowsA
390+
391+
[[ $(jq -c .nodes.C.inputs.D $flakeFollowsA/flake.lock) = '["D"]' ]]
392+
393+
# Test overlapping flake follows: B has D follow C/D, while A has B/C follow C
394+
395+
cat <<EOF > $flakeFollowsC/flake.nix
396+
{
397+
inputs.D.url = "path:$flakeFollowsD";
398+
outputs = _: {};
399+
}
400+
EOF
401+
cat <<EOF > $flakeFollowsB/flake.nix
402+
{
403+
inputs.C.url = "path:nosuchflake";
404+
inputs.D.follows = "C/D";
405+
outputs = _: {};
406+
}
407+
EOF
408+
cat <<EOF > $flakeFollowsA/flake.nix
409+
{
410+
inputs.B.url = "path:$flakeFollowsB";
411+
inputs.C.url = "path:$flakeFollowsC";
412+
inputs.B.inputs.C.follows = "C";
413+
outputs = _: {};
414+
}
415+
EOF
416+
417+
# bug was not triggered without recreating the lockfile
418+
nix flake lock $flakeFollowsA --recreate-lock-file
419+
420+
[[ $(jq -c .nodes.B.inputs.D $flakeFollowsA/flake.lock) = '["B","C","D"]' ]]
421+
422+
# Check that you can't have both a flakeref and a follows attribute on an input.
423+
cat <<EOF > $flakeFollowsB/flake.nix
424+
{
425+
inputs.C.url = "path:nosuchflake";
426+
inputs.D.url = "path:nosuchflake";
427+
inputs.D.follows = "C/D";
428+
outputs = _: {};
429+
}
430+
EOF
431+
432+
expectStderr 1 nix flake lock $flakeFollowsA --recreate-lock-file | grepQuiet "flake input has both a flake reference and a follows attribute"

0 commit comments

Comments
 (0)