Files
platform/scripts/setup/machine-setup/machine-setup.sh
T
pastilhasandClaude Opus 5 a5ef9f7662 report what a section actually installed, not what it was asked for
The summary claimed credit for everything in a section's list, including the
packages it had just decided to leave alone — so a run that installed nothing
still ended with "Command-line tools: lazydocker lazygit starship fastfetch".
The announce above it said "nothing, all present" in the same breath.

pkg_install and tools_install now record LAST_INSTALLED and LAST_KEPT, and
summarise_last turns those into one honest line:

  Core packages installed: btop tmux (17 already present)
  Command-line tools: already present, nothing installed

Verified all three shapes — everything present, nothing present, and mixed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 17:34:34 +00:00

172 lines
7.3 KiB
Bash
Executable File

#!/bin/bash
set -e
# =============================================================================
# machine-setup — provisioning for a fresh machine
#
# Brings a blank box up to a usable state: users, SSH, networking, firewall,
# Docker, shell and editor tooling, language runtimes.
#
# Run as root: sudo scripts/setup/machine-setup/machine-setup.sh
# =============================================================================
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROGRESS_FILE="$SCRIPT_DIR/.setup-progress"
# Shared state, output helpers, the step/resume machine and OS detection. Kept in
# lib/ so a step can eventually be read — or run — on its own without dragging the
# whole script in. Definitions only; nothing in there acts.
# shellcheck source=lib/base.sh
source "$SCRIPT_DIR/lib/base.sh"
# shellcheck source=lib/packages.sh
source "$SCRIPT_DIR/lib/packages.sh"
# shellcheck source=lib/tools.sh
source "$SCRIPT_DIR/lib/tools.sh"
# Trap errors with context. Installed here rather than in lib/base.sh, because
# that file is definitions only and a trap is a side effect on whoever sources it.
trap 'echo ""; echo -e "${RED}╔══════════════════════════════════════════════════╗${NC}"; echo -e "${RED}║ SETUP FAILED${NC}"; echo -e "${RED}║ Step: ${CURRENT_STEP:-unknown}${NC}"; echo -e "${RED}║ Line: $LINENO${NC}"; echo -e "${RED}║ Command: $BASH_COMMAND${NC}"; echo -e "${RED}╚══════════════════════════════════════════════════╝${NC}"' ERR
# =============================================================================
# 1. Pre-flight
# =============================================================================
echo ""
echo -e "${BOLD}╔══════════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}║ Machine Setup ║${NC}"
echo -e "${BOLD}╚══════════════════════════════════════════════════╝${NC}"
detect_os
echo ""
info "Machine: ${OS_NAME} (${ARCH})"
info "Packages: ${PM:-none detected}"
[[ "$IS_WSL" == true ]] && warn "WSL detected — the suspend, logind and boot-hang steps do not apply here"
# Everything below this line is written against apt and systemd. Detection above
# recognises pacman, dnf and brew so the branches have somewhere to hang, but
# nothing implements them yet — and running the apt path on Arch would half-build
# a machine and stop somewhere unhelpful. Refuse clearly instead, and relax this
# list one entry at a time as each package manager grows a real path.
case "$PM" in
apt) ;;
"") fail "Could not find a package manager for '${OS_NAME}'." ;;
*) fail "${OS_NAME} uses ${PM}, which this script does not implement yet — apt-based systems only, so far." ;;
esac
ask_machine_role
info "Role: ${MACHINE_ROLE}"
if [[ -f "$PROGRESS_FILE" ]]; then
DONE_COUNT=$(wc -l < "$PROGRESS_FILE")
echo -e "${YELLOW} Resuming — $DONE_COUNT step(s) already completed${NC}"
echo -e "${YELLOW} Progress file: $PROGRESS_FILE${NC}"
echo -e "${YELLOW} To start fresh: rm $PROGRESS_FILE${NC}"
fi
if [[ "$EUID" -ne 0 ]]; then
fail "Please run as root: sudo ./machine-setup.sh"
fi
prompt_value USERNAME "New admin username (or existing)" ""
if [[ -z "$USERNAME" ]]; then
fail "Username cannot be empty"
fi
USER_HOME="/home/$USERNAME"
# =============================================================================
# 2. System Update & Essentials
# =============================================================================
step "System Update & Essentials"
if ! skip; then
info "Refreshing the package index..."
pkg_refresh
# The one place that deliberately moves versions of things already installed.
# Everything else in this script only ever adds what is absent.
info "Upgrading installed packages..."
pkg_upgrade_all
# shellcheck disable=SC2046 # word splitting is how the list is passed
pkg_install "Core packages" $(pkgs_core)
summarise_last "Core packages"
ok "System updated and core packages in place"
step_ok
fi
# =============================================================================
# 2b. Command-line tools
# =============================================================================
#
# Separate from the packages above because they are a different thing: upstream
# binaries on their own release cadence, not anything the distribution ships.
# Lumping them in made a run look like it was installing system packages and
# then start downloading tarballs unannounced.
step "Command-line tools"
if ! skip; then
# shellcheck disable=SC2046 # word splitting is how the list is passed
tools_install "Command-line tools" $(tools_default)
summarise_last "Command-line tools"
step_ok
fi
# =============================================================================
# NOT PORTED YET
# =============================================================================
#
# Sections still to move across from scripts/setup-old/setup-ubuntu.sh, in order:
#
# locale · timezone · swap · auto-suspend · boot-hang fix · user creation ·
# ssh keys · ssh hardening · dns · static ip · fail2ban · unattended-upgrades ·
# git config · docker · zsh + prompt · tailscale · neovim · js runtimes ·
# dev tools · ufw · zshrc · disk ballast
#
# Each arrives as its own commit. Delete this block when the list is empty.
# =============================================================================
# 23. Summary
# =============================================================================
echo ""
echo ""
if [[ ${#ERRORS[@]} -gt 0 ]]; then
echo -e "${YELLOW}╔══════════════════════════════════════════════════╗${NC}"
echo -e "${YELLOW}║ Setup Complete (with warnings) ║${NC}"
echo -e "${YELLOW}╚══════════════════════════════════════════════════╝${NC}"
else
echo -e "${GREEN}╔══════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║ Setup Complete ║${NC}"
echo -e "${GREEN}╚══════════════════════════════════════════════════╝${NC}"
fi
echo ""
echo -e "${BOLD} What was done:${NC}"
for item in "${SUMMARY[@]}"; do
echo -e " ${GREEN}+${NC} $item"
done
if [[ ${#ERRORS[@]} -gt 0 ]]; then
echo ""
echo -e "${BOLD} Non-critical issues:${NC}"
for err in "${ERRORS[@]}"; do
echo -e " ${YELLOW}!${NC} $err"
done
fi
echo ""
echo -e "${BOLD} Machine:${NC}"
echo " System: $OS_NAME ($ARCH)"
echo " Role: $MACHINE_ROLE"
echo " User: $USERNAME"
echo " Home: $USER_HOME"
[[ -n "${TS_IP:-}" && "$TS_IP" != "unknown" ]] && echo " Tailscale: $TS_IP"
echo ""
# Clean up progress file on success
rm -f "$PROGRESS_FILE"