Skip to content

Commit 3337ecd

Browse files
committed
flake lock: fix relative inputs in nested flakes
When computeLocks() keeps an existing flake input without refetching it, it recurses into that flake's inputs using the parent flake's source path. That value is only used to resolve relative 'path:' inputs, so it is harmless unless the kept flake has one. When it does (e.g. a flake with a "path:./sub" input that is itself a transitive input), the relative input is resolved against the parent flake's tree instead of the kept flake's, and locking then fails to find the input's flake.nix. Force a refetch of the kept flake when it has a relative input, so its real source path is available to resolve that input. Flakes without relative inputs stay on the lazy path unchanged. Fixes #14762.
1 parent d1f04a7 commit 3337ecd

3 files changed

Lines changed: 63 additions & 0 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
synopsis: "Fix locking of relative `path:` inputs in deeply nested flakes"
3+
issues: [14762]
4+
---
5+
6+
Locking a flake that transitively depends on a flake with a relative `path:`
7+
input (three or more levels deep) no longer fails with
8+
`path '.../flake.nix' does not exist`. The relative input is now resolved
9+
against the correct flake's source tree.

src/libflake/flake.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,18 @@ LockedFlake lockFlake(
638638
those. */
639639
for (auto & i : oldLock->inputs) {
640640
if (auto lockedNode = std::get_if<0>(&i.second)) {
641+
/* A relative path input (e.g. 'path:./foo')
642+
can only be resolved against the source
643+
tree of *this* flake. In the lazy path we
644+
don't have that tree, so the input would
645+
be resolved against the parent flake's
646+
tree instead -- wrong when this flake is
647+
itself a nested input. Refetch so we get
648+
the correct source path. See #14762. */
649+
if ((*lockedNode)->lockedRef.input.isRelative()) {
650+
mustRefetch = true;
651+
break;
652+
}
641653
fakeInputs.emplace(
642654
i.first,
643655
FlakeInput{

tests/functional/flakes/relative-paths.sh

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,45 @@ EOF
172172
nix eval --json .#nestedFlake1.nestedFlake2 --no-eval-cache
173173
nix eval --json .#nestedFlake1.nestedFlake2 --no-eval-cache
174174
)
175+
176+
# https://github.com/NixOS/nix/issues/14762
177+
# A relative 'path:' input nested under a flake that is itself kept from an
178+
# existing lock (the lazy "keep" path) must be resolved against that flake's
179+
# source tree, not its parent's. This only goes wrong at three levels:
180+
# top -> middle -> library, where 'library' has a relative 'subflake' input.
181+
n14762="$TEST_ROOT/issue-14762"
182+
rm -rf "$n14762"
183+
mkdir -p "$n14762/library/subflake" "$n14762/middle" "$n14762/top"
184+
185+
cat > "$n14762/library/subflake/flake.nix" <<EOF
186+
{ outputs = _: { }; }
187+
EOF
188+
cat > "$n14762/library/flake.nix" <<EOF
189+
{
190+
inputs.subflake.url = "path:./subflake";
191+
outputs = _: { };
192+
}
193+
EOF
194+
cat > "$n14762/middle/flake.nix" <<EOF
195+
{
196+
inputs.library.url = "path:$n14762/library";
197+
outputs = _: { };
198+
}
199+
EOF
200+
cat > "$n14762/top/flake.nix" <<EOF
201+
{
202+
inputs.middle.url = "path:$n14762/middle";
203+
outputs = _: { };
204+
}
205+
EOF
206+
207+
# These are plain 'path:' inputs with no fingerprint, so fetching them is
208+
# uncacheable (as on master); disable the test-only barf, like other tests do.
209+
210+
# Establish the middle flake's lock first, so that when the top flake locks,
211+
# 'library' is taken from middle's lock via the lazy "keep" path.
212+
_NIX_TEST_BARF_ON_UNCACHEABLE='' nix flake lock "$n14762/middle"
213+
214+
# Previously failed: "path '.../subflake/flake.nix' does not exist".
215+
_NIX_TEST_BARF_ON_UNCACHEABLE='' nix flake update --flake "$n14762/top"
216+
[[ -e "$n14762/top/flake.lock" ]]

0 commit comments

Comments
 (0)