Skip to content

Commit

Permalink
flake.cc: computeLocks: Only verify overrides when they could change
Browse files Browse the repository at this point in the history
When we check for disappeared overrides, we can get "false positives"
for follows and overrides which are defined in the dependencies of the
flake we are locking, since they are not parsed by
parseFlakeInputs. However, at that point we already know that the
overrides couldn't have possible been changed if the input itself
hasn't changed (since we check that oldLock->originalRef == *input.ref
for the input's parent). So, to prevent this, only perform this check
when it was possible that the flake changed (e.g. the flake we're
locking, or a new input, or the input has changed and mustRefetch ==
true).
  • Loading branch information
balsoft committed Dec 28, 2021
1 parent 0e90b13 commit 2664a21
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 21 deletions.
36 changes: 22 additions & 14 deletions src/libexpr/flake/flake.cc
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,8 @@ LockedFlake lockFlake(
const InputPath & inputPathPrefix,
std::shared_ptr<const Node> oldNode,
const LockParent & parent,
const Path & parentPath)>
const Path & parentPath,
bool trustLock)>
computeLocks;

computeLocks = [&](
Expand All @@ -353,7 +354,8 @@ LockedFlake lockFlake(
const InputPath & inputPathPrefix,
std::shared_ptr<const Node> oldNode,
const LockParent & parent,
const Path & parentPath)
const Path & parentPath,
bool trustLock)
{
debug("computing lock file node '%s'", printInputPath(inputPathPrefix));

Expand Down Expand Up @@ -464,14 +466,20 @@ LockedFlake lockFlake(
.isFlake = (*lockedNode)->isFlake,
});
} else if (auto follows = std::get_if<1>(&i.second)) {
auto o = input.overrides.find(i.first);
// If the override disappeared, we have to refetch the flake,
// since some of the inputs may not be present in the lockfile.
if (o == input.overrides.end()) {
mustRefetch = true;
// There's no point populating the rest of the fake inputs,
// since we'll refetch the flake anyways.
break;
if (! trustLock) {
// It is possible that the flake has changed,
// so we must confirm all the follows that are in the lockfile are also in the flake.
auto overridePath(inputPath);
overridePath.push_back(i.first);
auto o = overrides.find(overridePath);
// If the override disappeared, we have to refetch the flake,
// since some of the inputs may not be present in the lockfile.
if (o == overrides.end()) {
mustRefetch = true;
// There's no point populating the rest of the fake inputs,
// since we'll refetch the flake anyways.
break;
}
}
fakeInputs.emplace(i.first, FlakeInput {
.follows = *follows,
Expand All @@ -482,14 +490,14 @@ LockedFlake lockFlake(

LockParent newParent {
.path = inputPath,
.absolute = false
.absolute = true
};

computeLocks(
mustRefetch
? getFlake(state, oldLock->lockedRef, false, flakeCache).inputs
: fakeInputs,
childNode, inputPath, oldLock, newParent, parentPath);
childNode, inputPath, oldLock, newParent, parentPath, !mustRefetch);

} else {
/* We need to create a new lock file entry. So fetch
Expand Down Expand Up @@ -546,7 +554,7 @@ LockedFlake lockFlake(
? std::dynamic_pointer_cast<const Node>(oldLock)
: LockFile::read(
inputFlake.sourceInfo->actualPath + "/" + inputFlake.lockedRef.subdir + "/flake.lock").root,
newParent, localPath);
newParent, localPath, false);
}

else {
Expand Down Expand Up @@ -574,7 +582,7 @@ LockedFlake lockFlake(

computeLocks(
flake.inputs, newLockFile.root, {},
lockFlags.recreateLockFile ? nullptr : oldLockFile.root, parent, parentPath);
lockFlags.recreateLockFile ? nullptr : oldLockFile.root, parent, parentPath, false);

for (auto & i : lockFlags.inputOverrides)
if (!overridesUsed.count(i.first))
Expand Down
10 changes: 3 additions & 7 deletions tests/flakes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -716,11 +716,10 @@ cat > $flakeFollowsA/flake.nix <<EOF
inputs = {
B = {
url = "path:./flakeB";
inputs.foobar.follows = "D";
inputs.nonFlake.follows = "D";
inputs.foobar.follows = "foobar";
};
D.url = "path:./flakeD";
foobar.url = "path:$flakeFollowsA/flakeE";
};
outputs = { ... }: {};
}
Expand All @@ -731,8 +730,6 @@ cat > $flakeFollowsB/flake.nix <<EOF
description = "Flake B";
inputs = {
foobar.url = "path:$flakeFollowsA/flakeE";
nonFlake.url = "path:$nonFlakeDir";
goodoo.follows = "C/goodoo";
C = {
url = "path:./flakeC";
inputs.foobar.follows = "foobar";
Expand All @@ -747,7 +744,6 @@ cat > $flakeFollowsC/flake.nix <<EOF
description = "Flake C";
inputs = {
foobar.url = "path:$flakeFollowsA/flakeE";
goodoo.follows = "foobar";
};
outputs = { ... }: {};
}
Expand Down Expand Up @@ -785,7 +781,7 @@ newLock="$(cat "$flakeFollowsA/flake.lock")"
diff <(echo "$newLock") <(echo "$oldLock")

[[ $(jq -c .nodes.B.inputs.C $flakeFollowsA/flake.lock) = '"C"' ]]
[[ $(jq -c .nodes.B.inputs.foobar $flakeFollowsA/flake.lock) = '["D"]' ]]
[[ $(jq -c .nodes.B.inputs.foobar $flakeFollowsA/flake.lock) = '["foobar"]' ]]
[[ $(jq -c .nodes.C.inputs.foobar $flakeFollowsA/flake.lock) = '["B","foobar"]' ]]

# Ensure removing follows from flake.nix removes them from the lockfile
Expand Down

0 comments on commit 2664a21

Please sign in to comment.