118 lines
3.9 KiB
Bash
118 lines
3.9 KiB
Bash
#!/usr/bin/env bash
|
|
# common.sh - shared helpers. Sourced by bootstrap.sh, not run directly.
|
|
|
|
# Exported once so we never rely on the `$SUDO VAR=val cmd` pattern, which
|
|
# breaks when $SUDO is empty (running as root): the var assignment gets parsed
|
|
# before $SUDO expands, so `DEBIAN_FRONTEND=...` ends up treated as a command.
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
|
|
# ---- colors / logging -------------------------------------------------------
|
|
if [[ -t 1 ]]; then
|
|
C_RESET=$'\e[0m'; C_DIM=$'\e[2m'; C_RED=$'\e[31m'; C_GRN=$'\e[32m'
|
|
C_YLW=$'\e[33m'; C_BLU=$'\e[34m'; C_BOLD=$'\e[1m'
|
|
else
|
|
C_RESET=""; C_DIM=""; C_RED=""; C_GRN=""; C_YLW=""; C_BLU=""; C_BOLD=""
|
|
fi
|
|
|
|
log() { printf '%s[*]%s %s\n' "$C_BLU" "$C_RESET" "$*"; }
|
|
ok() { printf '%s[+]%s %s\n' "$C_GRN" "$C_RESET" "$*"; }
|
|
warn() { printf '%s[!]%s %s\n' "$C_YLW" "$C_RESET" "$*" >&2; }
|
|
err() { printf '%s[x]%s %s\n' "$C_RED" "$C_RESET" "$*" >&2; }
|
|
die() { err "$*"; exit 1; }
|
|
step() { printf '\n%s== %s ==%s\n' "$C_BOLD" "$*" "$C_RESET"; }
|
|
|
|
# ---- privilege --------------------------------------------------------------
|
|
# Sets $SUDO to "sudo" if not root, "" if root. Fails if neither works.
|
|
detect_sudo() {
|
|
if [[ $EUID -eq 0 ]]; then
|
|
SUDO=""
|
|
elif command -v sudo >/dev/null 2>&1; then
|
|
SUDO="sudo"
|
|
# prime the credential cache early so prompts don't appear mid-run
|
|
$SUDO -v || die "sudo authentication failed"
|
|
else
|
|
die "not root and sudo not available"
|
|
fi
|
|
}
|
|
|
|
# ---- distro detection -------------------------------------------------------
|
|
# Sets DISTRO_ID (debian/ubuntu/...), DISTRO_LIKE, DISTRO_CODENAME, PKG_MGR.
|
|
detect_distro() {
|
|
[[ -r /etc/os-release ]] || die "/etc/os-release missing - unsupported system"
|
|
# shellcheck disable=SC1091
|
|
. /etc/os-release
|
|
DISTRO_ID="${ID:-unknown}"
|
|
# shellcheck disable=SC2034 # used in bootstrap.sh main()
|
|
DISTRO_LIKE="${ID_LIKE:-}"
|
|
DISTRO_CODENAME="${VERSION_CODENAME:-}"
|
|
|
|
if command -v apt-get >/dev/null 2>&1; then
|
|
PKG_MGR="apt"
|
|
elif command -v dnf >/dev/null 2>&1; then
|
|
PKG_MGR="dnf"
|
|
elif command -v pacman >/dev/null 2>&1; then
|
|
PKG_MGR="pacman"
|
|
else
|
|
die "no supported package manager found (apt/dnf/pacman)"
|
|
fi
|
|
ok "detected ${DISTRO_ID} ${DISTRO_CODENAME:-} (pkg: ${PKG_MGR})"
|
|
}
|
|
|
|
# ---- package helpers (apt-focused, dnf/pacman best-effort) ------------------
|
|
APT_UPDATED=0
|
|
pkg_refresh() {
|
|
case "$PKG_MGR" in
|
|
apt)
|
|
if [[ $APT_UPDATED -eq 0 ]]; then
|
|
log "apt-get update"
|
|
# a single broken third-party repo shouldn't abort the whole bootstrap;
|
|
# downstream installs will fail loudly if a needed pkg is truly missing.
|
|
$SUDO apt-get update -qq || warn "apt-get update reported errors (broken repo?) - continuing"
|
|
APT_UPDATED=1
|
|
fi
|
|
;;
|
|
dnf) $SUDO dnf -q makecache ;;
|
|
pacman) $SUDO pacman -Sy --noconfirm >/dev/null ;;
|
|
esac
|
|
}
|
|
|
|
# is a binary already on PATH?
|
|
have() { command -v "$1" >/dev/null 2>&1; }
|
|
|
|
# install one or more packages, skipping any already-present *packages*
|
|
pkg_install() {
|
|
pkg_refresh
|
|
case "$PKG_MGR" in
|
|
apt)
|
|
$SUDO apt-get install -y -qq \
|
|
--no-install-recommends "$@" ;;
|
|
dnf) $SUDO dnf install -y "$@" ;;
|
|
pacman) $SUDO pacman -S --needed --noconfirm "$@" ;;
|
|
esac
|
|
}
|
|
|
|
# install a package only if a given command is missing. usage: ensure_cmd <cmd> <pkg...>
|
|
ensure_cmd() {
|
|
local cmd="$1"; shift
|
|
if have "$cmd"; then
|
|
printf '%s - %s already present%s\n' "$C_DIM" "$cmd" "$C_RESET"
|
|
return 0
|
|
fi
|
|
log "installing ${cmd} (pkg: $*)"
|
|
pkg_install "$@"
|
|
}
|
|
|
|
# write file from stdin only if content differs (idempotent). usage: write_if_changed <path>
|
|
write_if_changed() {
|
|
local target="$1" tmp
|
|
tmp="$(mktemp)"
|
|
cat > "$tmp"
|
|
if [[ -f "$target" ]] && cmp -s "$tmp" "$target"; then
|
|
rm -f "$tmp"
|
|
return 1 # unchanged
|
|
fi
|
|
$SUDO install -D -m "${2:-0644}" "$tmp" "$target"
|
|
rm -f "$tmp"
|
|
return 0 # changed
|
|
}
|