files: assert that target files are unique

Fixes #1807
This commit is contained in:
Robert Helgesson 2021-06-27 16:42:45 +02:00
parent f4998f0adc
commit 2aeaf65e8f
No known key found for this signature in database
GPG key ID: 36BDAA14C2797E89
3 changed files with 58 additions and 0 deletions

View file

@ -39,6 +39,28 @@ in
};
config = {
assertions = [(
let
dups =
attrNames
(filterAttrs (n: v: v > 1)
(foldAttrs (acc: v: acc + v) 0
(mapAttrsToList (n: v: { ${v.target} = 1; }) cfg)));
dupsStr = concatStringsSep ", " dups;
in {
assertion = dups == [];
message = ''
Conflicting managed target files: ${dupsStr}
This may happen, for example, if you have a configuration similar to
home.file = {
conflict1 = { source = ./foo.nix; target = "baz"; };
conflict2 = { source = ./bar.nix; target = "baz"; };
}'';
})
];
lib.file.mkOutOfStoreSymlink = path:
let
pathStr = toString path;
@ -283,6 +305,15 @@ in
local executable="$3"
local recursive="$4"
# If the target already exists then we have a collision. Note, this
# should not happen due to the assertion found in the 'files' module.
# We therefore simply log the conflict and otherwise ignore it, mainly
# to make the `files-target-config` test work as expected.
if [[ -e "$realOut/$relTarget" ]]; then
echo "File conflict for file '$relTarget'" >&2
return
fi
# Figure out the real absolute path to the target.
local target
target="$(realpath -m "$realOut/$relTarget")"

View file

@ -3,6 +3,7 @@
files-hidden-source = ./hidden-source.nix;
files-out-of-store-symlink = ./out-of-store-symlink.nix;
files-source-with-spaces = ./source-with-spaces.nix;
files-target-conflict = ./target-conflict.nix;
files-target-with-shellvar = ./target-with-shellvar.nix;
files-text = ./text.nix;
}

View file

@ -0,0 +1,26 @@
{ ... }:
{
config = {
home.file = {
conflict1 = {
text = "";
target = "baz";
};
conflict2 = {
source = ./target-conflict.nix;
target = "baz";
};
};
test.asserts.assertions.expected = [''
Conflicting managed target files: baz
This may happen, for example, if you have a configuration similar to
home.file = {
conflict1 = { source = ./foo.nix; target = "baz"; };
conflict2 = { source = ./bar.nix; target = "baz"; };
}''];
};
}