Add Debian/Ubuntu support via a thin distro dispatch layer
Adds a parallel install path for Debian/Ubuntu hosts alongside the existing
Arch/Omarchy/Hyprland one. The Arch path is untouched at runtime; everything
new is gated on $DISTRO and (for headless) $COMPOSITOR.
Highlights:
- lib/distro.sh: detect_distro + pkg_install/pkg_remove/ca_anchor_path/
ca_update_trust dispatch helpers
- lib/packages.sh: Ubuntu sunshine install pulls LizardByte's official .deb
from GitHub releases (override via SUNSHINE_DEB_URL/SUNSHINE_DEB_VERSION);
GPU encoder packages branch per $DISTRO:$GPU_VENDOR
- bin/sunshine-stream-{do,undo,prestart}-sway.sh + files/sway-headless.*:
swaymsg-based headless capture path for hosts without Hyprland. sway runs
under a systemd-user unit that sunshine.service depends on via drop-in.
- lib/preflight.sh: clearer NVIDIA driver guidance on Ubuntu (we don't install
the driver - too many branch/kernel/Secure-Boot variants); sway-aware
headless preflight
- lib/certs.sh + lib/verify.sh + uninstall.sh: distro-aware CA trust anchor
(Arch: /etc/ca-certificates/trust-source/anchors + update-ca-trust;
Debian: /usr/local/share/ca-certificates + update-ca-certificates)
Verified on Ubuntu 24.04: ./install.sh --doctor --headless loads cleanly,
distro/GPU/compositor detection report the right values, all pre-install
failures correspond to the actual missing pieces.
This commit is contained in:
174
lib/distro.sh
Normal file
174
lib/distro.sh
Normal file
@@ -0,0 +1,174 @@
|
||||
#!/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/<name>.pem + update-ca-trust
|
||||
# Debian: /usr/local/share/ca-certificates/<name>.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
|
||||
}
|
||||
Reference in New Issue
Block a user