From 973eb601d45e71eb65b0ad83c38e027b385e9bb9 Mon Sep 17 00:00:00 2001 From: Matthew Kenigsberg Date: Fri, 11 Sep 2020 09:50:12 -0500 Subject: [PATCH 1/6] Allow no FlakeRef for FlakeInput This allows treating "nodes" in the override graph as empty if they don't have a FlakeRef, which allows combining overrides set by different flakes --- src/libexpr/flake/flake.cc | 13 +++++++------ src/libexpr/flake/flake.hh | 5 +++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 6a27ea2e8dc..d195227fd2f 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -91,11 +91,11 @@ static void expectType(EvalState & state, ValueType type, static std::map parseFlakeInputs( EvalState & state, Value * value, const PosIdx pos, - const std::optional & baseDir, InputPath lockRootPath); + const std::optional & baseDir, InputPath lockRootPath, bool defaultRef = true); static FlakeInput parseFlakeInput(EvalState & state, const std::string & inputName, Value * value, const PosIdx pos, - const std::optional & baseDir, InputPath lockRootPath) + const std::optional & baseDir, InputPath lockRootPath, bool defaultRef = true) { expectType(state, nAttrs, *value, pos); @@ -119,7 +119,7 @@ static FlakeInput parseFlakeInput(EvalState & state, expectType(state, nBool, *attr.value, attr.pos); input.isFlake = attr.value->boolean; } else if (attr.name == sInputs) { - input.overrides = parseFlakeInputs(state, attr.value, attr.pos, baseDir, lockRootPath); + input.overrides = parseFlakeInputs(state, attr.value, attr.pos, baseDir, lockRootPath, false); } else if (attr.name == sFollows) { expectType(state, nString, *attr.value, attr.pos); auto follows(parseInputPath(attr.value->string.s)); @@ -168,7 +168,7 @@ static FlakeInput parseFlakeInput(EvalState & state, input.ref = parseFlakeRef(*url, baseDir, true, input.isFlake); } - if (!input.follows && !input.ref) + if (!input.follows && !input.ref && defaultRef) input.ref = FlakeRef::fromAttrs({{"type", "indirect"}, {"id", inputName}}); return input; @@ -176,7 +176,7 @@ static FlakeInput parseFlakeInput(EvalState & state, static std::map parseFlakeInputs( EvalState & state, Value * value, const PosIdx pos, - const std::optional & baseDir, InputPath lockRootPath) + const std::optional & baseDir, InputPath lockRootPath, bool defaultRef) { std::map inputs; @@ -189,7 +189,8 @@ static std::map parseFlakeInputs( inputAttr.value, inputAttr.pos, baseDir, - lockRootPath)); + lockRootPath, + defaultRef)); } return inputs; diff --git a/src/libexpr/flake/flake.hh b/src/libexpr/flake/flake.hh index c1d1b71e509..29af9d60d36 100644 --- a/src/libexpr/flake/flake.hh +++ b/src/libexpr/flake/flake.hh @@ -38,6 +38,11 @@ typedef std::map FlakeInputs; * set. If not otherwise specified, a "ref" will be generated to a * 'type="indirect"' flake, which is treated as simply the name of a * flake to be resolved in the registry. + * + * FlakeInputs (a map from FlakeId to FlakeInput) is used to represent + * overrides, and in that case, a FlakeInput may have neither "ref" + * nor "follows", in which case it is an empty node in the override + * graph. */ struct FlakeInput From 3b2f4ba1bf771afa1e133d2eb9a170ce42419ba7 Mon Sep 17 00:00:00 2001 From: Matthew Kenigsberg Date: Fri, 11 Sep 2020 10:00:14 -0500 Subject: [PATCH 2/6] Allow composing overrrides Allow multi-level overridees, overriding with higher level overrides when appropriate. See tests for the following motivating cases: - multi-level overrides: A(override B.C.D=D2) -> B -> C -> D - overriding an override: A (override B.C.D) -> B (override C.D)-> C -> D - overrides are merged: A (override B.C.D.E) -> B (override C.D)-> C -> D -> E The prior implementation used a single overrides data structure accessible throughout recursive calls to computeLocks. Instead, only pass each recursive call exactly the overrides it needs. This better protects individual recursive calls from modifying the overrides "global" to the recursion. --- src/libexpr/flake/flake.cc | 153 ++++++++++----- src/libexpr/flake/flake.hh | 3 + tests/flakes/overrides.sh | 392 +++++++++++++++++++++++++++++++++++++ 3 files changed, 498 insertions(+), 50 deletions(-) create mode 100644 tests/flakes/overrides.sh diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index d195227fd2f..3e2cbf505ad 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -18,6 +18,60 @@ namespace flake { typedef std::pair FetchedFlake; typedef std::vector> FlakeCache; +// Add a single override to `overrides`, setting the input at `path` to `ref`. +void setOverride(FlakeInputs & overrides, const InputPath & path, const FlakeRef & ref) +{ + // find/emplace for each existing/non-existing node + auto pathIter = path.begin(); + auto currentNode = &(overrides.emplace(*pathIter, FlakeInput()).first->second); + ++pathIter; + while (pathIter != path.end()) { + currentNode = &(currentNode->overrides.emplace(*pathIter, FlakeInput()).first->second); + ++pathIter; + } + currentNode->ref = ref; +} + +// Recurse into overrides, warning each time an unused override is found. +void warnUnusedOverrides(const FlakeInputs & overrides, const InputPath & inputPathPrefix) +{ + for (auto & [id, input] : overrides) { + auto inputPath(inputPathPrefix); + inputPath.push_back(id); + if (input.ref) { + // It might make more sense to display where the override was set, + // but we don't currently keep track of that information. + // E.g. this will say a/b has an override for a non-existent input + // c, even if that override is set in a. + warn( + "input '%s' has an override for a non-existent input '%s'", + printInputPath(inputPathPrefix), id); + } + warnUnusedOverrides(input.overrides, inputPath); + } +} + +// Merge overrides into the existing set. +void FlakeInput::setOverrides(FlakeInputs && newOverrides) +{ + while (!newOverrides.empty()) { + auto mapNode = newOverrides.extract(newOverrides.begin()); + auto id = mapNode.key(); + auto & child = mapNode.mapped(); + auto existingOverrides = overrides.find(id); + // possibly replace existing override and recursively merge children + if (existingOverrides != overrides.end()) { + if (child.ref) { + existingOverrides->second.ref = std::move(child.ref); + } + existingOverrides->second.setOverrides(std::move(child.overrides)); + // no merge necessary; just move new overrides + } else { + overrides.insert(std::move(mapNode)); + } + } +} + static std::optional lookupInFlakeCache( const FlakeCache & flakeCache, const FlakeRef & flakeRef) @@ -351,11 +405,12 @@ LockedFlake lockFlake( debug("old lock file: %s", oldLockFile); - std::map overrides; - std::set overridesUsed, updatesUsed; + FlakeInputs overrides; + std::set updatesUsed; - for (auto & i : lockFlags.inputOverrides) - overrides.insert_or_assign(i.first, FlakeInput { .ref = i.second }); + for (auto & [inputPath, flakeRef] : lockFlags.inputOverrides) { + setOverride(overrides, inputPath, flakeRef); + } LockFile newLockFile; @@ -366,6 +421,7 @@ LockedFlake lockFlake( ref node, const InputPath & inputPathPrefix, std::shared_ptr oldNode, + FlakeInputs & overrides, const InputPath & lockRootPath, const Path & parentPath, bool trustLock)> @@ -382,57 +438,51 @@ LockedFlake lockFlake( /* The old node, if any, from which locks can be copied. */ std::shared_ptr oldNode, + /* The overrides for inputs of this node. */ + FlakeInputs & overrides, const InputPath & lockRootPath, const Path & parentPath, bool trustLock) { debug("computing lock file node '%s'", printInputPath(inputPathPrefix)); - /* Get the overrides (i.e. attributes of the form - 'inputs.nixops.inputs.nixpkgs.url = ...'). */ - for (auto & [id, input] : flakeInputs) { - for (auto & [idOverride, inputOverride] : input.overrides) { - auto inputPath(inputPathPrefix); - inputPath.push_back(id); - inputPath.push_back(idOverride); - overrides.insert_or_assign(inputPath, inputOverride); - } - } - - /* Check whether this input has overrides for a - non-existent input. */ - for (auto [inputPath, inputOverride] : overrides) { - auto inputPath2(inputPath); - auto follow = inputPath2.back(); - inputPath2.pop_back(); - if (inputPath2 == inputPathPrefix && !flakeInputs.count(follow)) - warn( - "input '%s' has an override for a non-existent input '%s'", - printInputPath(inputPathPrefix), follow); - } - /* Go over the flake inputs, resolve/fetch them if necessary (i.e. if they're new or the flakeref changed from what's in the lock file). */ - for (auto & [id, input2] : flakeInputs) { + for (auto & [id, originalInput] : flakeInputs) { auto inputPath(inputPathPrefix); inputPath.push_back(id); auto inputPathS = printInputPath(inputPath); debug("computing input '%s'", inputPathS); try { - - /* Do we have an override for this input from one of the - ancestors? */ - auto i = overrides.find(inputPath); - bool hasOverride = i != overrides.end(); - if (hasOverride) { - overridesUsed.insert(inputPath); - // Respect the “flakeness” of the input even if we - // override it - i->second.isFlake = input2.isFlake; + // check whether this input is overriden and apply overrides to its inputs + FlakeInput input = originalInput; + bool hasOverride = false; + auto matchingOverrides = overrides.extract(id); + if (matchingOverrides) { + auto & overrideInput = matchingOverrides.mapped(); + // overrideInput could be an empty node in the override + // graph with no ref or follows + if (overrideInput.ref) { + debug("%s has override %s", inputPathS, overrideInput.ref.value()); + input.ref = overrideInput.ref; + // Respect the “flakeness” of the input even if we + // override it, so don't set input.isFlake + hasOverride = true; + } + if (overrideInput.follows) { + input.follows = overrideInput.follows; + hasOverride = true; + } + // - input.overrides are from the parent of this input + // - overrides are from above the parent of this input + // - (this input hasn't been fetched yet) + // So we need to merge overrides, giving precedence to + // overrides from higher than parent. + debug("merging children overrides for '%s'", inputPathS); + input.setOverrides(std::move(matchingOverrides.mapped().overrides)); } - auto & input = hasOverride ? i->second : input2; /* Resolve 'follows' later (since it may refer to an input path we haven't processed yet. */ @@ -500,9 +550,7 @@ LockedFlake lockFlake( if (!trustLock) { // It is possible that the flake has changed, // so we must confirm all the follows that are in the lock file are also in the flake. - auto overridePath(inputPath); - overridePath.push_back(i.first); - auto o = overrides.find(overridePath); + auto o = 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 lock file. if (o == overrides.end()) { @@ -530,7 +578,13 @@ LockedFlake lockFlake( mustRefetch ? getFlake(state, oldLock->lockedRef, false, flakeCache, inputPath).inputs : fakeInputs, - childNode, inputPath, oldLock, lockRootPath, parentPath, !mustRefetch); + childNode, + inputPath, + oldLock, + input.overrides, + lockRootPath, + parentPath, + !mustRefetch); } else { /* We need to create a new lock file entry. So fetch @@ -541,13 +595,13 @@ LockedFlake lockFlake( throw Error("cannot update unlocked flake input '%s' in pure mode", inputPathS); /* Note: in case of an --override-input, we use - the *original* ref (input2.ref) for the + the *original* ref (originalInput.ref) for the "original" field, rather than the override. This ensures that the override isn't nuked the next time we update the lock file. That is, overrides are sticky unless you use --no-write-lock-file. */ - auto ref = input2.ref ? *input2.ref : *input.ref; + auto ref = originalInput.ref ? *originalInput.ref : *input.ref; if (input.isFlake) { Path localPath = parentPath; @@ -581,6 +635,7 @@ LockedFlake lockFlake( ? std::dynamic_pointer_cast(oldLock) : LockFile::read( inputFlake.sourceInfo->actualPath + "/" + inputFlake.lockedRef.subdir + "/flake.lock").root.get_ptr(), + input.overrides, oldLock ? lockRootPath : inputPath, localPath, false); @@ -601,6 +656,8 @@ LockedFlake lockFlake( throw; } } + // all overrides should have been extracted + warnUnusedOverrides(overrides, inputPathPrefix); }; // Bring in the current ref for relative path resolution if we have it @@ -611,15 +668,11 @@ LockedFlake lockFlake( newLockFile.root, {}, lockFlags.recreateLockFile ? nullptr : oldLockFile.root.get_ptr(), + overrides, {}, parentPath, false); - for (auto & i : lockFlags.inputOverrides) - if (!overridesUsed.count(i.first)) - warn("the flag '--override-input %s %s' does not match any input", - printInputPath(i.first), i.second); - for (auto & i : lockFlags.inputUpdates) if (!updatesUsed.count(i)) warn("the flag '--update-input %s' does not match any input", printInputPath(i)); diff --git a/src/libexpr/flake/flake.hh b/src/libexpr/flake/flake.hh index 29af9d60d36..5e3774b3b87 100644 --- a/src/libexpr/flake/flake.hh +++ b/src/libexpr/flake/flake.hh @@ -17,6 +17,8 @@ namespace flake { struct FlakeInput; typedef std::map FlakeInputs; +void setOverride(FlakeInputs & overrides, const InputPath & path, const FlakeRef & ref); +void warnUnusedOverrides(const FlakeInputs & overrides, const InputPath & inputPathPrefix); /** * FlakeInput is the 'Flake'-level parsed form of the "input" entries @@ -56,6 +58,7 @@ struct FlakeInput bool isFlake = true; std::optional follows; FlakeInputs overrides; + void setOverrides(FlakeInputs && overrides); }; struct ConfigFile diff --git a/tests/flakes/overrides.sh b/tests/flakes/overrides.sh new file mode 100644 index 00000000000..23b8ca88995 --- /dev/null +++ b/tests/flakes/overrides.sh @@ -0,0 +1,392 @@ +source ./common.sh + +requireGit + +clearStore +rm -rf $TEST_HOME/.cache $TEST_HOME/.config + +flakeA=$TEST_ROOT/flakeA +flakeB=$TEST_ROOT/flakeB +flakeC=$TEST_ROOT/flakeC +flakeC2=$TEST_ROOT/flakeC2 +flakeD=$TEST_ROOT/flakeD +flakeD2=$TEST_ROOT/flakeD2 +flakeD3=$TEST_ROOT/flakeD3 +flakeE=$TEST_ROOT/flakeE +flakeE2=$TEST_ROOT/flakeE2 + +for repo in "$flakeA" "$flakeB" "$flakeC" "$flakeC2" "$flakeD" "$flakeD2" "$flakeD3" "$flakeE" "$flakeE2"; do + createGitRepo "$repo" +done + +# Test simple override +# A(override B.C=C2) -> B -> C +cat > "$flakeA/flake.nix" < "$flakeB/flake.nix" < "$flakeC/flake.nix" < "$flakeC2/flake.nix" < B -> C +# --input-override a.b.c = C2 +cat > "$flakeA/flake.nix" < B -> C +cat > "$flakeA/flake.nix" <&1 | grep "has an override") =~ $expectedOutputRegex ]] + +# Test multi-level overrides +# A(override B.C.D=D2) -> B -> C -> D + +cat > "$flakeA/flake.nix" < "$flakeB/flake.nix" < "$flakeC/flake.nix" < "$flakeD/flake.nix" < "$flakeD2/flake.nix" < B (override C.D=D2)-> C -> D +cat > "$flakeA/flake.nix" < "$flakeB/flake.nix" < "$flakeD3/flake.nix" < B (override C.D=D2)-> C -> D -> E + +cat > "$flakeA/flake.nix" < "$flakeB/flake.nix" < "$flakeC/flake.nix" < "$flakeD/flake.nix" < "$flakeD2/flake.nix" < "$flakeE/flake.nix" < "$flakeE2/flake.nix" < B -> C -> D -> E +# C2 (override D.E=E2) +# E2 should be used + +cat > "$flakeA/flake.nix" < "$flakeB/flake.nix" < "$flakeC/flake.nix" < "$flakeC2/flake.nix" < B -> C(override D.E=E2) -> D -> E +# E should not be overridden since the input setting that override (C) was +# overridden with an input (C2) that did not have an override for E. + +# A and B same + +cat > "$flakeC/flake.nix" < "$flakeC2/flake.nix" < Date: Fri, 18 Aug 2023 16:29:15 -0600 Subject: [PATCH 3/6] remove unnecessary --recreate-lock-file --- tests/flakes/overrides.sh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/flakes/overrides.sh b/tests/flakes/overrides.sh index 23b8ca88995..2c2a947cc82 100644 --- a/tests/flakes/overrides.sh +++ b/tests/flakes/overrides.sh @@ -64,8 +64,8 @@ EOF git -C "$flakeC2" add flake.nix git -C "$flakeC2" commit -a -m 'initial' -[[ $(nix eval --raw "$flakeB#foo" --recreate-lock-file) = "B C" ]] -[[ $(nix eval --raw "$flakeA#foo" --recreate-lock-file) = "A B C2" ]] +[[ $(nix eval --raw "$flakeB#foo") = "B C" ]] +[[ $(nix eval --raw "$flakeA#foo") = "A B C2" ]] # Test simple override from command line # A -> B -> C @@ -83,7 +83,7 @@ git -C "$flakeA" commit -a -m 'initial' # B, C, and C2 same as previous test [[ $(nix eval --raw "$flakeA#foo" --recreate-lock-file) = "A B C" ]] -[[ $(nix eval --raw "$flakeA#foo" --recreate-lock-file --override-input b/c git+file://$flakeC2) = "A B C2" ]] +[[ $(nix eval --raw "$flakeA#foo" --override-input b/c git+file://$flakeC2) = "A B C2" ]] # Test unused overrides detected # A(override B.X=A, B.X.X=B, B.Y=C, B.C.Z=D) -> B -> C @@ -103,12 +103,12 @@ git -C "$flakeA" add flake.nix git -C "$flakeA" commit -a -m 'initial' # B and C same as previous test -[[ $(nix eval --raw "$flakeA#foo" --recreate-lock-file) = "A B C" ]] +[[ $(nix eval --raw "$flakeA#foo") = "A B C" ]] expectedOutputRegex="warning: input 'b/c' has an override for a non-existent input 'z' warning: input 'b' has an override for a non-existent input 'x' warning: input 'b/x' has an override for a non-existent input 'x' warning: input 'b' has an override for a non-existent input 'y'" -[[ $(nix eval "$flakeA#foo" --recreate-lock-file 2>&1 | grep "has an override") =~ $expectedOutputRegex ]] +[[ $(nix eval "$flakeA#foo" 2>&1 | grep "has an override") =~ $expectedOutputRegex ]] # Test multi-level overrides # A(override B.C.D=D2) -> B -> C -> D @@ -208,9 +208,9 @@ git -C "$flakeD3" commit -a -m 'initial' # C, D, and D2 same as previous test -[[ $(nix eval --raw "$flakeC#foo" --recreate-lock-file) = "C D" ]] -[[ $(nix eval --raw "$flakeB#foo" --recreate-lock-file) = "B C D2" ]] -[[ $(nix eval --raw "$flakeA#foo" --recreate-lock-file) = "A B C D3" ]] +[[ $(nix eval --raw "$flakeC#foo") = "C D" ]] +[[ $(nix eval --raw "$flakeB#foo") = "B C D2" ]] +[[ $(nix eval --raw "$flakeA#foo") = "A B C D3" ]] # Test overrides are merged # A(override B.C.D.E=E2) -> B (override C.D=D2)-> C -> D -> E @@ -294,7 +294,7 @@ git -C "$flakeE2" add flake.nix git -C "$flakeE2" commit -a -m 'initial' [[ $(nix eval --raw "$flakeC#foo" --recreate-lock-file) = "C D E" ]] -[[ $(nix eval --raw "$flakeB#foo" --recreate-lock-file) = "B C D2 E" ]] +[[ $(nix eval --raw "$flakeB#foo") = "B C D2 E" ]] [[ $(nix eval --raw "$flakeA#foo" --recreate-lock-file) = "A B C D2 E2" ]] # Test overrides set by an override are used @@ -353,8 +353,8 @@ git -C "$flakeC2" commit -a -m 'initial' # TODO is there a bug around when to update inputs? # The tests fail without removing these locks. rm -f {$flakeA,$flakeB}/flake.lock -[[ $(nix eval --raw "$flakeC#foo" --recreate-lock-file) = "C D E" ]] -[[ $(nix eval --raw "$flakeA#foo" --recreate-lock-file) = "A B C2 D E2" ]] +[[ $(nix eval --raw "$flakeC#foo") = "C D E" ]] +[[ $(nix eval --raw "$flakeA#foo") = "A B C2 D E2" ]] # Test overrides of overridden inputs get discarded # A(override B.C=C2) -> B -> C(override D.E=E2) -> D -> E @@ -388,5 +388,5 @@ git -C "$flakeC2" commit -a -m 'initial' # D, E, and E2 same as previous test -[[ $(nix eval --raw "$flakeC#foo" --recreate-lock-file) = "C D E2" ]] +[[ $(nix eval --raw "$flakeC#foo") = "C D E2" ]] [[ $(nix eval --raw "$flakeA#foo" --recreate-lock-file) = "A B C2 D E" ]] From 1223b30cb653d7de4a6b0ca582c6841dd8214c6c Mon Sep 17 00:00:00 2001 From: Matthew Kenigsberg Date: Fri, 18 Aug 2023 16:49:56 -0600 Subject: [PATCH 4/6] fix follows warning --- src/libexpr/flake/flake.cc | 5 +++++ tests/flakes/follow-paths.sh | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 3e2cbf505ad..7dbf1c4a3b3 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -47,6 +47,11 @@ void warnUnusedOverrides(const FlakeInputs & overrides, const InputPath & inputP "input '%s' has an override for a non-existent input '%s'", printInputPath(inputPathPrefix), id); } + if (input.follows) { + warn( + "input '%s' has a follows for a non-existent input '%s'", + printInputPath(inputPathPrefix), id); + } warnUnusedOverrides(input.overrides, inputPath); } } diff --git a/tests/flakes/follow-paths.sh b/tests/flakes/follow-paths.sh index fe9b51c652e..74cf94cf013 100644 --- a/tests/flakes/follow-paths.sh +++ b/tests/flakes/follow-paths.sh @@ -146,5 +146,5 @@ EOF git -C $flakeFollowsA add flake.nix -nix flake lock $flakeFollowsA 2>&1 | grep "warning: input 'B' has an override for a non-existent input 'invalid'" +nix flake lock $flakeFollowsA 2>&1 | grep "warning: input 'B' has a follows for a non-existent input 'invalid'" nix flake lock $flakeFollowsA 2>&1 | grep "warning: input 'B' has an override for a non-existent input 'invalid2'" From f245a933b10ea92e1717245d4789fcaee285902c Mon Sep 17 00:00:00 2001 From: Matthew Kenigsberg Date: Fri, 18 Aug 2023 18:18:05 -0600 Subject: [PATCH 5/6] better English --- src/libexpr/flake/flake.cc | 2 +- tests/flakes/follow-paths.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 7dbf1c4a3b3..1ac08f186bb 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -49,7 +49,7 @@ void warnUnusedOverrides(const FlakeInputs & overrides, const InputPath & inputP } if (input.follows) { warn( - "input '%s' has a follows for a non-existent input '%s'", + "input '%s' follows a non-existent input '%s'", printInputPath(inputPathPrefix), id); } warnUnusedOverrides(input.overrides, inputPath); diff --git a/tests/flakes/follow-paths.sh b/tests/flakes/follow-paths.sh index 74cf94cf013..13439f5d21b 100644 --- a/tests/flakes/follow-paths.sh +++ b/tests/flakes/follow-paths.sh @@ -146,5 +146,5 @@ EOF git -C $flakeFollowsA add flake.nix -nix flake lock $flakeFollowsA 2>&1 | grep "warning: input 'B' has a follows for a non-existent input 'invalid'" +nix flake lock $flakeFollowsA 2>&1 | grep "warning: input 'B' follows a non-existent input 'invalid'" nix flake lock $flakeFollowsA 2>&1 | grep "warning: input 'B' has an override for a non-existent input 'invalid2'" From ae5fe55c49a3bc82c57a41f542c3c9de96049018 Mon Sep 17 00:00:00 2001 From: Matthew Kenigsberg Date: Sat, 19 Aug 2023 11:27:32 -0600 Subject: [PATCH 6/6] correct warn for follows --- src/libexpr/flake/flake.cc | 4 ++-- tests/flakes/follow-paths.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 1ac08f186bb..c357c0f00db 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -49,8 +49,8 @@ void warnUnusedOverrides(const FlakeInputs & overrides, const InputPath & inputP } if (input.follows) { warn( - "input '%s' follows a non-existent input '%s'", - printInputPath(inputPathPrefix), id); + "input '%s' does not exist but follows '%s'", + printInputPath(inputPath), printInputPath(*input.follows)); } warnUnusedOverrides(input.overrides, inputPath); } diff --git a/tests/flakes/follow-paths.sh b/tests/flakes/follow-paths.sh index 13439f5d21b..9f97f30aaa6 100644 --- a/tests/flakes/follow-paths.sh +++ b/tests/flakes/follow-paths.sh @@ -146,5 +146,5 @@ EOF git -C $flakeFollowsA add flake.nix -nix flake lock $flakeFollowsA 2>&1 | grep "warning: input 'B' follows a non-existent input 'invalid'" +nix flake lock $flakeFollowsA 2>&1 | grep "warning: input 'B/invalid' does not exist but follows 'D'" nix flake lock $flakeFollowsA 2>&1 | grep "warning: input 'B' has an override for a non-existent input 'invalid2'"