mirror of
https://github.com/nix-community/home-manager.git
synced 2025-11-08 19:46:05 +01:00
Some files don't need nesting and can be root level again to reduce conflicts with other PRs. Signed-off-by: Austin Horstman <khaneliman12@gmail.com>
334 lines
9.7 KiB
Nix
334 lines
9.7 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
let
|
|
inherit (lib) literalExpression mkOption types;
|
|
|
|
cfg = config.programs.borgmatic;
|
|
|
|
yamlFormat = pkgs.formats.yaml { };
|
|
|
|
mkNullableOption =
|
|
args:
|
|
lib.mkOption (
|
|
args
|
|
// {
|
|
type = lib.types.nullOr args.type;
|
|
default = null;
|
|
}
|
|
);
|
|
|
|
cleanRepositories =
|
|
repos:
|
|
map (
|
|
repo:
|
|
if builtins.isString repo then
|
|
{
|
|
path = repo;
|
|
}
|
|
else
|
|
removeNullValues repo
|
|
) repos;
|
|
|
|
mkRetentionOption =
|
|
frequency:
|
|
mkNullableOption {
|
|
type = types.int;
|
|
description = "Number of ${frequency} archives to keep. Use -1 for no limit.";
|
|
example = 3;
|
|
};
|
|
|
|
extraConfigOption = mkOption {
|
|
type = yamlFormat.type;
|
|
default = { };
|
|
description = "Extra settings.";
|
|
};
|
|
|
|
repositoryOption = types.submodule {
|
|
options = {
|
|
path = mkOption {
|
|
type = types.str;
|
|
example = "ssh://myuser@myrepo.myserver.com/./repo";
|
|
description = "Path of the repository.";
|
|
};
|
|
|
|
label = mkOption {
|
|
type = types.nullOr types.str;
|
|
default = null;
|
|
example = "remote";
|
|
description = ''
|
|
Short text describing the repository. Can be used with the
|
|
`--repository` flag to select a repository.
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
|
|
consistencyCheckModule = types.submodule {
|
|
options = {
|
|
name = mkOption {
|
|
type = types.enum [
|
|
"repository"
|
|
"archives"
|
|
"data"
|
|
"extract"
|
|
];
|
|
description = "Name of consistency check to run.";
|
|
example = "repository";
|
|
};
|
|
|
|
frequency = mkNullableOption {
|
|
type = types.strMatching "([[:digit:]]+ .*)|always";
|
|
description = "Frequency of this type of check";
|
|
example = "2 weeks";
|
|
};
|
|
};
|
|
};
|
|
|
|
configModule = types.submodule (
|
|
{ config, ... }:
|
|
{
|
|
config.location.extraConfig.exclude_from = lib.mkIf config.location.excludeHomeManagerSymlinks (
|
|
lib.mkAfter [ (toString hmExcludeFile) ]
|
|
);
|
|
options = {
|
|
location = {
|
|
sourceDirectories = mkNullableOption {
|
|
type = types.listOf types.str;
|
|
default = null;
|
|
description = ''
|
|
Directories to backup.
|
|
|
|
Mutually exclusive with [](#opt-programs.borgmatic.backups._name_.location.patterns).
|
|
'';
|
|
example = literalExpression "[config.home.homeDirectory]";
|
|
};
|
|
|
|
patterns = mkNullableOption {
|
|
type = types.listOf types.str;
|
|
default = null;
|
|
description = ''
|
|
Patterns to include/exclude.
|
|
|
|
See the output of `borg help patterns` for the syntax. Pattern paths
|
|
are relative to `/` even when a different recursion root is set.
|
|
|
|
Mutually exclusive with [](#opt-programs.borgmatic.backups._name_.location.sourceDirectories).
|
|
'';
|
|
example = literalExpression ''
|
|
[
|
|
"R /home/user"
|
|
"- home/user/.cache"
|
|
"- home/user/Downloads"
|
|
"+ home/user/Videos/Important Video"
|
|
"- home/user/Videos"
|
|
]
|
|
'';
|
|
};
|
|
|
|
repositories = mkOption {
|
|
type = types.listOf (types.either types.str repositoryOption);
|
|
apply = cleanRepositories;
|
|
example = literalExpression ''
|
|
[
|
|
{
|
|
"path" = "ssh://myuser@myrepo.myserver.com/./repo";
|
|
"label" = "server";
|
|
}
|
|
{
|
|
"path" = "/var/lib/backups/local.borg";
|
|
"label" = "local";
|
|
}
|
|
]
|
|
'';
|
|
description = ''
|
|
List of local or remote repositories with paths and optional labels.
|
|
'';
|
|
};
|
|
|
|
excludeHomeManagerSymlinks = mkOption {
|
|
type = types.bool;
|
|
description = ''
|
|
Whether to exclude Home Manager generated symbolic links from
|
|
the backups. This facilitates restoring the whole home
|
|
directory when the Nix store doesn't contain the latest
|
|
Home Manager generation.
|
|
'';
|
|
default = false;
|
|
example = true;
|
|
};
|
|
|
|
extraConfig = extraConfigOption;
|
|
};
|
|
|
|
storage = {
|
|
encryptionPasscommand = mkNullableOption {
|
|
type = types.str;
|
|
description = "Command writing the passphrase to standard output.";
|
|
example = literalExpression ''"''${pkgs.password-store}/bin/pass borg-repo"'';
|
|
};
|
|
extraConfig = extraConfigOption;
|
|
};
|
|
|
|
retention = {
|
|
keepWithin = mkNullableOption {
|
|
type = types.strMatching "[[:digit:]]+[Hdwmy]";
|
|
description = "Keep all archives within this time interval.";
|
|
example = "2d";
|
|
};
|
|
|
|
keepSecondly = mkRetentionOption "secondly";
|
|
keepMinutely = mkRetentionOption "minutely";
|
|
keepHourly = mkRetentionOption "hourly";
|
|
keepDaily = mkRetentionOption "daily";
|
|
keepWeekly = mkRetentionOption "weekly";
|
|
keepMonthly = mkRetentionOption "monthly";
|
|
keepYearly = mkRetentionOption "yearly";
|
|
|
|
extraConfig = extraConfigOption;
|
|
};
|
|
|
|
consistency = {
|
|
checks = mkOption {
|
|
type = types.listOf consistencyCheckModule;
|
|
default = [ ];
|
|
description = "Consistency checks to run";
|
|
example = literalExpression ''
|
|
[
|
|
{
|
|
name = "repository";
|
|
frequency = "2 weeks";
|
|
}
|
|
{
|
|
name = "archives";
|
|
frequency = "4 weeks";
|
|
}
|
|
{
|
|
name = "data";
|
|
frequency = "6 weeks";
|
|
}
|
|
{
|
|
name = "extract";
|
|
frequency = "6 weeks";
|
|
}
|
|
];
|
|
'';
|
|
};
|
|
|
|
extraConfig = extraConfigOption;
|
|
};
|
|
|
|
output = {
|
|
extraConfig = extraConfigOption;
|
|
};
|
|
|
|
hooks = {
|
|
extraConfig = extraConfigOption;
|
|
};
|
|
};
|
|
}
|
|
);
|
|
|
|
removeNullValues = attrSet: lib.filterAttrs (key: value: value != null) attrSet;
|
|
|
|
hmFiles = builtins.attrValues config.home.file;
|
|
hmSymlinks = (lib.filter (file: !file.recursive) hmFiles);
|
|
hmExcludePattern = file: ''
|
|
${config.home.homeDirectory}/${file.target}
|
|
'';
|
|
hmExcludePatterns = lib.concatMapStrings hmExcludePattern hmSymlinks;
|
|
hmExcludeFile = pkgs.writeText "hm-symlinks.txt" hmExcludePatterns;
|
|
|
|
writeConfig =
|
|
config:
|
|
lib.generators.toYAML { } (
|
|
removeNullValues (
|
|
{
|
|
source_directories = config.location.sourceDirectories;
|
|
patterns = config.location.patterns;
|
|
repositories = config.location.repositories;
|
|
encryption_passcommand = config.storage.encryptionPasscommand;
|
|
keep_within = config.retention.keepWithin;
|
|
keep_secondly = config.retention.keepSecondly;
|
|
keep_minutely = config.retention.keepMinutely;
|
|
keep_hourly = config.retention.keepHourly;
|
|
keep_daily = config.retention.keepDaily;
|
|
keep_weekly = config.retention.keepWeekly;
|
|
keep_monthly = config.retention.keepMonthly;
|
|
keep_yearly = config.retention.keepYearly;
|
|
checks = config.consistency.checks;
|
|
}
|
|
// config.location.extraConfig
|
|
// config.storage.extraConfig
|
|
// config.retention.extraConfig
|
|
// config.consistency.extraConfig
|
|
// config.output.extraConfig
|
|
// config.hooks.extraConfig
|
|
)
|
|
);
|
|
in
|
|
{
|
|
meta.maintainers = [ lib.maintainers.DamienCassou ];
|
|
|
|
options = {
|
|
programs.borgmatic = {
|
|
enable = lib.mkEnableOption "Borgmatic";
|
|
|
|
package = lib.mkPackageOption pkgs "borgmatic" { nullable = true; };
|
|
|
|
backups = mkOption {
|
|
type = types.attrsOf configModule;
|
|
description = ''
|
|
Borgmatic allows for several named backup configurations,
|
|
each with its own source directories and repositories.
|
|
'';
|
|
example = literalExpression ''
|
|
{
|
|
personal = {
|
|
location = {
|
|
sourceDirectories = [ "/home/me/personal" ];
|
|
repositories = [ "ssh://myuser@myserver.com/./personal-repo" ];
|
|
};
|
|
};
|
|
work = {
|
|
location = {
|
|
sourceDirectories = [ "/home/me/work" ];
|
|
repositories = [ "ssh://myuser@myserver.com/./work-repo" ];
|
|
};
|
|
};
|
|
};
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
assertions =
|
|
(lib.mapAttrsToList (backup: opts: {
|
|
assertion = opts.location.sourceDirectories == null || opts.location.patterns == null;
|
|
message = ''
|
|
Borgmatic backup configuration "${backup}" cannot specify both 'location.sourceDirectories' and 'location.patterns'.
|
|
'';
|
|
}) cfg.backups)
|
|
++ (lib.mapAttrsToList (backup: opts: {
|
|
assertion = !(opts.location.sourceDirectories == null && opts.location.patterns == null);
|
|
message = ''
|
|
Borgmatic backup configuration "${backup}" must specify one of 'location.sourceDirectories' or 'location.patterns'.
|
|
'';
|
|
}) cfg.backups);
|
|
|
|
xdg.configFile =
|
|
with lib.attrsets;
|
|
mapAttrs' (
|
|
configName: config:
|
|
nameValuePair ("borgmatic.d/" + configName + ".yaml") {
|
|
text = writeConfig config;
|
|
}
|
|
) cfg.backups;
|
|
|
|
home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];
|
|
};
|
|
}
|