133 lines
3.7 KiB
Nix
133 lines
3.7 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
let
|
|
cfg = config.impermanence.tools;
|
|
|
|
persistence = config.environment.persistence or { };
|
|
|
|
normalizePath = v:
|
|
if builtins.isString v then
|
|
v
|
|
else if v ? dirPath then
|
|
v.dirPath
|
|
else if v ? filePath then
|
|
v.filePath
|
|
else
|
|
null;
|
|
|
|
pathsFromList = f: xs: lib.filter (p: p != null) (map f xs);
|
|
|
|
userPersistencePaths = users:
|
|
lib.flatten (
|
|
lib.mapAttrsToList (
|
|
userName: userCfg:
|
|
let
|
|
home = (config.users.users.${userName} or { }).home or "/home/${userName}";
|
|
normalizeUserPath = v:
|
|
if builtins.isString v then
|
|
if lib.hasPrefix "/" v then v else "${home}/${v}"
|
|
else
|
|
normalizePath v;
|
|
in
|
|
(pathsFromList normalizeUserPath (userCfg.directories or [ ]))
|
|
++ (pathsFromList normalizeUserPath (userCfg.files or [ ]))
|
|
) users
|
|
);
|
|
|
|
ignorePaths =
|
|
lib.unique (
|
|
lib.filter (p: p != null && p != "" && p != "/") (
|
|
lib.flatten (
|
|
lib.mapAttrsToList (
|
|
persistRoot: persistCfg:
|
|
[ persistRoot ]
|
|
++ (pathsFromList normalizePath (persistCfg.directories or [ ]))
|
|
++ (pathsFromList normalizePath (persistCfg.files or [ ]))
|
|
++ (userPersistencePaths (persistCfg.users or { }))
|
|
) persistence
|
|
)
|
|
)
|
|
);
|
|
|
|
ignoreFile = pkgs.writeText "bcache-impermanence-ignore-paths" (
|
|
lib.concatStringsSep "\n" ignorePaths + "\n"
|
|
);
|
|
|
|
scriptFile = pkgs.writeText "bcache-impermanence.sh" (
|
|
builtins.readFile ./impermanence-tools.sh
|
|
);
|
|
|
|
bcacheImpermanenceBin = pkgs.writeShellScriptBin "bcache-impermanence" ''
|
|
export BCACHE_IMPERMANENCE_IGNORE_FILE="${ignoreFile}"
|
|
exec ${pkgs.bash}/bin/bash "${scriptFile}" "$@"
|
|
'';
|
|
in
|
|
{
|
|
options.impermanence.tools = {
|
|
# enable = lib.mkEnableOption "bcachefs impermanence tools (GC + CLI)";
|
|
|
|
snapshotRoot = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "/.snapshots/old_roots";
|
|
description = "Root directory containing old root snapshots.";
|
|
};
|
|
|
|
gc = {
|
|
enable = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = true;
|
|
description = "Enable garbage collection of old root snapshots.";
|
|
};
|
|
|
|
keepPerMonth = lib.mkOption {
|
|
type = lib.types.int;
|
|
default = 1;
|
|
description = "Keep at least this many snapshots per calendar month (latest ones).";
|
|
};
|
|
|
|
keepRecentWeeks = lib.mkOption {
|
|
type = lib.types.int;
|
|
default = 4;
|
|
description = "Keep at least one snapshot per ISO week within this many recent weeks.";
|
|
};
|
|
|
|
keepRecentCount = lib.mkOption {
|
|
type = lib.types.int;
|
|
default = 5;
|
|
description = "Always keep at least this many most recent snapshots overall.";
|
|
};
|
|
};
|
|
};
|
|
|
|
config = {
|
|
# config = lib.mkIf cfg.enable {
|
|
environment.systemPackages = [
|
|
bcacheImpermanenceBin
|
|
pkgs.coreutils
|
|
pkgs.findutils
|
|
pkgs.diffutils
|
|
pkgs.bcachefs-tools
|
|
pkgs.fzf
|
|
];
|
|
|
|
systemd.services."bcache-impermanence-gc" = lib.mkIf cfg.gc.enable {
|
|
description = "Garbage collect bcachefs impermanence snapshots";
|
|
wantedBy = [ "multi-user.target" ];
|
|
after = [ "multi-user.target" ];
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
};
|
|
script = ''
|
|
exec ${bcacheImpermanenceBin}/bin/bcache-impermanence gc \
|
|
--snapshot-root ${cfg.snapshotRoot} \
|
|
--keep-per-month ${toString cfg.gc.keepPerMonth} \
|
|
--keep-recent-weeks ${toString cfg.gc.keepRecentWeeks} \
|
|
--keep-recent-count ${toString cfg.gc.keepRecentCount}
|
|
'';
|
|
};
|
|
};
|
|
}
|