Files
Nomarchy/pkgs/nomarchy-lifecycle/default.nix
Bernardo Magri 639f553cb7
Some checks failed
Check / eval (push) Has been cancelled
feat(lifecycle): plain-language generation diffs (#82)
nomarchy-what-changed wraps nvd into "N added, M removed, K updated"
summaries. nomarchy-rebuild / nomarchy-home print full nvd and toast
the one-liner; System › What changed? offers toast + floating report.
checks.what-changed fixtures nvd via NOMARCHY_NVD.

Verified: V2 — flake check --no-build; checks.what-changed green;
local smoke on real HM generations.
2026-07-11 10:26:57 +01:00

172 lines
6.0 KiB
Nix

# Day-to-day lifecycle CLIs for a Nomarchy machine flake (~/.nomarchy).
# Installed on both NixOS (systemPackages) and Home Manager so a home
# switch can refresh them without waiting for a full system rebuild —
# otherwise a broken nomarchy-pull can never update itself.
{ lib, writeShellScriptBin, nvd, jq, symlinkJoin, nomarchy-what-changed }:
let
# Shared preamble: refuse root, resolve flake path.
preamble = name: ''
set -euo pipefail
if [ "$(id -u)" -eq 0 ]; then
echo "${name}: run as your normal user" >&2
exit 1
fi
flake="''${NOMARCHY_PATH:-$HOME/.nomarchy}"
'';
nomarchy-pull = writeShellScriptBin "nomarchy-pull" ''
${preamble "nomarchy-pull"}
if [ ! -e "$flake/flake.nix" ]; then
echo "nomarchy-pull: no flake.nix at $flake" >&2
echo " Set NOMARCHY_PATH or put your machine flake in ~/.nomarchy." >&2
exit 1
fi
# Optional: pull *your* machine config only if this checkout tracks a
# remote. Distro updates come from the nomarchy flake *input* below
# many installs have no upstream on ~/.nomarchy (local auto-commits).
if [ -d "$flake/.git" ] \
&& git -C "$flake" rev-parse --abbrev-ref '@{u}' >/dev/null 2>&1; then
echo "nomarchy-pull: git pull --ff-only (machine flake tracks upstream)"
git -C "$flake" pull --ff-only
elif [ -d "$flake/.git" ]; then
echo "nomarchy-pull: machine flake has no upstream branch skipping git pull"
echo " (normal for a local-only ~/.nomarchy; distro updates use flake inputs)"
fi
echo "nomarchy-pull: nix flake update in $flake"
nix flake update --flake "$flake"
nom=$(nix flake metadata "$flake" --json 2>/dev/null \
| ${jq}/bin/jq -r '
.locks.nodes.nomarchy.locked
| if . == null then empty
elif .rev then "nomarchy @ \(.rev[0:12])"
else empty end
' 2>/dev/null || true)
[ -n "''${nom:-}" ] && echo "nomarchy-pull: $nom"
echo "nomarchy-pull: done next: nomarchy-rebuild then nomarchy-home"
'';
nomarchy-rebuild = writeShellScriptBin "nomarchy-rebuild" ''
${preamble "nomarchy-rebuild"}
if [ ! -e "$flake/flake.nix" ]; then
echo "nomarchy-rebuild: no flake.nix at $flake" >&2
exit 1
fi
before=$(readlink -f /run/current-system)
log=$(mktemp)
trap 'rm -f "$log"' EXIT
set +e
if command -v nixos-rebuild-snap >/dev/null 2>&1; then
sudo env NOMARCHY_PATH="$flake" nixos-rebuild-snap "$@" 2>&1 | tee "$log"
else
sudo nixos-rebuild switch --flake "$flake#default" "$@" 2>&1 | tee "$log"
fi
rc=''${PIPESTATUS[0]}
set -e
if [ "$rc" -ne 0 ]; then
echo
echo "nomarchy-rebuild: FAILED (exit $rc). Last lines:"
tail -n 40 "$log" || true
echo
echo "Diagnose: nomarchy-doctor"
echo "Recovery: docs/RECOVERY.md (boot menu generations / snapper)"
exit "$rc"
fi
after=$(readlink -f /run/current-system)
if [ "$before" = "$after" ]; then
echo "nomarchy-rebuild: no changes the system is identical."
else
echo "nomarchy-rebuild: what changed:"
${nvd}/bin/nvd diff "$before" "$after" || true
# One-line toast for the session (full report already on the terminal).
if command -v notify-send >/dev/null 2>&1 \
&& command -v nomarchy-what-changed >/dev/null 2>&1; then
body=$(nomarchy-what-changed --summary --diff "$before" "$after" 2>/dev/null \
| sed 's/^Diff: //' || true)
[ -n "''${body:-}" ] && notify-send -a Nomarchy "System rebuild" "$body" || true
fi
fi
'';
nomarchy-home = writeShellScriptBin "nomarchy-home" ''
${preamble "nomarchy-home"}
if [ ! -e "$flake/flake.nix" ]; then
echo "nomarchy-home: no flake.nix at $flake" >&2
exit 1
fi
# Snapshot the active HM generation before the switch so we can nvd it.
hm_before=""
for d in \
"''${XDG_STATE_HOME:-$HOME/.local/state}/nix/profiles" \
"/nix/var/nix/profiles/per-user/$(id -un)"; do
if [ -L "$d/home-manager" ]; then
hm_before=$(readlink -f "$d/home-manager" 2>/dev/null || true)
break
fi
done
log=$(mktemp)
trap 'rm -f "$log"' EXIT
set +e
home-manager switch --flake "$flake" "$@" 2>&1 | tee "$log"
rc=''${PIPESTATUS[0]}
set -e
if [ "$rc" -ne 0 ]; then
echo
echo "nomarchy-home: FAILED (exit $rc). Last lines:"
tail -n 40 "$log" || true
echo
echo "Diagnose: nomarchy-doctor"
echo "Recovery: home-manager generations (or docs/RECOVERY.md)"
exit "$rc"
fi
hm_after=""
for d in \
"''${XDG_STATE_HOME:-$HOME/.local/state}/nix/profiles" \
"/nix/var/nix/profiles/per-user/$(id -un)"; do
if [ -L "$d/home-manager" ]; then
hm_after=$(readlink -f "$d/home-manager" 2>/dev/null || true)
break
fi
done
if [ -n "$hm_before" ] && [ -n "$hm_after" ] && [ "$hm_before" != "$hm_after" ]; then
echo "nomarchy-home: what changed:"
${nvd}/bin/nvd diff "$hm_before" "$hm_after" || true
if command -v notify-send >/dev/null 2>&1 \
&& command -v nomarchy-what-changed >/dev/null 2>&1; then
body=$(nomarchy-what-changed --summary --diff "$hm_before" "$hm_after" 2>/dev/null \
| sed 's/^Diff: //' || true)
[ -n "''${body:-}" ] && notify-send -a Nomarchy "Desktop updated" "$body" || true
fi
else
echo "nomarchy-home: desktop applied."
fi
'';
# Legacy aliases
sys-update = writeShellScriptBin "sys-update" ''
nomarchy-pull && nomarchy-rebuild "$@"
'';
sys-rebuild = writeShellScriptBin "sys-rebuild" ''
exec nomarchy-rebuild "$@"
'';
home-update = writeShellScriptBin "home-update" ''
exec nomarchy-home "$@"
'';
in
symlinkJoin {
name = "nomarchy-lifecycle";
paths = [
nomarchy-pull
nomarchy-rebuild
nomarchy-home
sys-update
sys-rebuild
home-update
nomarchy-what-changed
];
meta = {
description = "Nomarchy machine-flake lifecycle: pull, rebuild, home";
mainProgram = "nomarchy-pull";
};
}