nix-da/options/services/rsync-backup/module.nix

138 lines
3.5 KiB
Nix

{
config,
lib,
specialArgs,
...
}:
let
inherit (lib)
mkOption
concatLists
concatStringsSep
mkEnableOption
;
inherit (lib.types)
listOf
nonEmptyStr
enum
str
bool
;
inherit (lib.lists) optionals;
inherit (specialArgs) rootCfg;
in
{
options = {
exclude = mkOption {
type = listOf nonEmptyStr;
default = rootCfg.exclude;
};
followGitignore = mkOption {
type = bool;
default = rootCfg.followGitignore;
};
sources = mkOption {
type = listOf nonEmptyStr;
default = [ ]; # TODO: validate if at least 1 element
description = ''
A list of absolute paths to the files or folders that should get synchronized.
It isn't necessary to wrap them in escaped double quotation marks.
'';
};
target = {
location = mkOption {
type = nonEmptyStr;
description = ''
The target to where the data should be backed up.
If it is a directory, it will be created automatically by rsync.
'';
};
finalLocation = mkOption {
type = nonEmptyStr;
default =
if config.target.type == "local" then
config.target.location
else if config.target.type == "rsyncd" then
"rsync://${config.target.host}/${config.target.location}"
else
throw "Unable to create location.";
};
type = mkOption {
type = enum [
"local"
"rsyncd"
];
default = "local";
description = ''
Guesses if the given target is local or ssh, very rudimentary therefore it might be necessary to specify manually (or rewrite the logic).
'';
};
host = mkOption {
type = str;
default = "";
};
};
interval = mkOption {
type = nonEmptyStr;
default = "daily";
};
flags = mkOption {
type = listOf str;
default = [
"--archive"
"--verbose"
"--mkpath" # create destination's missing path components
"--safe-links" # ignore symlinks that point outside the tree
"--itemize-changes" # output a change-summary for all updates
];
};
flagsFinal = mkOption {
type = listOf str;
default = concatLists [
config.flags
(optionals config.incremental.enable [
"--delete"
"--backup-dir=\"${config.incremental.finalIncrementPath}\""
])
(optionals config.followGitignore [ "--filter=':- .gitignore'" ])
[ "--port=${toString rootCfg.port}" ]
(map (ex: "--exclude='${ex}'") config.exclude)
];
apply = concatStringsSep " ";
};
incremental = {
enable = mkEnableOption "incremental backups";
format = mkOption {
type = nonEmptyStr;
default = "%Y-%m-%d-%-H-%M-%S-$RANDOM";
description = ''
The increment folder name. Refer to `man date` for specifics about the format.
Omit the leading +.
'';
};
finalIncrementPath = mkOption {
type = nonEmptyStr;
default = "../increment/$(date +${config.incremental.format})/";
description = ''
The directory in which the changes will be stored, the .. at the start is necessary because it is relative to
the target and we append `backup` to the target.
-- cfg.location
| - backup/
| - increment/<increment format>
'';
};
};
};
}