The Shell section moves to 26, after Neovim, the runtimes and the agent CLIs. Everything that writes to .zshrc now happens there and only there: the starship init, the PATH for the agent CLIs (moved out of that section), the aliases, and the editor. That ordering is what the editor choice needs — it offers whichever of nvim, vim and nano are actually present, so it has to run after Neovim is installed rather than naming an editor that is not there. Which was the original's mistake in the other direction: it set core.editor to nvim four sections before installing it. The default editor is the setting git's core.editor was deliberately left out in favour of. EDITOR, VISUAL and SUDO_EDITOR go in the account's shell, and the Debian `editor` alternative is set too — an account's shell config cannot reach root or sudoedit, and those are exactly the cases where the wrong editor is most annoying. Recorded a limitation of append_once while cleaning up after it: renaming a marker orphans the block that used the old name, and changing a block's content does nothing because the marker is still found. Both need the old block removed by hand. This run left exactly that — a `local-bin` block superseded by `agent-clis` — in the dev box's .zshrc, now removed. UFW is deliberately still unported and will be last, for the reason the original gave: it is the one step that can cut the connection the run is happening over. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
128 lines
4.4 KiB
Bash
128 lines
4.4 KiB
Bash
#!/bin/bash
|
|
# =============================================================================
|
|
# machine-setup — writing files into somebody's home
|
|
# =============================================================================
|
|
#
|
|
# Definitions only, like the other lib/ files.
|
|
#
|
|
# ── The rule ──
|
|
#
|
|
# A setup script may create a config file. It may not silently replace one the
|
|
# user wrote. The original did the second: `cp .tmux.conf $USER_HOME/` on every
|
|
# run, over whatever was there, and five separate `cat >>` into .zshrc with no
|
|
# guard — so a second pass duplicated the starship init, the nvim PATH, bun, deno
|
|
# and the aliases.
|
|
#
|
|
# Both of those are the same mistake in different shapes: writing without looking
|
|
# first. The two helpers here are the two safe shapes.
|
|
|
|
[[ -n "${MACHINE_SETUP_FILES_LOADED:-}" ]] && return 0
|
|
MACHINE_SETUP_FILES_LOADED=1
|
|
|
|
# Put a config file in place, asking before it replaces one the user has.
|
|
#
|
|
# Three outcomes, and the caller can tell them apart by the return code:
|
|
#
|
|
# 0 installed — there was nothing there, or the user chose to replace
|
|
# 1 identical — already exactly this, nothing done
|
|
# 2 kept — the user chose to keep theirs
|
|
#
|
|
# When the file exists and differs, this ASKS rather than deciding. Silently
|
|
# keeping theirs is safe but unhelpful — they never learn that a newer version
|
|
# exists — and silently replacing it is how a setup script eats somebody's
|
|
#configuration. So: keep, replace, or show the difference first, and a replaced file is
|
|
# always kept beside the new one.
|
|
#
|
|
# NOTE for callers: 1 and 2 are outcomes, not failures — but they are still
|
|
# non-zero, so calling this as a plain command under `set -e` ends the script
|
|
# before the result can be read. Always capture it:
|
|
#
|
|
# install_config "$src" "$dest" "$user" && rc=0 || rc=$?
|
|
install_config() {
|
|
local src="$1" dest="$2" owner="$3" answer
|
|
|
|
if [[ ! -f "$dest" ]]; then
|
|
install -D -m 0644 -o "$owner" -g "$owner" "$src" "$dest"
|
|
return 0
|
|
fi
|
|
|
|
cmp -s "$src" "$dest" && return 1
|
|
|
|
echo ""
|
|
warn "${dest} already exists here, and differs from the one this script ships."
|
|
|
|
# Never replace a file the user has without being told to. An unattended run
|
|
# answers "keep", because the alternative is destroying configuration nobody
|
|
# was present to defend.
|
|
if [[ "${ASSUME_YES:-}" == "1" ]] || [[ ! -t 0 ]]; then
|
|
echo " keeping yours (nothing was asked, so nothing is replaced)"
|
|
return 2
|
|
fi
|
|
|
|
while true; do
|
|
echo " [1] keep yours — nothing changes"
|
|
echo " [2] use ours — yours is kept as ${dest}.before-machine-setup"
|
|
echo " [3] show me the difference first"
|
|
echo ""
|
|
if ! read -rp " Which one? (1/2/3) [1]: " answer; then
|
|
echo ""
|
|
echo " keeping yours"
|
|
return 2
|
|
fi
|
|
case "${answer:-1}" in
|
|
1)
|
|
echo " keeping yours"
|
|
return 2
|
|
;;
|
|
2)
|
|
cp -a "$dest" "${dest}.before-machine-setup"
|
|
install -D -m 0644 -o "$owner" -g "$owner" "$src" "$dest"
|
|
ok "replaced — yours is at ${dest}.before-machine-setup"
|
|
return 0
|
|
;;
|
|
3)
|
|
echo ""
|
|
# yours on the left, ours on the right: - is what you would lose,
|
|
# + is what you would gain.
|
|
diff -u --label "yours: ${dest}" --label "ours: ${src}" "$dest" "$src" | page
|
|
echo ""
|
|
;;
|
|
*) warn "Pick 1, 2 or 3." ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# Append a block to a file exactly once.
|
|
#
|
|
# The block is wrapped in markers naming what it is, so a second run recognises
|
|
# its own work instead of adding it again — and so a human reading the file can
|
|
# see which lines came from here and delete them as a unit.
|
|
#
|
|
# append_once ~/.zshrc bun <<'EOF'
|
|
# export PATH="$HOME/.bun/bin:$PATH"
|
|
# EOF
|
|
#
|
|
# Returns 0 if it wrote, 1 if the block was already there.
|
|
#
|
|
# One limitation, and it bites the author rather than the user: RENAMING a marker
|
|
# orphans the block that used the old name. append_once only recognises the name
|
|
# it is given, so the previous block stays in the file doing whatever it did.
|
|
# Changing a block's CONTENT has the same shape — the marker is found, so the new
|
|
# content is never written. Both need the old block removed by hand.
|
|
append_once() {
|
|
local file="$1" name="$2"
|
|
local begin="# >>> machine-setup: ${name} >>>"
|
|
local end="# <<< machine-setup: ${name} <<<"
|
|
|
|
if [[ -f "$file" ]] && grep -qF "$begin" "$file"; then
|
|
return 1
|
|
fi
|
|
|
|
{
|
|
echo ""
|
|
echo "$begin"
|
|
cat
|
|
echo "$end"
|
|
} >>"$file"
|
|
}
|