{ config, lib, pkgs, ... }: let 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 { meta.maintainers = [ lib.maintainers.dawidsowa ]; imports = [ (lib.mkRemovedOptionModule [ "systemd" "user" "tmpfiles" "rules" ] '' It has been replaced by 'systemd.user.tmpfiles.settings'. '') ]; options.systemd.user.tmpfiles.settings = lib.mkOption { description = '' Declare systemd-tmpfiles rules to create, delete, and clean up volatile and temporary files and directories. 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.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 ); 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; }; }