Skip to content

Commit bf1c007

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

5 files changed

Lines changed: 117 additions & 1 deletion

File tree

src/libflake/flake.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ LockedFlake lockFlake(
580580
oldLock = *oldLock3;
581581

582582
if (oldLock
583-
&& oldLock->originalRef == *input.ref
583+
&& oldLock->originalRef.canonicalize() == input.ref->canonicalize()
584584
&& oldLock->parentInputAttrPath == overridenParentPath
585585
&& !hasCliOverride)
586586
{

src/libflake/flakeref.cc

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,55 @@ std::pair<ref<SourceAccessor>, FlakeRef> FlakeRef::lazyFetch(ref<Store> store) c
289289
return {accessor, FlakeRef(std::move(lockedInput), subdir)};
290290
}
291291

292+
FlakeRef FlakeRef::canonicalize() const
293+
{
294+
auto flakeRef(*this);
295+
296+
/* Backward compatibility hack: In old versions of Nix, if you had
297+
a flake input like
298+
299+
inputs.foo.url = "git+https://foo/bar?dir=subdir";
300+
301+
it would result in a lock file entry like
302+
303+
"original": {
304+
"dir": "subdir",
305+
"type": "git",
306+
"url": "https://foo/bar?dir=subdir"
307+
}
308+
309+
New versions of Nix remove `?dir=subdir` from the `url` field,
310+
since the subdirectory is intended for `FlakeRef`, not the
311+
fetcher (and specifically the remote server), that is, the
312+
flakeref is parsed into
313+
314+
"original": {
315+
"dir": "subdir",
316+
"type": "git",
317+
"url": "https://foo/bar"
318+
}
319+
320+
However, this causes new versions of Nix to consider the lock
321+
file entry to be stale since the `original` ref no longer
322+
matches exactly.
323+
324+
For this reason, we canonicalise the `original` ref by
325+
filtering the `dir` query parameter from the URL. */
326+
if (auto url = fetchers::maybeGetStrAttr(flakeRef.input.attrs, "url")) {
327+
try {
328+
auto parsed = parseURL(*url);
329+
if (auto dir2 = get(parsed.query, "dir")) {
330+
if (flakeRef.subdir != "" && flakeRef.subdir == *dir2)
331+
parsed.query.erase("dir");
332+
}
333+
flakeRef.input.attrs.insert_or_assign("url", parsed.to_string());
334+
} catch (BadURL &) {
335+
}
336+
}
337+
338+
return flakeRef;
339+
}
340+
292341
std::tuple<FlakeRef, std::string, ExtendedOutputsSpec> parseFlakeRefWithFragmentAndExtendedOutputsSpec(
293342
const fetchers::Settings & fetchSettings,
294343
const std::string & url,

src/libflake/include/nix/flake/flakeref.hh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ struct FlakeRef
7272
const fetchers::Attrs & attrs);
7373

7474
std::pair<ref<SourceAccessor>, FlakeRef> lazyFetch(ref<Store> store) const;
75+
76+
/**
77+
* Canonicalize a flakeref for the purpose of comparing "old" and
78+
* "new" `original` fields in lock files.
79+
*/
80+
FlakeRef canonicalize() const;
7581
};
7682

7783
std::ostream & operator << (std::ostream & str, const FlakeRef & flakeRef);

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)