Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libflake/flake.cc
Original file line number Diff line number Diff line change
Expand Up @@ -580,7 +580,7 @@ LockedFlake lockFlake(
oldLock = *oldLock3;

if (oldLock
&& oldLock->originalRef == *input.ref
&& oldLock->originalRef.canonicalize() == input.ref->canonicalize()
&& oldLock->parentInputAttrPath == overridenParentPath
&& !hasCliOverride)
{
Expand Down
49 changes: 49 additions & 0 deletions src/libflake/flakeref.cc
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,55 @@ std::pair<ref<SourceAccessor>, FlakeRef> FlakeRef::lazyFetch(ref<Store> store) c
return {accessor, FlakeRef(std::move(lockedInput), subdir)};
}

FlakeRef FlakeRef::canonicalize() const
{
auto flakeRef(*this);

/* Backward compatibility hack: In old versions of Nix, if you had
a flake input like

inputs.foo.url = "git+https://foo/bar?dir=subdir";

it would result in a lock file entry like

"original": {
"dir": "subdir",
"type": "git",
"url": "https://foo/bar?dir=subdir"
}

New versions of Nix remove `?dir=subdir` from the `url` field,
since the subdirectory is intended for `FlakeRef`, not the
fetcher (and specifically the remote server), that is, the
flakeref is parsed into

"original": {
"dir": "subdir",
"type": "git",
"url": "https://foo/bar"
}

However, this causes new versions of Nix to consider the lock
file entry to be stale since the `original` ref no longer
matches exactly.

For this reason, we canonicalise the `original` ref by
filtering the `dir` query parameter from the URL. */
if (auto url = fetchers::maybeGetStrAttr(flakeRef.input.attrs, "url")) {
try {
auto parsed = parseURL(*url);
if (auto dir2 = get(parsed.query, "dir")) {
if (flakeRef.subdir != "" && flakeRef.subdir == *dir2)
parsed.query.erase("dir");
}
flakeRef.input.attrs.insert_or_assign("url", parsed.to_string());
} catch (BadURL &) {
}
}

return flakeRef;
}

std::tuple<FlakeRef, std::string, ExtendedOutputsSpec> parseFlakeRefWithFragmentAndExtendedOutputsSpec(
const fetchers::Settings & fetchSettings,
const std::string & url,
Expand Down
6 changes: 6 additions & 0 deletions src/libflake/include/nix/flake/flakeref.hh
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ struct FlakeRef
const fetchers::Attrs & attrs);

std::pair<ref<SourceAccessor>, FlakeRef> lazyFetch(ref<Store> store) const;

/**
* Canonicalize a flakeref for the purpose of comparing "old" and
* "new" `original` fields in lock files.
*/
FlakeRef canonicalize() const;
};

std::ostream & operator << (std::ostream & str, const FlakeRef & flakeRef);
Expand Down
1 change: 1 addition & 0 deletions tests/functional/flakes/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ suites += {
'symlink-paths.sh',
'debugger.sh',
'source-paths.sh',
'old-lockfiles.sh',
],
'workdir': meson.current_source_dir(),
}
60 changes: 60 additions & 0 deletions tests/functional/flakes/old-lockfiles.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env bash

source ./common.sh

requireGit

repo="$TEST_ROOT/repo"

createGitRepo "$repo"

cat > "$repo/flake.nix" <<EOF
{
inputs = {
dependency.url = "git+file:///no-such-path?dir=subdir";
};
outputs = { dependency, self }: {
hi = dependency.an_output;
};
}
EOF

cat > "$repo/flake.lock" <<EOF
{
"nodes": {
"dependency": {
"locked": {
"dir": "subdir",
"lastModified": 1746721011,
"narHash": "sha256-9aIDvIdyHAfQyvT5SwPgYxUUhf1GwQVAWq+qa5LcEQE=",
"ref": "refs/heads/master",
"rev": "432058dbfc82b0369bc9cce440e4af2aece52b54",
"revCount": 1,
"type": "git",
"url": "file:///no-such-path?dir=subdir"
},
"original": {
"dir": "subdir",
"type": "git",
"url": "file:///no-such-path?dir=subdir"
}
},
"root": {
"inputs": {
"dependency": "dependency"
}
}
},
"root": "root",
"version": 7
}
EOF

git -C "$repo" add flake.nix flake.lock
git -C "$repo" commit -a -m foo

cp "$repo/flake.lock" "$repo/flake.lock.old"

nix flake lock "$repo"

cmp "$repo/flake.lock" "$repo/flake.lock.old"