diff --git a/flake.nix b/flake.nix index d71ffc7..677ae5d 100644 --- a/flake.nix +++ b/flake.nix @@ -152,6 +152,7 @@ newsboat = ./home/modules/programs/newsboat; mpd-auto-updater = ./home/modules/services/mpd.nix; cargo = ./home/modules/programs/cargo; + systemd-tmpfiles = ./home/modules/systemd-tmpfiles.nix; }; homeConfigurations = { diff --git a/home/home.nix b/home/home.nix index 7669c55..925846d 100644 --- a/home/home.nix +++ b/home/home.nix @@ -50,6 +50,7 @@ in { ./modules/colors.nix ./modules/shellAliases.nix ./modules/uidGid.nix + ./modules/systemd-tmpfiles.nix ./modules/programs/cargo ./modules/programs/gpg ./modules/programs/neovim/auto-clean-swapfiles.nix diff --git a/home/modules/systemd-tmpfiles.nix b/home/modules/systemd-tmpfiles.nix new file mode 100644 index 0000000..92a94aa --- /dev/null +++ b/home/modules/systemd-tmpfiles.nix @@ -0,0 +1,168 @@ +# Taken from nixpkgs: nixos/modules/system/boot/systemd/tmpfiles.nix +{ config, pkgs, lib, unstable-pkgs, ... }: +let + # TODO: 24.05, year of the types.attrsWith + inherit (unstable-pkgs.lib) types mkOption; + + cfg = config.systemd.user.tmpfiles; + + attrsWith' = + placeholder: elemType: + types.attrsWith { + inherit elemType; + inherit (lib) placeholder; + }; + + escapeArgument = lib.strings.escapeC [ + "\t" + "\n" + "\r" + " " + "\\" + ]; + + settingsOption = { + 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 = { + "10-mypackage" = { + "/var/lib/my-service/statefolder".d = { + mode = "0755"; + user = "root"; + group = "root"; + }; + }; + }; + default = { }; + type = attrsWith' "config-name" ( + attrsWith' "path" ( + attrsWith' "tmpfiles-type" ( + lib.types.submodule ( + { name, config, ... }: + { + options.type = mkOption { + type = types.str; + 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 = mkOption { + type = types.str; + default = "-"; + example = "0755"; + description = '' + The file access mode to use when creating this file or directory. + ''; + }; + options.user = mkOption { + type = 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 = mkOption { + type = 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 = mkOption { + type = 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 = mkOption { + type = 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)` + ''; + }; + } + ) + ) + ) + ); + }; + + # generates a single entry for a tmpfiles.d rule + settingsEntryToRule = path: entry: '' + '${entry.type}' '${path}' '${entry.mode}' '${entry.user}' '${entry.group}' '${entry.age}' ${escapeArgument entry.argument} + ''; + + # generates a list of tmpfiles.d rules from the attrs (paths) under tmpfiles.settings. + pathsToRules = lib.mapAttrsToList ( + path: types: lib.concatStrings (lib.mapAttrsToList (_type: settingsEntryToRule path) types) + ); + + mkRuleFileContent = paths: lib.concatStrings (pathsToRules paths); +in +{ + options.systemd.user.tmpfiles.settings = lib.mkOption settingsOption; + + config = lib.mkIf (cfg.settings != { }) { + assertions = [ + (lib.hm.assertions.assertPlatform "systemd.user.tmpfiles" pkgs + lib.platforms.linux) + ]; + + 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: paths: { + name = "user-tmpfiles.d/${name}.conf"; + value = { + text = mkRuleFileContent paths; + onChange = "${pkgs.systemd}/bin/systemd-tmpfiles --user --create"; + }; + }) cfg.settings); + }; +}