#!/usr/bin/env bash # Distro detection + small dispatch layer so the rest of the installer can # stay distro-agnostic. Two backends supported today: Arch (Omarchy) and # Debian/Ubuntu. # # Sourced once at the top of install.sh / uninstall.sh. detect_distro must # run before any of the dispatch helpers; require_supported_distro calls it # for you. # Populated by detect_distro: # DISTRO - "arch" | "debian" (ubuntu folds into debian) # DISTRO_ID - raw ID from /etc/os-release (e.g. "ubuntu", "arch") # DISTRO_VERSION - VERSION_ID from /etc/os-release (e.g. "24.04"), empty on Arch detect_distro() { if [[ -n "${DISTRO:-}" ]]; then return 0 fi local id="" id_like="" version_id="" if [[ -r /etc/os-release ]]; then # shellcheck disable=SC1091 . /etc/os-release id="${ID:-}" id_like="${ID_LIKE:-}" version_id="${VERSION_ID:-}" fi DISTRO_ID="$id" DISTRO_VERSION="$version_id" case "$id" in arch|manjaro|endeavouros|omarchy) DISTRO="arch" ;; ubuntu|debian|pop|linuxmint) DISTRO="debian" ;; *) # Fall back to ID_LIKE. if [[ " $id_like " == *" arch "* ]]; then DISTRO="arch" elif [[ " $id_like " == *" debian "* || " $id_like " == *" ubuntu "* ]]; then DISTRO="debian" elif [[ -f /etc/arch-release ]]; then DISTRO="arch" elif command -v apt-get >/dev/null 2>&1; then DISTRO="debian" elif command -v pacman >/dev/null 2>&1; then DISTRO="arch" else DISTRO="unknown" fi ;; esac export DISTRO DISTRO_ID DISTRO_VERSION } require_supported_distro() { detect_distro case "$DISTRO" in arch) if ! command -v yay >/dev/null 2>&1; then err "yay is required to install AUR packages on Arch. Install yay first." exit 1 fi ;; debian) if ! command -v apt-get >/dev/null 2>&1; then err "apt-get not found — Debian/Ubuntu install path requires it." exit 1 fi ;; *) err "Unsupported distro (ID='${DISTRO_ID:-unknown}'). Supported: Arch family, Debian/Ubuntu family." exit 1 ;; esac } # --------------------------------------------------------------------------- # Package query / install dispatch. # True if package is installed. pkg_installed() { case "$DISTRO" in arch) pacman -Qi "$1" >/dev/null 2>&1 ;; debian) dpkg-query -W -f='${Status}' "$1" 2>/dev/null | grep -q '^install ok installed$' ;; *) return 1 ;; esac } # Install one or more packages. Idempotent: only installs missing ones. # On Arch, uses yay; on Debian/Ubuntu, uses apt-get. The Arch-only yay_install # function below is kept as an alias for code that explicitly wants AUR. pkg_install() { local missing=() local p for p in "$@"; do pkg_installed "$p" || missing+=("$p") done if [[ ${#missing[@]} -eq 0 ]]; then ok "Already installed: $*" return 0 fi info "Installing: ${missing[*]}" case "$DISTRO" in arch) yay -S --needed --noconfirm "${missing[@]}" ;; debian) _apt_ensure_updated as_root env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "${missing[@]}" ;; *) err "Don't know how to install packages on distro '$DISTRO'" return 1 ;; esac } # Cache `apt-get update` for this script run; running it on every pkg_install # call would be slow and noisy. _APT_UPDATED=0 _apt_ensure_updated() { [[ "$_APT_UPDATED" -eq 1 ]] && return 0 info "Refreshing apt package lists" as_root env DEBIAN_FRONTEND=noninteractive apt-get update -y >/dev/null _APT_UPDATED=1 } # Install a local .deb file. Resolves its dependencies via apt. deb_install_local() { local deb_path="$1" [[ -f "$deb_path" ]] || { err "deb not found: $deb_path"; return 1; } _apt_ensure_updated info "Installing $(basename "$deb_path") via apt-get" as_root env DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "$deb_path" } # Remove a package if installed. Quiet no-op if absent. pkg_remove() { local p for p in "$@"; do pkg_installed "$p" || continue case "$DISTRO" in arch) as_root pacman -Rns --noconfirm "$p" ;; debian) as_root env DEBIAN_FRONTEND=noninteractive apt-get purge -y "$p" ;; esac done } # --------------------------------------------------------------------------- # CA trust-store dispatch. # # Arch: /etc/ca-certificates/trust-source/anchors/.pem + update-ca-trust # Debian: /usr/local/share/ca-certificates/.crt + update-ca-certificates # Path where we'll drop our CA anchor for this distro. Stable across runs. ca_anchor_path() { case "$DISTRO" in arch) echo "/etc/ca-certificates/trust-source/anchors/omarchy-stream-ca.pem" ;; debian) echo "/usr/local/share/ca-certificates/omarchy-stream-ca.crt" ;; *) echo "" ;; esac } # Refresh the system trust store after writing a new anchor. ca_update_trust() { case "$DISTRO" in arch) as_root update-ca-trust extract >/dev/null ;; debian) as_root update-ca-certificates >/dev/null ;; *) warn "Unknown distro — CA trust update skipped"; return 1 ;; esac }