Skip to content

Commit

Permalink
flakes: throw an error if follows-declaration for an input is invalid
Browse files Browse the repository at this point in the history
I recently got fairly confused why the following expression didn't have
any effect

    {
      description = "Foobar";
      inputs.sops-nix = {
        url = github:mic92/sops-nix;
        inputs.nixpkgs_22_05.follows = "nixpkgs";
      };
    }

until I found out that the input was called `nixpkgs-22_05` (please note
the dash vs. underscore).

IMHO it's not a good idea to not throw an error in that case and
probably leave end-users rather confused, so I implemented a small check
for that which basically checks whether `follows`-declaration from
overrides actually have corresponding inputs in the transitive flake.

In fact this was done by accident already in our own test-suite where
the removal of a `follows` was apparently forgotten[1].

Since the key of the `std::map` that holds the `overrides` is a vector
and we have to find the last element of each vector (i.e. the override)
this has to be done with a for loop in O(n) complexity with `n` being
the total amount of overrides (which shouldn't be that large though).

Please note that this doesn't work with nested expressions, i.e.

    inputs.fenix.inputs.nixpkgs.follows = "...";

which is a known problem[2].

For the expression demonstrated above, an error like this will be
thrown:

    error: sops-nix has a `follows'-declaration for a non-existant input nixpkgs_22_05!

[1] 2664a21
[2] NixOS#5790
  • Loading branch information
Ma27 committed Jul 12, 2022
1 parent f071eb3 commit c1c37f3
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 1 deletion.
23 changes: 23 additions & 0 deletions src/libexpr/flake/flake.cc
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,29 @@ LockedFlake lockFlake(
{
debug("computing lock file node '%s'", printInputPath(inputPathPrefix));

auto overrides2 = overrides;
for (auto & [inputPath, inputOverride] : overrides2) {
auto inputPath2(inputPath);
auto follow = inputPath2.back();
inputPath2.pop_back();
if (inputPath2 == inputPathPrefix
&& flakeInputs.find(follow) == flakeInputs.end()
) {
std::string root;
for (auto & element : inputPath2) {
root.append(element);
if (element != inputPath2.back()) {
root.append(".inputs.");
}
}
throw Error(
"%s has a `follows'-declaration for a non-existant input %s!",
root,
follow
);
}
}

/* Get the overrides (i.e. attributes of the form
'inputs.nixops.inputs.nixpkgs.url = ...'). */
for (auto & [id, input] : flakeInputs) {
Expand Down
21 changes: 20 additions & 1 deletion tests/flakes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,8 @@ nix flake metadata $flakeFollowsA

nix flake update $flakeFollowsA

nix flake lock $flakeFollowsA

oldLock="$(cat "$flakeFollowsA/flake.lock")"

# Ensure that locking twice doesn't change anything
Expand All @@ -823,7 +825,6 @@ cat > $flakeFollowsA/flake.nix <<EOF
inputs = {
B = {
url = "path:./flakeB";
inputs.nonFlake.follows = "D";
};
D.url = "path:./flakeD";
};
Expand Down Expand Up @@ -859,3 +860,21 @@ nix store delete $(nix store add-path $badFlakeDir)

[[ $(nix path-info $(nix store add-path $flake1Dir)) =~ flake1 ]]
[[ $(nix path-info path:$(nix store add-path $flake1Dir)) =~ simple ]]

# Non-existant follows causes an error

cat >$flakeFollowsA/flake.nix <<EOF
{
description = "Flake A";
inputs.B = {
url = "path:./flakeB";
inputs.invalid.follows = "D";
};
inputs.D.url = "path:./flakeD";
outputs = { ... }: {};
}
EOF

git -C $flakeFollowsA add flake.nix

nix flake lock $flakeFollowsA 2>&1 | grep "error: B has a \`follows'-declaration for a non-existant input invalid!"

0 comments on commit c1c37f3

Please sign in to comment.