mirror of
https://github.com/nix-community/home-manager.git
synced 2025-11-08 11:36:05 +01:00
tmpfiles: add option to purge rules' targets on change
This commit is contained in:
parent
090aa14e5d
commit
b4350d54c2
7 changed files with 151 additions and 58 deletions
|
|
@ -89,6 +89,46 @@ 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);
|
||||
};
|
||||
|
||||
configSubmodule = lib.types.submodule {
|
||||
options.rules = lib.mkOption {
|
||||
description = "The rules contained in this configuration.";
|
||||
example = {
|
||||
"%C".d = {
|
||||
mode = "0755";
|
||||
user = "alice";
|
||||
group = "alice";
|
||||
age = "4 weeks";
|
||||
};
|
||||
};
|
||||
type = nonEmptyAttrsWith' "path" (nonEmptyAttrsWith' "tmpfiles-type" ruleSubmodule);
|
||||
};
|
||||
options.purgeOnChange = lib.mkOption {
|
||||
description = ''
|
||||
Whether the rules that are marked for purging, will automatically
|
||||
be purged when the set of rules changes.
|
||||
|
||||
See {manpage}`systemd-tmpfiles(8)` for details about purging.
|
||||
'';
|
||||
type = lib.types.bool;
|
||||
default = false;
|
||||
};
|
||||
};
|
||||
|
||||
modulePrefix = [
|
||||
"systemd"
|
||||
"user"
|
||||
|
|
@ -100,6 +140,9 @@ let
|
|||
|
||||
mkConfigFile =
|
||||
name: rules:
|
||||
{
|
||||
suffix ? [ name ],
|
||||
}:
|
||||
let
|
||||
escapeArgument = lib.strings.escapeC [
|
||||
"\t"
|
||||
|
|
@ -115,7 +158,7 @@ let
|
|||
{
|
||||
text = ''
|
||||
# This file was generated by Home Manager and should not be modified.
|
||||
# Please change the option '${lib.showAttrPath (modulePrefix ++ [ name ])}' instead.
|
||||
# Please change the option '${lib.showAttrPath (modulePrefix ++ suffix)}' instead.
|
||||
${lib.pipe rules [
|
||||
(lib.mapAttrs (_path: lib.attrValues))
|
||||
(lib.mapAttrsToList (path: map (mkRule path)))
|
||||
|
|
@ -128,6 +171,13 @@ let
|
|||
'';
|
||||
};
|
||||
|
||||
nonPurgedConfigs = lib.filterAttrs (_name: config: !config.purgeOnChange) cfg.settings;
|
||||
purgedConfigs = lib.filterAttrs (_name: config: config.purgeOnChange) cfg.settings;
|
||||
|
||||
# WARNING: When changing this path, the next home-manager generation will
|
||||
# not find and the rules of the old generation that are subject to purging.
|
||||
purgedRulesConfigName = "purge-on-change";
|
||||
|
||||
in
|
||||
{
|
||||
meta.maintainers = [ lib.maintainers.dawidsowa ];
|
||||
|
|
@ -147,7 +197,7 @@ in
|
|||
persistent files.
|
||||
'';
|
||||
example = {
|
||||
cache."%C".d = {
|
||||
cache.rules."%C".d = {
|
||||
mode = "0755";
|
||||
user = "alice";
|
||||
group = "alice";
|
||||
|
|
@ -155,58 +205,70 @@ in
|
|||
};
|
||||
};
|
||||
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)
|
||||
type = attrsWith' "config-name" configSubmodule;
|
||||
};
|
||||
|
||||
config = lib.mkMerge [
|
||||
|
||||
(lib.mkIf pkgs.stdenv.hostPlatform.isLinux {
|
||||
# The activation script must be enabled unconditionally in order to
|
||||
# guarantee that the old rules are purged even if the new set of rules
|
||||
# is empty, i.e. `cfg.rulesToPurgeOnChange == [ ]`.
|
||||
home.activation.purgeTmpfiles = lib.hm.dag.entryAfter [ "writeBoundary" ] (
|
||||
let
|
||||
relativeXdgConfigHome = lib.strings.removePrefix "${config.home.homeDirectory}/" config.xdg.configHome;
|
||||
configPath = "home-files/${relativeXdgConfigHome}/${purgedRulesConfigName}";
|
||||
in
|
||||
''
|
||||
if [[ -v oldGenPath && -f $oldGenPath/${configPath} ]] &&
|
||||
diff -q $oldGenPath/${configPath} $newGenPath/${configPath} &>/dev/null; then
|
||||
verboseEcho "Purge old tmpfiles"
|
||||
run ${pkgs.systemd}/bin/systemd-tmpfiles --user --purge ''${DRY_RUN:+--dry-run} $oldGenPath/${configPath}
|
||||
fi
|
||||
''
|
||||
);
|
||||
};
|
||||
})
|
||||
|
||||
config = lib.mkIf (cfg.settings != { }) {
|
||||
assertions = [
|
||||
(lib.hm.assertions.assertPlatform "systemd.user.tmpfiles" pkgs lib.platforms.linux)
|
||||
];
|
||||
(lib.mkIf (cfg.settings != { }) {
|
||||
assertions = [
|
||||
(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
|
||||
);
|
||||
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 = {
|
||||
"systemd/user/basic.target.wants/systemd-tmpfiles-setup.service".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-setup.service";
|
||||
"systemd/user/systemd-tmpfiles-setup.service".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-setup.service";
|
||||
"systemd/user/timers.target.wants/systemd-tmpfiles-clean.timer".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-clean.timer";
|
||||
"systemd/user/systemd-tmpfiles-clean.service".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-clean.service";
|
||||
}
|
||||
// lib.mapAttrs' (
|
||||
name: rules: lib.nameValuePair (mkFileName name) (mkConfigFile name rules)
|
||||
) cfg.settings;
|
||||
};
|
||||
xdg.configFile = {
|
||||
"systemd/user/basic.target.wants/systemd-tmpfiles-setup.service".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-setup.service";
|
||||
"systemd/user/systemd-tmpfiles-setup.service".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-setup.service";
|
||||
"systemd/user/timers.target.wants/systemd-tmpfiles-clean.timer".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-clean.timer";
|
||||
"systemd/user/systemd-tmpfiles-clean.service".source =
|
||||
"${pkgs.systemd}/example/systemd/user/systemd-tmpfiles-clean.service";
|
||||
}
|
||||
// lib.mapAttrs' (
|
||||
name: config: lib.nameValuePair (mkFileName name) (mkConfigFile name config.rules { })
|
||||
) nonPurgedConfigs
|
||||
// lib.optionalAttrs (purgedConfigs != { }) {
|
||||
${mkFileName purgedRulesConfigName} =
|
||||
let
|
||||
purgedConfigsMerged = lib.foldl' lib.recursiveUpdate { } (lib.attrValues purgedConfigs);
|
||||
in
|
||||
mkConfigFile purgedRulesConfigName purgedConfigsMerged.rules { suffix = [ ]; };
|
||||
};
|
||||
})
|
||||
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ in
|
|||
# Use `systemd-tmpfiles` since glab requires its configuration file to have
|
||||
# mode 0600.
|
||||
systemd.user.tmpfiles.settings.glab = lib.mkIf (cfg.settings != { }) {
|
||||
"${config.xdg.configHome}/glab-cli/config.yml" = {
|
||||
rules."${config.xdg.configHome}/glab-cli/config.yml" = {
|
||||
"C+".argument = yaml.generate "glab-config" cfg.settings;
|
||||
z.mode = "0600";
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue