#!/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, unless the user has their own. # # Three outcomes, and the caller can tell them apart by the return code: # # 0 installed — there was nothing there # 1 identical — already exactly this, nothing done # 2 kept — theirs differs, left alone # # Converging when there is nothing to lose and keeping what the user wrote when # there is. The third case prints how to take ours, so the choice stays with # them. # # 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" if [[ -f "$dest" ]]; then if cmp -s "$src" "$dest"; then return 1 fi warn "kept your ${dest} — it differs from the one shipped here" echo " to take ours instead: cp ${src} ${dest}" return 2 fi install -D -m 0644 -o "$owner" -g "$owner" "$src" "$dest" return 0 } # 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. 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" }