···136136137137- `services.sourcehut.dispatch` and the corresponding package (`sourcehut.dispatchsrht`) have been removed due to [upstream deprecation](https://sourcehut.org/blog/2022-08-01-dispatch-deprecation-plans/).
138138139139+- The attributes used by `services.snapper.configs.<name>` have changed. Migrate from this:
140140+141141+ ```nix
142142+ services.snapper.configs.example = {
143143+ subvolume = "/example";
144144+ extraConfig = ''
145145+ ALLOW_USERS="alice"
146146+ '';
147147+ };
148148+ ```
149149+150150+ to this:
151151+152152+ ```nix
153153+ services.snapper.configs.example = {
154154+ SUBVOLUME = "/example";
155155+ ALLOW_USERS = [ "alice" ];
156156+ };
157157+ ```
158158+139159- The [services.snapserver.openFirewall](#opt-services.snapserver.openFirewall) module option default value has been changed from `true` to `false`. You will need to explicitly set this option to `true`, or configure your firewall.
140160141161- The [services.tmate-ssh-server.openFirewall](#opt-services.tmate-ssh-server.openFirewall) module option default value has been changed from `true` to `false`. You will need to explicitly set this option to `true`, or configure your firewall.
+107-39
nixos/modules/services/misc/snapper.nix
···4455let
66 cfg = config.services.snapper;
77+88+ mkValue = v:
99+ if isList v then "\"${concatMapStringsSep " " (escape [ "\\" " " ]) v}\""
1010+ else if v == true then "yes"
1111+ else if v == false then "no"
1212+ else if isString v then "\"${v}\""
1313+ else builtins.toJSON v;
1414+1515+ mkKeyValue = k: v: "${k}=${mkValue v}";
1616+1717+ # "it's recommended to always specify the filesystem type" -- man snapper-configs
1818+ defaultOf = k: if k == "FSTYPE" then null else configOptions.${k}.default or null;
1919+2020+ safeStr = types.strMatching "[^\n\"]*" // {
2121+ description = "string without line breaks or quotes";
2222+ descriptionClass = "conjunction";
2323+ };
2424+2525+ configOptions = {
2626+ SUBVOLUME = mkOption {
2727+ type = types.path;
2828+ description = lib.mdDoc ''
2929+ Path of the subvolume or mount point.
3030+ This path is a subvolume and has to contain a subvolume named
3131+ .snapshots.
3232+ See also man:snapper(8) section PERMISSIONS.
3333+ '';
3434+ };
3535+3636+ FSTYPE = mkOption {
3737+ type = types.enum [ "btrfs" ];
3838+ default = "btrfs";
3939+ description = lib.mdDoc ''
4040+ Filesystem type. Only btrfs is stable and tested.
4141+ '';
4242+ };
4343+4444+ ALLOW_GROUPS = mkOption {
4545+ type = types.listOf safeStr;
4646+ default = [];
4747+ description = lib.mdDoc ''
4848+ List of groups allowed to operate with the config.
4949+5050+ Also see the PERMISSIONS section in man:snapper(8).
5151+ '';
5252+ };
5353+5454+ ALLOW_USERS = mkOption {
5555+ type = types.listOf safeStr;
5656+ default = [];
5757+ example = [ "alice" ];
5858+ description = lib.mdDoc ''
5959+ List of users allowed to operate with the config. "root" is always
6060+ implicitly included.
6161+6262+ Also see the PERMISSIONS section in man:snapper(8).
6363+ '';
6464+ };
6565+6666+ TIMELINE_CLEANUP = mkOption {
6767+ type = types.bool;
6868+ default = false;
6969+ description = lib.mdDoc ''
7070+ Defines whether the timeline cleanup algorithm should be run for the config.
7171+ '';
7272+ };
7373+7474+ TIMELINE_CREATE = mkOption {
7575+ type = types.bool;
7676+ default = false;
7777+ description = lib.mdDoc ''
7878+ Defines whether hourly snapshots should be created.
7979+ '';
8080+ };
8181+ };
782in
883984{
···52127 example = literalExpression ''
53128 {
54129 home = {
5555- subvolume = "/home";
5656- extraConfig = '''
5757- ALLOW_USERS="alice"
5858- TIMELINE_CREATE=yes
5959- TIMELINE_CLEANUP=yes
6060- ''';
130130+ SUBVOLUME = "/home";
131131+ ALLOW_USERS = [ "alice" ];
132132+ TIMELINE_CREATE = true;
133133+ TIMELINE_CLEANUP = true;
61134 };
62135 }
63136 '';
6413765138 description = lib.mdDoc ''
6666- Subvolume configuration
139139+ Subvolume configuration. Any option mentioned in man:snapper-configs(5)
140140+ is valid here, even if NixOS doesn't document it.
67141 '';
6814269143 type = types.attrsOf (types.submodule {
7070- options = {
7171- subvolume = mkOption {
7272- type = types.path;
7373- description = lib.mdDoc ''
7474- Path of the subvolume or mount point.
7575- This path is a subvolume and has to contain a subvolume named
7676- .snapshots.
7777- See also man:snapper(8) section PERMISSIONS.
7878- '';
7979- };
144144+ freeformType = types.attrsOf (types.oneOf [ (types.listOf safeStr) types.bool safeStr types.number ]);
801458181- fstype = mkOption {
8282- type = types.enum [ "btrfs" ];
8383- default = "btrfs";
8484- description = lib.mdDoc ''
8585- Filesystem type. Only btrfs is stable and tested.
8686- '';
8787- };
8888-8989- extraConfig = mkOption {
9090- type = types.lines;
9191- default = "";
9292- description = lib.mdDoc ''
9393- Additional configuration next to SUBVOLUME and FSTYPE.
9494- See man:snapper-configs(5).
9595- '';
9696- };
9797- };
146146+ options = configOptions;
98147 });
99148 };
100149 };
···117166118167 }
119168 // (mapAttrs' (name: subvolume: nameValuePair "snapper/configs/${name}" ({
120120- text = ''
121121- ${subvolume.extraConfig}
122122- FSTYPE="${subvolume.fstype}"
123123- SUBVOLUME="${subvolume.subvolume}"
124124- '';
169169+ text = lib.generators.toKeyValue { inherit mkKeyValue; } (filterAttrs (k: v: v != defaultOf k) subvolume);
125170 })) cfg.configs)
126171 // (lib.optionalAttrs (cfg.filters != null) {
127172 "snapper/filters/default.txt".text = cfg.filters;
···181226 unitConfig.ConditionPathExists = "/etc/snapper/configs/root";
182227 };
183228229229+ assertions =
230230+ concatMap
231231+ (name:
232232+ let
233233+ sub = cfg.configs.${name};
234234+ in
235235+ [ { assertion = !(sub ? extraConfig);
236236+ message = ''
237237+ The option definition `services.snapper.configs.${name}.extraConfig' no longer has any effect; please remove it.
238238+ The contents of this option should be migrated to attributes on `services.snapper.configs.${name}'.
239239+ '';
240240+ }
241241+ ] ++
242242+ map
243243+ (attr: {
244244+ assertion = !(hasAttr attr sub);
245245+ message = ''
246246+ The option definition `services.snapper.configs.${name}.${attr}' has been renamed to `services.snapper.configs.${name}.${toUpper attr}'.
247247+ '';
248248+ })
249249+ [ "fstype" "subvolume" ]
250250+ )
251251+ (attrNames cfg.configs);
184252 });
185253}