detect the operating system before any step runs
The script assumed Ubuntu on x86_64 in every line of it. detect_os() now runs first and fills in OS, OS_NAME, OS_VERSION, PM, ARCH and IS_WSL, so the steps have something to branch on as support for other systems is added. Read from /etc/os-release rather than probing for a binary: a machine can have more than one package manager on PATH, and only os-release can say which distribution this actually is or give a version worth printing. Sourced in a subshell so its NAME, VERSION and ID do not leak in here. ID_LIKE is the fallback, so Pop!_OS, Mint and EndeavourOS resolve without being named. ARCH is normalised to amd64/arm64 in one place because upstream disagrees — Neovim ships aarch64, Go and Docker ship arm64, lazygit ships x86_64 — and several steps hardcode one spelling today. Windows exits with a message pointing at WSL2. WSL itself is detected and warned about rather than refused: it reports as Linux but has no real systemd session, so the suspend, logind and boot-hang steps do nothing there. Everything below pre-flight is still apt and systemd only, so a gate refuses pacman/dnf/brew by name rather than half-building a machine and stopping somewhere unhelpful. Relax that case one entry at a time as each grows a path. Verified on this host (Ubuntu 24.04.4, amd64, apt) and by stubbing uname and os_release for arch, manjaro/arm64, fedora, pop, macos, mingw and riscv64. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+109
-2
@@ -14,6 +14,15 @@ ERRORS=()
|
||||
CURRENT_STEP=""
|
||||
SKIP_STEP=false
|
||||
|
||||
# What machine this is. Filled in by detect_os() before any step runs; every step
|
||||
# after that branches on these rather than assuming apt on x86_64.
|
||||
OS="" # os-release ID: ubuntu | debian | arch | fedora | macos | …
|
||||
OS_NAME="" # pretty name, for the banner
|
||||
OS_VERSION="" # version id; empty on rolling releases
|
||||
PM="" # apt | pacman | dnf | brew
|
||||
ARCH="" # amd64 | arm64, normalised — upstream tarballs disagree on spelling
|
||||
IS_WSL=false
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# -----------------------------------------------------------------------------
|
||||
@@ -84,15 +93,113 @@ as_user() {
|
||||
sudo -u "$USERNAME" -i bash -c "$1"
|
||||
}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Operating system detection
|
||||
# -----------------------------------------------------------------------------
|
||||
#
|
||||
# Read one key out of /etc/os-release without leaking the rest of it into this
|
||||
# script. That file defines NAME, VERSION and ID — all generic enough to collide
|
||||
# with something here — so it is sourced in a subshell and only the one value
|
||||
# asked for comes back.
|
||||
os_release() {
|
||||
[[ -r /etc/os-release ]] || return 1
|
||||
# shellcheck disable=SC1091
|
||||
(
|
||||
. /etc/os-release 2>/dev/null
|
||||
printf '%s' "${!1:-}"
|
||||
)
|
||||
}
|
||||
|
||||
# Identify the machine, or refuse to guess.
|
||||
#
|
||||
# /etc/os-release rather than probing for a binary: a box can have more than one
|
||||
# package manager on PATH (a Homebrew install on Linux, a leftover apt on a
|
||||
# converted box), and only os-release can say which distribution the machine
|
||||
# actually IS, or give a version worth reporting.
|
||||
#
|
||||
# ID_LIKE is the fallback so derivatives resolve without being listed by name —
|
||||
# Pop!_OS, Mint and EndeavourOS all answer correctly without appearing below.
|
||||
detect_os() {
|
||||
local kernel like
|
||||
kernel="$(uname -s)"
|
||||
|
||||
case "$kernel" in
|
||||
Darwin)
|
||||
OS="macos"
|
||||
OS_VERSION="$(sw_vers -productVersion 2>/dev/null || true)"
|
||||
OS_NAME="macOS ${OS_VERSION}"
|
||||
PM="brew"
|
||||
;;
|
||||
Linux)
|
||||
OS="$(os_release ID || true)"
|
||||
OS_NAME="$(os_release PRETTY_NAME || true)"
|
||||
OS_VERSION="$(os_release VERSION_ID || true)"
|
||||
like="$(os_release ID_LIKE || true)"
|
||||
|
||||
case "$OS" in
|
||||
ubuntu | debian | linuxmint | pop | raspbian | elementary) PM="apt" ;;
|
||||
arch | manjaro | endeavouros | cachyos | garuda) PM="pacman" ;;
|
||||
fedora | rhel | centos | rocky | almalinux) PM="dnf" ;;
|
||||
*)
|
||||
case " $like " in
|
||||
*" debian "* | *" ubuntu "*) PM="apt" ;;
|
||||
*" arch "*) PM="pacman" ;;
|
||||
*" fedora "* | *" rhel "*) PM="dnf" ;;
|
||||
esac
|
||||
;;
|
||||
esac
|
||||
|
||||
# WSL reports itself as Linux, but has no real systemd session: masking
|
||||
# sleep targets, restarting logind and anything touching the boot path
|
||||
# either fail or silently do nothing. Worth knowing before those steps run.
|
||||
if grep -qi microsoft /proc/version 2>/dev/null; then IS_WSL=true; fi
|
||||
;;
|
||||
MINGW* | MSYS* | CYGWIN*)
|
||||
fail "Windows is not supported. Run this inside WSL2 with an Ubuntu image instead."
|
||||
;;
|
||||
*)
|
||||
fail "Unrecognised kernel '$kernel' — cannot tell what this machine is."
|
||||
;;
|
||||
esac
|
||||
|
||||
# Normalised once here because upstream projects spell it differently:
|
||||
# Neovim ships aarch64, Go and Docker ship arm64, and lazygit ships x86_64.
|
||||
case "$(uname -m)" in
|
||||
x86_64 | amd64) ARCH="amd64" ;;
|
||||
aarch64 | arm64) ARCH="arm64" ;;
|
||||
*) fail "Unsupported CPU architecture '$(uname -m)' — this script installs amd64/arm64 binaries only." ;;
|
||||
esac
|
||||
|
||||
[[ -n "$OS" ]] || fail "Could not identify this distribution (no readable /etc/os-release)."
|
||||
[[ -n "$OS_NAME" ]] || OS_NAME="$OS${OS_VERSION:+ $OS_VERSION}"
|
||||
}
|
||||
|
||||
# =============================================================================
|
||||
# 1. Pre-flight
|
||||
# =============================================================================
|
||||
|
||||
echo ""
|
||||
echo -e "${BOLD}╔══════════════════════════════════════════════════╗${NC}"
|
||||
echo -e "${BOLD}║ Ubuntu Server Setup ║${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
|
||||
|
||||
if [[ -f "$PROGRESS_FILE" ]]; then
|
||||
DONE_COUNT=$(wc -l < "$PROGRESS_FILE")
|
||||
echo -e "${YELLOW} Resuming — $DONE_COUNT step(s) already completed${NC}"
|
||||
@@ -101,7 +208,7 @@ if [[ -f "$PROGRESS_FILE" ]]; then
|
||||
fi
|
||||
|
||||
if [[ "$EUID" -ne 0 ]]; then
|
||||
fail "Please run as root: sudo ./setup-ubuntu.sh"
|
||||
fail "Please run as root: sudo ./machine-setup.sh"
|
||||
fi
|
||||
|
||||
prompt_value USERNAME "New admin username (or existing)" ""
|
||||
|
||||
Reference in New Issue
Block a user