mirror of
https://github.com/nix-community/home-manager.git
synced 2025-11-08 19:46:05 +01:00
tmpfiles: migrate to an RFC42-style option
This commit is contained in:
parent
32a671dce5
commit
090aa14e5d
9 changed files with 247 additions and 31 deletions
|
|
@ -9,38 +9,193 @@ let
|
||||||
|
|
||||||
cfg = config.systemd.user.tmpfiles;
|
cfg = config.systemd.user.tmpfiles;
|
||||||
|
|
||||||
|
ruleSubmodule = lib.types.submodule (
|
||||||
|
{ name, ... }:
|
||||||
|
{
|
||||||
|
options.type = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
readOnly = true;
|
||||||
|
default = name;
|
||||||
|
defaultText = "‹tmpfiles-type›";
|
||||||
|
example = "d";
|
||||||
|
description = ''
|
||||||
|
The type of operation to perform on the file.
|
||||||
|
|
||||||
|
The type consists of a single letter and optionally one or more
|
||||||
|
modifier characters.
|
||||||
|
|
||||||
|
Please see the upstream documentation for the available types and
|
||||||
|
more details: {manpage}`tmpfiles.d(5)`
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
options.mode = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "-";
|
||||||
|
example = "0755";
|
||||||
|
description = ''
|
||||||
|
The file access mode to use when creating this file or directory.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
options.user = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "-";
|
||||||
|
example = "root";
|
||||||
|
description = ''
|
||||||
|
The user of the file.
|
||||||
|
|
||||||
|
This may either be a numeric ID or a user/group name.
|
||||||
|
|
||||||
|
If omitted or when set to `"-"`, the user and group of the user who
|
||||||
|
invokes systemd-tmpfiles is used.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
options.group = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "-";
|
||||||
|
example = "root";
|
||||||
|
description = ''
|
||||||
|
The group of the file.
|
||||||
|
|
||||||
|
This may either be a numeric ID or a user/group name.
|
||||||
|
|
||||||
|
If omitted or when set to `"-"`, the user and group of the user who
|
||||||
|
invokes systemd-tmpfiles is used.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
options.age = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "-";
|
||||||
|
example = "10d";
|
||||||
|
description = ''
|
||||||
|
Delete a file when it reaches a certain age.
|
||||||
|
|
||||||
|
If a file or directory is older than the current time minus the age
|
||||||
|
field, it is deleted.
|
||||||
|
|
||||||
|
If set to `"-"`, no automatic clean-up is done.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
options.argument = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
default = "";
|
||||||
|
example = "";
|
||||||
|
description = ''
|
||||||
|
An argument whose meaning depends on the type of operation.
|
||||||
|
|
||||||
|
Please see the upstream documentation for the meaning of this
|
||||||
|
parameter in different situations: {manpage}`tmpfiles.d(5)`
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
modulePrefix = [
|
||||||
|
"systemd"
|
||||||
|
"user"
|
||||||
|
"tmpfiles"
|
||||||
|
"settings"
|
||||||
|
];
|
||||||
|
|
||||||
|
mkFileName = configName: "user-tmpfiles.d/home-manager-${configName}.conf";
|
||||||
|
|
||||||
|
mkConfigFile =
|
||||||
|
name: rules:
|
||||||
|
let
|
||||||
|
escapeArgument = lib.strings.escapeC [
|
||||||
|
"\t"
|
||||||
|
"\n"
|
||||||
|
"\r"
|
||||||
|
" "
|
||||||
|
"\\"
|
||||||
|
];
|
||||||
|
mkRule = path: rule: ''
|
||||||
|
'${rule.type}' '${path}' '${rule.mode}' '${rule.user}' '${rule.group}' '${rule.age}' ${escapeArgument rule.argument}
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
{
|
||||||
|
text = ''
|
||||||
|
# This file was generated by Home Manager and should not be modified.
|
||||||
|
# Please change the option '${lib.showAttrPath (modulePrefix ++ [ name ])}' instead.
|
||||||
|
${lib.pipe rules [
|
||||||
|
(lib.mapAttrs (_path: lib.attrValues))
|
||||||
|
(lib.mapAttrsToList (path: map (mkRule path)))
|
||||||
|
lib.flatten
|
||||||
|
lib.concatStrings
|
||||||
|
]}
|
||||||
|
'';
|
||||||
|
onChange = ''
|
||||||
|
run ${pkgs.systemd}/bin/systemd-tmpfiles --user --remove --create ''${DRY_RUN:+--dry-run} '${mkFileName name}'
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
meta.maintainers = [ lib.maintainers.dawidsowa ];
|
meta.maintainers = [ lib.maintainers.dawidsowa ];
|
||||||
|
|
||||||
options.systemd.user.tmpfiles.rules = lib.mkOption {
|
imports = [
|
||||||
type = lib.types.listOf lib.types.str;
|
(lib.mkRemovedOptionModule [ "systemd" "user" "tmpfiles" "rules" ] ''
|
||||||
default = [ ];
|
It has been replaced by 'systemd.user.tmpfiles.settings'.
|
||||||
example = [ "L /home/user/Documents - - - - /mnt/data/Documents" ];
|
'')
|
||||||
|
];
|
||||||
|
|
||||||
|
options.systemd.user.tmpfiles.settings = lib.mkOption {
|
||||||
description = ''
|
description = ''
|
||||||
Rules for creating and cleaning up temporary files
|
Declare systemd-tmpfiles rules to create, delete, and clean up volatile
|
||||||
automatically. See
|
and temporary files and directories.
|
||||||
{manpage}`tmpfiles.d(5)`
|
|
||||||
for the exact format.
|
Even though the service is called `*tmp*files` you can also create
|
||||||
|
persistent files.
|
||||||
'';
|
'';
|
||||||
|
example = {
|
||||||
|
cache."%C".d = {
|
||||||
|
mode = "0755";
|
||||||
|
user = "alice";
|
||||||
|
group = "alice";
|
||||||
|
age = "4 weeks";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
default = { };
|
||||||
|
type =
|
||||||
|
let
|
||||||
|
attrsWith' = placeholder: elemType: lib.types.attrsWith { inherit elemType placeholder; };
|
||||||
|
nonEmptyAttrsWith' =
|
||||||
|
placeholder: elemType:
|
||||||
|
let
|
||||||
|
attrs = lib.types.addCheck (attrsWith' placeholder elemType) (s: s != { });
|
||||||
|
in
|
||||||
|
attrs
|
||||||
|
// {
|
||||||
|
name = "nonEmptyAttrsOf";
|
||||||
|
description = "non-empty ${attrs.description}";
|
||||||
|
emptyValue = { }; # no .value attribute, meaning there is not empty value
|
||||||
|
substSubModules = m: nonEmptyAttrsWith' placeholder (elemType.substSubModules m);
|
||||||
|
};
|
||||||
|
in
|
||||||
|
attrsWith' "config-name" (
|
||||||
|
nonEmptyAttrsWith' "path" (nonEmptyAttrsWith' "tmpfiles-type" ruleSubmodule)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf (cfg.rules != [ ]) {
|
config = lib.mkIf (cfg.settings != { }) {
|
||||||
assertions = [
|
assertions = [
|
||||||
(lib.hm.assertions.assertPlatform "systemd.user.tmpfiles" pkgs lib.platforms.linux)
|
(lib.hm.assertions.assertPlatform "systemd.user.tmpfiles" pkgs lib.platforms.linux)
|
||||||
];
|
];
|
||||||
|
|
||||||
|
warnings = lib.flatten (
|
||||||
|
lib.mapAttrsToListRecursive (
|
||||||
|
path: value:
|
||||||
|
lib.optional
|
||||||
|
(lib.last path == "argument" && lib.match ''.*\\([nrt]|x[0-9A-Fa-f]{2}).*'' value != null)
|
||||||
|
''
|
||||||
|
The '${lib.showAttrPath (modulePrefix ++ path)}' option
|
||||||
|
appears to contain escape sequences, which will be escaped again.
|
||||||
|
Unescape them if this is not intended. The assigned string is:
|
||||||
|
"${value}"
|
||||||
|
''
|
||||||
|
) cfg.settings
|
||||||
|
);
|
||||||
|
|
||||||
xdg.configFile = {
|
xdg.configFile = {
|
||||||
"user-tmpfiles.d/home-manager.conf" = {
|
|
||||||
text = ''
|
|
||||||
# This file is created automatically and should not be modified.
|
|
||||||
# Please change the option ‘systemd.user.tmpfiles.rules’ instead.
|
|
||||||
${lib.concatStringsSep "\n" cfg.rules}
|
|
||||||
'';
|
|
||||||
onChange = ''
|
|
||||||
run ${pkgs.systemd}/bin/systemd-tmpfiles --user --remove --create ''${DRY_RUN:+--dry-run}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
"systemd/user/basic.target.wants/systemd-tmpfiles-setup.service".source =
|
"systemd/user/basic.target.wants/systemd-tmpfiles-setup.service".source =
|
||||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-setup.service";
|
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-setup.service";
|
||||||
"systemd/user/systemd-tmpfiles-setup.service".source =
|
"systemd/user/systemd-tmpfiles-setup.service".source =
|
||||||
|
|
@ -49,6 +204,9 @@ in
|
||||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-clean.timer";
|
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-clean.timer";
|
||||||
"systemd/user/systemd-tmpfiles-clean.service".source =
|
"systemd/user/systemd-tmpfiles-clean.service".source =
|
||||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-clean.service";
|
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-clean.service";
|
||||||
};
|
}
|
||||||
|
// lib.mapAttrs' (
|
||||||
|
name: rules: lib.nameValuePair (mkFileName name) (mkConfigFile name rules)
|
||||||
|
) cfg.settings;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,14 +36,12 @@ in
|
||||||
|
|
||||||
# Use `systemd-tmpfiles` since glab requires its configuration file to have
|
# Use `systemd-tmpfiles` since glab requires its configuration file to have
|
||||||
# mode 0600.
|
# mode 0600.
|
||||||
systemd.user.tmpfiles.rules =
|
systemd.user.tmpfiles.settings.glab = lib.mkIf (cfg.settings != { }) {
|
||||||
let
|
"${config.xdg.configHome}/glab-cli/config.yml" = {
|
||||||
target = "${config.xdg.configHome}/glab-cli/config.yml";
|
"C+".argument = yaml.generate "glab-config" cfg.settings;
|
||||||
in
|
z.mode = "0600";
|
||||||
lib.mkIf (cfg.settings != { }) [
|
};
|
||||||
"C+ ${target} - - - - ${yaml.generate "glab-config" cfg.settings}"
|
};
|
||||||
"z ${target} 0600"
|
|
||||||
];
|
|
||||||
|
|
||||||
xdg.configFile."glab-cli/aliases.yml" = lib.mkIf (cfg.aliases != { }) {
|
xdg.configFile."glab-cli/aliases.yml" = lib.mkIf (cfg.aliases != { }) {
|
||||||
source = yaml.generate "glab-aliases" cfg.aliases;
|
source = yaml.generate "glab-aliases" cfg.aliases;
|
||||||
|
|
|
||||||
|
|
@ -203,6 +203,7 @@ import nmtSrc {
|
||||||
./modules/misc/numlock
|
./modules/misc/numlock
|
||||||
./modules/misc/pam
|
./modules/misc/pam
|
||||||
./modules/misc/qt
|
./modules/misc/qt
|
||||||
|
./modules/misc/tmpfiles
|
||||||
./modules/misc/xdg/linux.nix
|
./modules/misc/xdg/linux.nix
|
||||||
./modules/misc/xsession
|
./modules/misc/xsession
|
||||||
./modules/systemd
|
./modules/systemd
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,12 @@ in
|
||||||
uid = 1000;
|
uid = 1000;
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.settings.age."/home/alice/age-key".f = {
|
||||||
"f /home/alice/age-key 400 alice users - ${ageKey}"
|
mode = "400";
|
||||||
];
|
user = "alice";
|
||||||
|
group = "users";
|
||||||
|
argument = ageKey;
|
||||||
|
};
|
||||||
|
|
||||||
home-manager.users.alice =
|
home-manager.users.alice =
|
||||||
{ config, ... }:
|
{ config, ... }:
|
||||||
|
|
|
||||||
24
tests/modules/misc/tmpfiles/basic-rules.nix
Normal file
24
tests/modules/misc/tmpfiles/basic-rules.nix
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
{
|
||||||
|
imports = [ ./common-stubs.nix ];
|
||||||
|
|
||||||
|
systemd.user.tmpfiles.settings = {
|
||||||
|
cache."%C".d.age = "4 weeks";
|
||||||
|
myTool."%h/.config/myTool.conf"."f+" = {
|
||||||
|
mode = "0644";
|
||||||
|
user = "alice";
|
||||||
|
group = "users";
|
||||||
|
argument = "my unescaped config";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
cacheRulesFile=home-files/.config/user-tmpfiles.d/home-manager-cache.conf
|
||||||
|
assertFileExists $cacheRulesFile
|
||||||
|
assertFileRegex $cacheRulesFile "^'d' '%C' '-' '-' '-' '4 weeks' $"
|
||||||
|
|
||||||
|
myToolRulesFile=home-files/.config/user-tmpfiles.d/home-manager-myTool.conf
|
||||||
|
assertFileExists $myToolRulesFile
|
||||||
|
assertFileRegex $myToolRulesFile \
|
||||||
|
"^'f+' '%h/.config/myTool.conf' '0644' 'alice' 'users' '-' my\\\\x20unescaped\\\\x20config$"
|
||||||
|
'';
|
||||||
|
}
|
||||||
3
tests/modules/misc/tmpfiles/common-stubs.nix
Normal file
3
tests/modules/misc/tmpfiles/common-stubs.nix
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
test.stubs.systemd.outPath = null;
|
||||||
|
}
|
||||||
6
tests/modules/misc/tmpfiles/default.nix
Normal file
6
tests/modules/misc/tmpfiles/default.nix
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
tmpfiles-no-rules = ./no-rules.nix;
|
||||||
|
tmpfiles-basic-rules = ./basic-rules.nix;
|
||||||
|
|
||||||
|
tmpfiles-escaped-argument-warning = ./escaped-argument-warning.nix;
|
||||||
|
}
|
||||||
14
tests/modules/misc/tmpfiles/escaped-argument-warning.nix
Normal file
14
tests/modules/misc/tmpfiles/escaped-argument-warning.nix
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
imports = [ ./common-stubs.nix ];
|
||||||
|
|
||||||
|
systemd.user.tmpfiles.settings.foo.path.f.argument = "my\\x20unescaped\\x20config";
|
||||||
|
|
||||||
|
test.asserts.warnings.expected = [
|
||||||
|
''
|
||||||
|
The 'systemd.user.tmpfiles.settings.foo.path.f.argument' option
|
||||||
|
appears to contain escape sequences, which will be escaped again.
|
||||||
|
Unescape them if this is not intended. The assigned string is:
|
||||||
|
"my\x20unescaped\x20config"
|
||||||
|
''
|
||||||
|
];
|
||||||
|
}
|
||||||
9
tests/modules/misc/tmpfiles/no-rules.nix
Normal file
9
tests/modules/misc/tmpfiles/no-rules.nix
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
imports = [ ./common-stubs.nix ];
|
||||||
|
|
||||||
|
systemd.user.tmpfiles.settings = { };
|
||||||
|
|
||||||
|
nmt.script = ''
|
||||||
|
assertPathNotExists home-files/.config/user-tmpfiles.d/
|
||||||
|
'';
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue