feat(snapshots): desktop browse/restore + snapshot /home by default

Surface snapper snapshots from the desktop: `nomarchy-menu snapshot` (in the
SUPER+M picker, self-gated) launches btrfs-assistant, the polkit-aware
browse/diff/restore/rollback UI -- safer than a fat-fingerable rofi rollback
for a destructive root-only op. Shipped system-side gated on
nomarchy.system.snapper.

Also snapshot /home by default (hourly 5 / daily 7 / weekly 4) when it's its
own BTRFS subvolume -- the installer only set up snapper for /. A boot
oneshot creates the required /home/.snapshots subvolume if missing, so
already-installed machines get it too (no disko change).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Bernardo Magri
2026-06-15 17:14:05 +01:00
parent 5c83b52727
commit 0897391cfb
3 changed files with 60 additions and 7 deletions

View File

@@ -172,6 +172,14 @@ let
&& notify-send "Do Not Disturb off" "Notifications resumed."
exit 0 ;;
snapshot)
# btrfs-assistant: snapshot browse / diff / restore / rollback over
# snapper, elevating via polkit. Shipped system-side with
# nomarchy.system.snapper; self-gate so the entry no-ops elsewhere.
command -v btrfs-assistant >/dev/null 2>&1 \
|| { notify-send "Snapshots" "btrfs-assistant isn't installed (BTRFS snapshots off?)."; exit 0; }
exec btrfs-assistant ;;
"")
entries=(
"󰀻 Apps"
@@ -188,6 +196,8 @@ let
"󰭹 Ask Claude"
"󰂛 Do Not Disturb"
)
# Snapshots only when btrfs-assistant is installed (BTRFS + snapper).
command -v btrfs-assistant >/dev/null 2>&1 && entries+=("󰋚 Snapshots")
# Power-profile picker only when this is a laptop (battery present)
# running power-profiles-daemon matches the Waybar indicator's
# self-gating; desktops and the TLP backend don't show it.
@@ -211,12 +221,13 @@ let
*Keybindings*) exec "$0" keybinds ;;
*Ask*) exec "$0" ask ;;
*"Do Not Disturb"*) exec "$0" dnd ;;
*Snapshots*) exec "$0" snapshot ;;
*"Power profile"*) exec "$0" power-profile ;;
*Power*) exec "$0" power ;;
esac ;;
*)
echo "usage: nomarchy-menu [power|power-profile|theme|clipboard|calc|files|emoji|web|network|bluetooth|capture|keybinds|ask|dnd]" >&2
echo "usage: nomarchy-menu [power|power-profile|theme|clipboard|calc|files|emoji|web|network|bluetooth|capture|keybinds|ask|dnd|snapshot]" >&2
exit 64 ;;
esac
'';

View File

@@ -185,7 +185,7 @@ in
# is a clean no-op rather than a failing timer.
services.snapper.configs = lib.mkIf
(cfg.snapper.enable && (config.fileSystems."/".fsType or "") == "btrfs")
{
({
root = {
SUBVOLUME = "/";
TIMELINE_CREATE = true;
@@ -196,6 +196,39 @@ in
TIMELINE_LIMIT_MONTHLY = "0";
TIMELINE_LIMIT_YEARLY = "0";
};
}
# /home is user data — snapshot it too when it's its own BTRFS subvolume
# (the installer's @home). Keep the recent hourlies for oops-recovery
# plus dailies, and a month of weeklies; "at least daily" by default.
// lib.optionalAttrs ((config.fileSystems."/home".fsType or "") == "btrfs") {
home = {
SUBVOLUME = "/home";
TIMELINE_CREATE = true;
TIMELINE_CLEANUP = true;
TIMELINE_LIMIT_HOURLY = "5";
TIMELINE_LIMIT_DAILY = "7";
TIMELINE_LIMIT_WEEKLY = "4";
TIMELINE_LIMIT_MONTHLY = "0";
TIMELINE_LIMIT_YEARLY = "0";
};
});
# snapper needs a `.snapshots` subvolume inside each tracked subvolume.
# The installer made one for / (@snapshots → /.snapshots) but not /home,
# so create a nested one there if missing (idempotent via the condition;
# excluded from /home snapshots since BTRFS snapshots are non-recursive).
# Runs at boot so it also fixes already-installed machines — no disko
# change needed.
systemd.services.nomarchy-home-snapshots-subvol = lib.mkIf
(cfg.snapper.enable && (config.fileSystems."/home".fsType or "") == "btrfs") {
description = "Create /home/.snapshots for snapper if missing";
wantedBy = [ "multi-user.target" ];
before = [ "snapper-timeline.service" "snapper-cleanup.service" ];
unitConfig.ConditionPathExists = "!/home/.snapshots";
serviceConfig = {
Type = "oneshot";
ExecStart = "${pkgs.btrfs-progs}/bin/btrfs subvolume create /home/.snapshots";
};
};
# ── Fonts ────────────────────────────────────────────────────────
@@ -285,7 +318,10 @@ in
--cleanup-algorithm number
echo "Rebuilding..."
nixos-rebuild switch --flake /etc/nixos#default "$@"
'');
'')
# The desktop snapshot manager (browse / diff / restore / rollback over
# snapper, elevating via polkit) — what `nomarchy-menu snapshot` launches.
++ lib.optional cfg.snapper.enable pkgs.btrfs-assistant;
# Don't let boot entries fill the ESP over the years.
boot.loader.systemd-boot.configurationLimit = lib.mkDefault 10;