mirror of
https://github.com/NixOS/nix.git
synced 2025-12-23 17:31:08 +01:00
libflake: reject empty paths in inputUpdates
An empty path refers to the flake itself, not an input. Apply the same type safety to inputUpdates as inputOverrides. The deprecated --update-input flag (deprecated since Nix 2.4) and the modern 'nix flake update' command now properly reject empty paths. Includes functional tests for both commands.
This commit is contained in:
parent
f7fc24c973
commit
bec436c0b1
5 changed files with 24 additions and 11 deletions
|
|
@ -116,7 +116,11 @@ MixFlakeOptions::MixFlakeOptions()
|
||||||
.labels = {"input-path"},
|
.labels = {"input-path"},
|
||||||
.handler = {[&](std::string s) {
|
.handler = {[&](std::string s) {
|
||||||
warn("'--update-input' is a deprecated alias for 'flake update' and will be removed in a future version.");
|
warn("'--update-input' is a deprecated alias for 'flake update' and will be removed in a future version.");
|
||||||
lockFlags.inputUpdates.insert(flake::parseInputAttrPath(s));
|
auto path = flake::NonEmptyInputAttrPath::parse(s);
|
||||||
|
if (!path)
|
||||||
|
throw UsageError(
|
||||||
|
"--update-input was passed a zero-length input path, which would refer to the flake itself, not an input");
|
||||||
|
lockFlags.inputUpdates.insert(*path);
|
||||||
}},
|
}},
|
||||||
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
|
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
|
||||||
completeFlakeInputAttrPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix);
|
completeFlakeInputAttrPath(completions, getEvalState(), getFlakeRefsForCompletion(), prefix);
|
||||||
|
|
|
||||||
|
|
@ -617,7 +617,7 @@ lockFlake(const Settings & settings, EvalState & state, const FlakeRef & topRef,
|
||||||
|
|
||||||
updatesUsed.insert(inputAttrPath);
|
updatesUsed.insert(inputAttrPath);
|
||||||
|
|
||||||
if (oldNode && !lockFlags.inputUpdates.count(inputAttrPath))
|
if (oldNode && !lockFlags.inputUpdates.count(nonEmptyInputAttrPath))
|
||||||
if (auto oldLock2 = get(oldNode->inputs, id))
|
if (auto oldLock2 = get(oldNode->inputs, id))
|
||||||
if (auto oldLock3 = std::get_if<0>(&*oldLock2))
|
if (auto oldLock3 = std::get_if<0>(&*oldLock2))
|
||||||
oldLock = *oldLock3;
|
oldLock = *oldLock3;
|
||||||
|
|
@ -636,10 +636,10 @@ lockFlake(const Settings & settings, EvalState & state, const FlakeRef & topRef,
|
||||||
|
|
||||||
/* If we have this input in updateInputs, then we
|
/* If we have this input in updateInputs, then we
|
||||||
must fetch the flake to update it. */
|
must fetch the flake to update it. */
|
||||||
auto lb = lockFlags.inputUpdates.lower_bound(inputAttrPath);
|
auto lb = lockFlags.inputUpdates.lower_bound(nonEmptyInputAttrPath);
|
||||||
|
|
||||||
auto mustRefetch = lb != lockFlags.inputUpdates.end() && lb->size() > inputAttrPath.size()
|
auto mustRefetch = lb != lockFlags.inputUpdates.end() && lb->get().size() > inputAttrPath.size()
|
||||||
&& std::equal(inputAttrPath.begin(), inputAttrPath.end(), lb->begin());
|
&& std::equal(inputAttrPath.begin(), inputAttrPath.end(), lb->get().begin());
|
||||||
|
|
||||||
FlakeInputs fakeInputs;
|
FlakeInputs fakeInputs;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -211,7 +211,7 @@ struct LockFlags
|
||||||
* Flake inputs to be updated. This means that any existing lock
|
* Flake inputs to be updated. This means that any existing lock
|
||||||
* for those inputs will be ignored.
|
* for those inputs will be ignored.
|
||||||
*/
|
*/
|
||||||
std::set<InputAttrPath> inputUpdates;
|
std::set<NonEmptyInputAttrPath> inputUpdates;
|
||||||
};
|
};
|
||||||
|
|
||||||
LockedFlake
|
LockedFlake
|
||||||
|
|
|
||||||
|
|
@ -90,9 +90,12 @@ public:
|
||||||
.optional = true,
|
.optional = true,
|
||||||
.handler = {[&](std::vector<std::string> inputsToUpdate) {
|
.handler = {[&](std::vector<std::string> inputsToUpdate) {
|
||||||
for (const auto & inputToUpdate : inputsToUpdate) {
|
for (const auto & inputToUpdate : inputsToUpdate) {
|
||||||
InputAttrPath inputAttrPath;
|
std::optional<NonEmptyInputAttrPath> inputAttrPath;
|
||||||
try {
|
try {
|
||||||
inputAttrPath = flake::parseInputAttrPath(inputToUpdate);
|
inputAttrPath = flake::NonEmptyInputAttrPath::parse(inputToUpdate);
|
||||||
|
if (!inputAttrPath)
|
||||||
|
throw UsageError(
|
||||||
|
"input path to be updated cannot be zero-length; it would refer to the flake itself, not an input");
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
warn(
|
warn(
|
||||||
"Invalid flake input '%s'. To update a specific flake, use 'nix flake update --flake %s' instead.",
|
"Invalid flake input '%s'. To update a specific flake, use 'nix flake update --flake %s' instead.",
|
||||||
|
|
@ -100,11 +103,11 @@ public:
|
||||||
inputToUpdate);
|
inputToUpdate);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
if (lockFlags.inputUpdates.contains(inputAttrPath))
|
if (lockFlags.inputUpdates.contains(*inputAttrPath))
|
||||||
warn(
|
warn(
|
||||||
"Input '%s' was specified multiple times. You may have done this by accident.",
|
"Input '%s' was specified multiple times. You may have done this by accident.",
|
||||||
printInputAttrPath(inputAttrPath));
|
printInputAttrPath(*inputAttrPath));
|
||||||
lockFlags.inputUpdates.insert(inputAttrPath);
|
lockFlags.inputUpdates.insert(*inputAttrPath);
|
||||||
}
|
}
|
||||||
}},
|
}},
|
||||||
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
|
.completer = {[&](AddCompletions & completions, size_t, std::string_view prefix) {
|
||||||
|
|
|
||||||
|
|
@ -398,6 +398,9 @@ nix flake lock "$flake3Dir" --override-input flake2/flake1 flake1/master/"$hash1
|
||||||
# Test that --override-input with empty input path is rejected (issue #14816).
|
# Test that --override-input with empty input path is rejected (issue #14816).
|
||||||
expectStderr 1 nix flake lock "$flake3Dir" --override-input '' . | grepQuiet "input path cannot be empty"
|
expectStderr 1 nix flake lock "$flake3Dir" --override-input '' . | grepQuiet "input path cannot be empty"
|
||||||
|
|
||||||
|
# Test that deprecated --update-input with empty input path is rejected.
|
||||||
|
expectStderr 1 nix flake lock "$flake3Dir" --update-input '' | grepQuiet -- "--update-input was passed a zero-length input path, which would refer to the flake itself, not an input"
|
||||||
|
|
||||||
# Test --update-input.
|
# Test --update-input.
|
||||||
nix flake lock "$flake3Dir"
|
nix flake lock "$flake3Dir"
|
||||||
[[ $(jq -r .nodes.flake1_2.locked.rev "$flake3Dir/flake.lock") = "$hash1" ]]
|
[[ $(jq -r .nodes.flake1_2.locked.rev "$flake3Dir/flake.lock") = "$hash1" ]]
|
||||||
|
|
@ -405,6 +408,9 @@ nix flake lock "$flake3Dir"
|
||||||
nix flake update flake2/flake1 --flake "$flake3Dir"
|
nix flake update flake2/flake1 --flake "$flake3Dir"
|
||||||
[[ $(jq -r .nodes.flake1_2.locked.rev "$flake3Dir/flake.lock") =~ $hash2 ]]
|
[[ $(jq -r .nodes.flake1_2.locked.rev "$flake3Dir/flake.lock") =~ $hash2 ]]
|
||||||
|
|
||||||
|
# Test that 'nix flake update' with empty input path is rejected.
|
||||||
|
expectStderr 1 nix flake update '' --flake "$flake3Dir" | grepQuiet -- "input path to be updated cannot be zero-length; it would refer to the flake itself, not an input"
|
||||||
|
|
||||||
# Test updating multiple inputs.
|
# Test updating multiple inputs.
|
||||||
nix flake lock "$flake3Dir" --override-input flake1 flake1/master/"$hash1"
|
nix flake lock "$flake3Dir" --override-input flake1 flake1/master/"$hash1"
|
||||||
nix flake lock "$flake3Dir" --override-input flake2/flake1 flake1/master/"$hash1"
|
nix flake lock "$flake3Dir" --override-input flake2/flake1 flake1/master/"$hash1"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue