files: allow a wider range of source file names
In particular support source files whose name start with `.` or contain characters not allowed in the nix store, such as spaces. Also add some test cases for `home.file`.
This commit is contained in:
parent
46f787950a
commit
7c04351a57
|
@ -14,6 +14,15 @@ let
|
||||||
inherit homeDirectory lib pkgs;
|
inherit homeDirectory lib pkgs;
|
||||||
}).fileType;
|
}).fileType;
|
||||||
|
|
||||||
|
sourceStorePath = file:
|
||||||
|
let
|
||||||
|
sourcePath = toString file.source;
|
||||||
|
sourceName = config.lib.strings.storeFileName (baseNameOf sourcePath);
|
||||||
|
in
|
||||||
|
if builtins.hasContext sourcePath
|
||||||
|
then file.source
|
||||||
|
else builtins.path { path = file.source; name = sourceName; };
|
||||||
|
|
||||||
# A symbolic link whose target path matches this pattern will be
|
# A symbolic link whose target path matches this pattern will be
|
||||||
# considered part of a Home Manager generation.
|
# considered part of a Home Manager generation.
|
||||||
homeFilePattern = "${builtins.storeDir}/*-home-manager-files/*";
|
homeFilePattern = "${builtins.storeDir}/*-home-manager-files/*";
|
||||||
|
@ -36,20 +45,6 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
assertions = [
|
|
||||||
(let
|
|
||||||
badFiles =
|
|
||||||
filter (f: hasPrefix "." (baseNameOf f))
|
|
||||||
(map (v: toString v.source)
|
|
||||||
(attrValues cfg));
|
|
||||||
badFilesStr = toString badFiles;
|
|
||||||
in
|
|
||||||
{
|
|
||||||
assertion = badFiles == [];
|
|
||||||
message = "Source file names must not start with '.': ${badFilesStr}";
|
|
||||||
})
|
|
||||||
];
|
|
||||||
|
|
||||||
# This verifies that the links we are about to create will not
|
# This verifies that the links we are about to create will not
|
||||||
# overwrite an existing file.
|
# overwrite an existing file.
|
||||||
home.activation.checkLinkTargets = dag.entryBefore ["writeBoundary"] (
|
home.activation.checkLinkTargets = dag.entryBefore ["writeBoundary"] (
|
||||||
|
@ -201,7 +196,7 @@ in
|
||||||
''
|
''
|
||||||
declare -A changedFiles
|
declare -A changedFiles
|
||||||
'' + concatMapStrings (v: ''
|
'' + concatMapStrings (v: ''
|
||||||
cmp --quiet "${v.source}" "${config.home.homeDirectory}/${v.target}" \
|
cmp --quiet "${sourceStorePath v}" "${homeDirectory}/${v.target}" \
|
||||||
&& changedFiles["${v.target}"]=0 \
|
&& changedFiles["${v.target}"]=0 \
|
||||||
|| changedFiles["${v.target}"]=1
|
|| changedFiles["${v.target}"]=1
|
||||||
'') (filter (v: v.onChange != "") (attrValues cfg))
|
'') (filter (v: v.onChange != "") (attrValues cfg))
|
||||||
|
@ -277,7 +272,7 @@ in
|
||||||
}
|
}
|
||||||
'' + concatStrings (
|
'' + concatStrings (
|
||||||
mapAttrsToList (n: v: ''
|
mapAttrsToList (n: v: ''
|
||||||
insertFile "${v.source}" \
|
insertFile "${sourceStorePath v}" \
|
||||||
"${v.target}" \
|
"${v.target}" \
|
||||||
"${if v.executable == null
|
"${if v.executable == null
|
||||||
then "inherit"
|
then "inherit"
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
entryBefore = d.dagEntryBefore;
|
entryBefore = d.dagEntryBefore;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
strings = import ./strings.nix { inherit lib; };
|
||||||
|
|
||||||
shell = import ./shell.nix { inherit lib; };
|
shell = import ./shell.nix { inherit lib; };
|
||||||
zsh = import ./zsh.nix { inherit lib; };
|
zsh = import ./zsh.nix { inherit lib; };
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,27 +4,7 @@ with lib;
|
||||||
|
|
||||||
let
|
let
|
||||||
|
|
||||||
# Figures out a valid Nix store name for the given path.
|
stringsExtra = import ./strings.nix { inherit lib; };
|
||||||
storeFileName = path:
|
|
||||||
let
|
|
||||||
# All characters that are considered safe. Note "-" is not
|
|
||||||
# included to avoid "-" followed by digit being interpreted as a
|
|
||||||
# version.
|
|
||||||
safeChars =
|
|
||||||
[ "+" "." "_" "?" "=" ]
|
|
||||||
++ lowerChars
|
|
||||||
++ upperChars
|
|
||||||
++ stringToCharacters "0123456789";
|
|
||||||
|
|
||||||
empties = l: genList (x: "") (length l);
|
|
||||||
|
|
||||||
unsafeInName = stringToCharacters (
|
|
||||||
replaceStrings safeChars (empties safeChars) path
|
|
||||||
);
|
|
||||||
|
|
||||||
safeName = replaceStrings unsafeInName (empties unsafeInName) path;
|
|
||||||
in
|
|
||||||
"home_file_" + safeName;
|
|
||||||
|
|
||||||
in
|
in
|
||||||
|
|
||||||
|
@ -113,7 +93,7 @@ in
|
||||||
source = mkIf (config.text != null) (
|
source = mkIf (config.text != null) (
|
||||||
mkDefault (pkgs.writeTextFile {
|
mkDefault (pkgs.writeTextFile {
|
||||||
inherit (config) executable text;
|
inherit (config) executable text;
|
||||||
name = storeFileName name;
|
name = stringsExtra.storeFileName name;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
27
modules/lib/strings.nix
Normal file
27
modules/lib/strings.nix
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
{ lib }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
{
|
||||||
|
# Figures out a valid Nix store name for the given path.
|
||||||
|
storeFileName = path:
|
||||||
|
let
|
||||||
|
# All characters that are considered safe. Note "-" is not
|
||||||
|
# included to avoid "-" followed by digit being interpreted as a
|
||||||
|
# version.
|
||||||
|
safeChars =
|
||||||
|
[ "+" "." "_" "?" "=" ]
|
||||||
|
++ lowerChars
|
||||||
|
++ upperChars
|
||||||
|
++ stringToCharacters "0123456789";
|
||||||
|
|
||||||
|
empties = l: genList (x: "") (length l);
|
||||||
|
|
||||||
|
unsafeInName = stringToCharacters (
|
||||||
|
replaceStrings safeChars (empties safeChars) path
|
||||||
|
);
|
||||||
|
|
||||||
|
safeName = replaceStrings unsafeInName (empties unsafeInName) path;
|
||||||
|
in
|
||||||
|
"hm_" + safeName;
|
||||||
|
}
|
|
@ -16,6 +16,10 @@ import nmt {
|
||||||
modules = import ../modules/modules.nix { inherit pkgs; lib = pkgs.lib; };
|
modules = import ../modules/modules.nix { inherit pkgs; lib = pkgs.lib; };
|
||||||
testedAttrPath = [ "home" "activationPackage" ];
|
testedAttrPath = [ "home" "activationPackage" ];
|
||||||
tests = {
|
tests = {
|
||||||
|
files-executable = ./modules/files/executable.nix;
|
||||||
|
files-hidden-source = ./modules/files/hidden-source.nix;
|
||||||
|
files-source-with-spaces = ./modules/files/source-with-spaces.nix;
|
||||||
|
files-text = ./modules/files/text.nix;
|
||||||
git-with-most-options = ./modules/programs/git.nix;
|
git-with-most-options = ./modules/programs/git.nix;
|
||||||
git-with-str-extra-config = ./modules/programs/git-with-str-extra-config.nix;
|
git-with-str-extra-config = ./modules/programs/git-with-str-extra-config.nix;
|
||||||
texlive-minimal = ./modules/programs/texlive-minimal.nix;
|
texlive-minimal = ./modules/programs/texlive-minimal.nix;
|
||||||
|
|
1
tests/modules/files/.hidden
Normal file
1
tests/modules/files/.hidden
Normal file
|
@ -0,0 +1 @@
|
||||||
|
The name of this file has a dot prefix.
|
17
tests/modules/files/executable.nix
Normal file
17
tests/modules/files/executable.nix
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
{
|
||||||
|
config = {
|
||||||
|
home.file."executable" = {
|
||||||
|
text = "";
|
||||||
|
executable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists home-files/executable
|
||||||
|
assertFileIsExecutable home-files/executable;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
16
tests/modules/files/hidden-source.nix
Normal file
16
tests/modules/files/hidden-source.nix
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
{
|
||||||
|
config = {
|
||||||
|
home.file.".hidden".source = ./.hidden;
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists home-files/.hidden;
|
||||||
|
assertFileContent home-files/.hidden ${
|
||||||
|
builtins.path { path = ./.hidden; name = "expected"; }
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
1
tests/modules/files/source with spaces!
Normal file
1
tests/modules/files/source with spaces!
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Source with spaces!
|
20
tests/modules/files/source-with-spaces.nix
Normal file
20
tests/modules/files/source-with-spaces.nix
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
{
|
||||||
|
config = {
|
||||||
|
home.file."source with spaces!".source = ./. + "/source with spaces!";
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists 'home-files/source with spaces!';
|
||||||
|
assertFileContent 'home-files/source with spaces!' \
|
||||||
|
${
|
||||||
|
builtins.path {
|
||||||
|
path = ./. + "/source with spaces!";
|
||||||
|
name = "source-with-spaces-expected";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
2
tests/modules/files/text-expected.txt
Normal file
2
tests/modules/files/text-expected.txt
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
This is the
|
||||||
|
expected text.
|
18
tests/modules/files/text.nix
Normal file
18
tests/modules/files/text.nix
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
{
|
||||||
|
config = {
|
||||||
|
home.file."using-text".text = ''
|
||||||
|
This is the
|
||||||
|
expected text.
|
||||||
|
'';
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertFileExists home-files/using-text
|
||||||
|
assertFileIsNotExecutable home-files/using-text
|
||||||
|
assertFileContent home-files/using-text ${./text-expected.txt}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in a new issue