{ config, lib, pkgs, ... }: with lib; let cfg = config.services.borgbackup; targetOptions = { options = { repo = mkOption { type = types.str; }; paths = mkOption { type = types.listOf types.path; default = []; }; interval = mkOption { type = types.str; default = "6h"; }; lock = mkOption { type = types.nullOr types.str; default = "backup"; }; network = mkOption { type = types.bool; default = true; }; }; }; in { options = { services.borgbackup = { snapshots = mkOption { type = types.nullOr (types.enum ["btrfs"]); default = null; }; targets = mkOption { type = types.attrsOf (types.submodule targetOptions); default = {}; }; prefix = mkOption { type = types.str; }; }; }; config = mkIf (any (t: t.paths != []) (attrValues cfg.targets)) { services.btrfs-snapshots.enable = mkIf (cfg.snapshots == "btrfs") true; systemd.timers = listToAttrs (map (target: path: nameValuePair "borgbackup-${target}@${path}" { wantedBy = [ "timers.target" ]; timerConfig = { Persistent = true; OnUnitInactiveSec = "6h"; }; }) (flatten (mapAttrsToList (target: tCfg: map (path: { inherit target path; }) tCfg.paths) cfg.targets))); systemd.services = map (target: nameValuePair "borgbackup-${target}@" (let deps = flatten [ optional (cfg.snapshots == "btrfs") "btrfs-snapshot@%i.service" optional network "network-online.target" ]; in { bindsTo = deps; after = deps; path = with pkgs; [borgbackup]; script = '' borg create \ --stats \ --list \ --filter 'AME' \ --exclude-caches \ --keep-exclude-tags \ --patterns-from .backup \ --one-file-system \ --compression auto,lzma \ ${target}::${prefix}$1-{utcnow} ''; scriptArgs = "%i"; serviceConfig = { Type = "oneshot"; WorkingDirectory = if (cfg.snapshots == null) then "%p" else "/mnt/snapshot-%i"; Nice = 15; IOSchedulingClass = 2; IOSchedulingPriority = 7; SuccessExitStatus = [1 2]; }; })) (attrNames cfg.targets); }; }