Skip to content

Commit bcbdc50

Browse files
committed
Backward compatibility hack for dealing with dir in URL-style flakerefs
1 parent df93fa8 commit bcbdc50

3 files changed

Lines changed: 113 additions & 1 deletion

File tree

src/libflake/flake.cc

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,57 @@ static LockFile readLockFile(
367367
: LockFile();
368368
}
369369

370+
/**
371+
* Canonicalize a flakeref for the purpose of comparing "old" and
372+
* "new" `original` fields in lock files.
373+
*/
374+
static FlakeRef canonFlakeRef(FlakeRef flakeRef)
375+
{
376+
/* Backward compatibility hack: In old versions of Nix, if you had
377+
a flake input like
378+
379+
inputs.foo.url = "git+https://foo/bar?dir=subdir";
380+
381+
it would result in a lock file entry like
382+
383+
"original": {
384+
"dir": "subdir",
385+
"type": "git",
386+
"url": "https://foo/bar?dir=subdir"
387+
}
388+
389+
New versions of Nix remove `?dir=subdir` from the `url` field,
390+
since the subdirectory is intended for `FlakeRef`, not the
391+
fetcher (and specifically the remote server), that is, the
392+
flakeref is parsed into
393+
394+
"original": {
395+
"dir": "subdir",
396+
"type": "git",
397+
"url": "https://foo/bar"
398+
}
399+
400+
However, this causes new versions of Nix to consider the lock
401+
file entry to be stale since the `original` ref no longer
402+
matches exactly.
403+
404+
For this reason, we canonicalise the `original` ref by
405+
filtering the `dir` query parameter from the URL. */
406+
if (auto url = fetchers::maybeGetStrAttr(flakeRef.input.attrs, "url")) {
407+
try {
408+
auto parsed = parseURL(*url);
409+
if (auto dir2 = get(parsed.query, "dir")) {
410+
if (flakeRef.subdir != "" && flakeRef.subdir == *dir2)
411+
parsed.query.erase("dir");
412+
}
413+
flakeRef.input.attrs.insert_or_assign("url", parsed.to_string());
414+
} catch (BadURL &) {
415+
}
416+
}
417+
418+
return flakeRef;
419+
}
420+
370421
/* Compute an in-memory lock file for the specified top-level flake,
371422
and optionally write it to file, if the flake is writable. */
372423
LockedFlake lockFlake(
@@ -580,7 +631,7 @@ LockedFlake lockFlake(
580631
oldLock = *oldLock3;
581632

582633
if (oldLock
583-
&& oldLock->originalRef == *input.ref
634+
&& canonFlakeRef(oldLock->originalRef) == canonFlakeRef(*input.ref)
584635
&& oldLock->parentInputAttrPath == overridenParentPath
585636
&& !hasCliOverride)
586637
{

tests/functional/flakes/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ suites += {
3232
'symlink-paths.sh',
3333
'debugger.sh',
3434
'source-paths.sh',
35+
'old-lockfiles.sh',
3536
],
3637
'workdir': meson.current_source_dir(),
3738
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/usr/bin/env bash
2+
3+
source ./common.sh
4+
5+
requireGit
6+
7+
repo="$TEST_ROOT/repo"
8+
9+
createGitRepo "$repo"
10+
11+
cat > "$repo/flake.nix" <<EOF
12+
{
13+
inputs = {
14+
dependency.url = "git+file:///no-such-path?dir=subdir";
15+
};
16+
outputs = { dependency, self }: {
17+
hi = dependency.an_output;
18+
};
19+
}
20+
EOF
21+
22+
cat > "$repo/flake.lock" <<EOF
23+
{
24+
"nodes": {
25+
"dependency": {
26+
"locked": {
27+
"dir": "subdir",
28+
"lastModified": 1746721011,
29+
"narHash": "sha256-9aIDvIdyHAfQyvT5SwPgYxUUhf1GwQVAWq+qa5LcEQE=",
30+
"ref": "refs/heads/master",
31+
"rev": "432058dbfc82b0369bc9cce440e4af2aece52b54",
32+
"revCount": 1,
33+
"type": "git",
34+
"url": "file:///no-such-path?dir=subdir"
35+
},
36+
"original": {
37+
"dir": "subdir",
38+
"type": "git",
39+
"url": "file:///no-such-path?dir=subdir"
40+
}
41+
},
42+
"root": {
43+
"inputs": {
44+
"dependency": "dependency"
45+
}
46+
}
47+
},
48+
"root": "root",
49+
"version": 7
50+
}
51+
EOF
52+
53+
git -C "$repo" add flake.nix flake.lock
54+
git -C "$repo" commit -a -m foo
55+
56+
cp "$repo/flake.lock" "$repo/flake.lock.old"
57+
58+
nix flake lock "$repo"
59+
60+
cmp "$repo/flake.lock" "$repo/flake.lock.old"

0 commit comments

Comments
 (0)