Give an installed machine a way to catch up
./install only ever adds. It copies over /, links dotfiles, installs packages -- and has no way to say "remove that file", "disable that unit", "that symlink points nowhere now". So a machine set up months ago keeps whatever this repository has since decided was wrong, and the only thing that ever fixes it is somebody reading a commit message. With a curl installer in the README, that stopped being hypothetical. A migration is one script that performs one repair, exactly once, on the machines that need it. Named by the commit timestamp that authored it, so glob order is chronological without a sequence number two branches could both pick. Marked in ~/.local/state on success and only on success, so a repair that failed stays pending rather than being recorded as done and hidden forever. Ordered, and stopped at the first failure, because a later repair may assume an earlier one landed. A fresh install marks everything without running it, the way Migrations.qml stamps a pre-versioning settings file at its baseline. The first real one removes the dangling ~/.config/forge symlink left behind when the GNOME session was cut: link-dotfiles could link it but never unlink it. Verified both ways -- a no-op on a machine that never had it, an actual repair on one that did. Root work goes through panama-sudo --reason so the password prompt names the repair, and the contract fails any migration reaching for bare sudo.
This commit is contained in:
Executable
+44
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Remove the dangling ~/.config/forge symlink left by the GNOME session cut.
|
||||
#
|
||||
# `forge` was in link-dotfiles' `dirs` array while the GNOME session was still
|
||||
# the fallback and Hyprland was being built beside it. Commit 47f29f9 deleted
|
||||
# config/dot/forge along with the rest of that hedge, but link-dotfiles has no
|
||||
# way to un-link what it once linked: a machine that ran the installer before
|
||||
# that commit still has ~/.config/forge pointing into the repository at a path
|
||||
# that no longer exists.
|
||||
#
|
||||
# Nothing reads it, so the cost is only that `ls ~/.config` shows a broken link
|
||||
# forever. That is exactly the kind of small permanent wrongness migrations
|
||||
# exist to clear.
|
||||
#
|
||||
# This is the shape every future "a dotfile directory was removed" repair takes:
|
||||
# check that the link is dangling AND points into Panama, then remove it. Both
|
||||
# halves matter -- a dangling link somebody else made is not ours to delete.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PANAMA_PATH="${PANAMA_PATH:-$HOME/.local/share/Panama}"
|
||||
|
||||
link="${XDG_CONFIG_HOME:-$HOME/.config}/forge"
|
||||
|
||||
# Not a symlink, or not there at all: already correct. Both are the common case
|
||||
# on a machine installed after the cut, and neither is a failure.
|
||||
[[ -L "$link" ]] || exit 0
|
||||
|
||||
# Still resolves? Then something else owns this path now and it is not ours to
|
||||
# remove.
|
||||
[[ -e "$link" ]] && exit 0
|
||||
|
||||
target="$(readlink "$link")"
|
||||
case "$target" in
|
||||
"$PANAMA_PATH"/*) ;;
|
||||
*)
|
||||
echo "Leaving $link alone: it points at $target, which is not Panama's."
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
rm -f "$link"
|
||||
echo "Removed the dangling $link"
|
||||
@@ -0,0 +1,2 @@
|
||||
# Migrations live here, one repair per file, named by the commit timestamp
|
||||
# that authored them. See bin/panama-migrate.
|
||||
Reference in New Issue
Block a user