feat(install): idempotent per-host package installer with host-gated enablement
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
# packages/aur.pkgs — AUR-only desired state, installed via yay (bootstrapped
|
||||||
|
# from the cachyos repo by install.sh). pkgbase names; runtime resolution by yay.
|
||||||
|
|
||||||
|
oh-my-zsh-git # system-wide oh-my-zsh at /usr/share/oh-my-zsh; sourced by .zshrc guard
|
||||||
|
herdr-bin # AI-agent terminal workspace manager (prebuilt binary)
|
||||||
|
proton-pass # Proton Pass desktop client
|
||||||
|
handy-bin # Handy voice dictation (AppImage repackaged as pkg)
|
||||||
|
typora # markdown editor
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# packages/blankpad.pkgs — desired state for the AMD iGPU laptop (Cezanne/Vega).
|
||||||
|
# amdgpu is in-kernel; the only GPU-relevant package is the CPU microcode,
|
||||||
|
# pkgbase amd-u-code (split pkgname amd-ucode). No module options needed.
|
||||||
|
|
||||||
|
amd-u-code
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# packages/common.pkgs — desired-state package list for EVERY host in the fleet.
|
||||||
|
# install.sh installs (desired − installed); already-installed names are no-ops.
|
||||||
|
# pkgbase names only; AUR lives in aur.pkgs.
|
||||||
|
|
||||||
|
# terminals + shells
|
||||||
|
ghostty
|
||||||
|
zoxide
|
||||||
|
|
||||||
|
# dev tooling
|
||||||
|
neovim
|
||||||
|
lazygit
|
||||||
|
uv
|
||||||
|
fzf
|
||||||
|
ripgrep
|
||||||
|
fd
|
||||||
|
eza
|
||||||
|
btop
|
||||||
|
|
||||||
|
# system / fleet tooling
|
||||||
|
yay # AUR helper bootstrap: ships in the cachyos repo; aur.pkgs installs need it
|
||||||
|
git-lfs # LFS smudge/clean for tracked wallpapers (see .gitattributes)
|
||||||
|
swayidle # idle lock + lid policy via swayidle-lock.service unit
|
||||||
|
|
||||||
|
# desktop apps
|
||||||
|
flameshot # screenshot tool; bound to CTRL+Shift+1/2/3 in niri keybinds
|
||||||
|
wl-clipboard # clipboard provider flameshot copies through on wayland
|
||||||
|
filezilla
|
||||||
|
podman
|
||||||
|
firefox
|
||||||
|
vlc
|
||||||
|
steam
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# packages/dankware.pkgs — desired state for the nvidia hybrid-GPU laptop.
|
||||||
|
# GPU stack: open-kernel-module DKMS kernels; nvidia-utils/lib32/libxnvctrl/
|
||||||
|
# nvidia-prime/nvidia-settings arrive as dependencies of these pkgbases.
|
||||||
|
# Sleep fix (NVreg_UseKernelSuspendNotifiers=1 + nvidia-suspend/resume units)
|
||||||
|
# ships with these packages; install.sh --apply enables the units idempotently.
|
||||||
|
|
||||||
|
linux-cachyos-nvidia-open
|
||||||
|
linux-cachyos-lts-nvidia-open
|
||||||
Executable
+115
@@ -0,0 +1,115 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# install.sh — idempotent fleet package installer for the ~/.omp repo deployment.
|
||||||
|
#
|
||||||
|
# Model: packages/*.pkgs declare DESIRED state per host. This script computes
|
||||||
|
# (desired − installed) and installs only that delta via pacman/yay. It NEVER
|
||||||
|
# removes anything. Re-running after a fresh install, or casually months later,
|
||||||
|
# is safe by construction.
|
||||||
|
#
|
||||||
|
# Modes:
|
||||||
|
# install.sh check (default): print the plan for this host, write nothing
|
||||||
|
# install.sh --apply install the delta + run host-gated enablement actions
|
||||||
|
#
|
||||||
|
# Host selection: --host <name> overrides $(hostname); an unknown host gets the
|
||||||
|
# common manifest only — wrong-host runs are a no-op, not a hazard.
|
||||||
|
#
|
||||||
|
# Sudo: set FRANK_SUDO_PW in the environment for non-interactive runs;
|
||||||
|
# otherwise sudo prompts normally. The value is never stored in this repo.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO="$(git -C "$(dirname "$(realpath "$0")")" rev-parse --show-toplevel 2>/dev/null || true)"
|
||||||
|
REPO="${INSTALL_REPO:-$REPO}"
|
||||||
|
[ -n "$REPO" ] && [ -d "$REPO/packages" ] || { echo "install.sh: no packages/ under ${REPO:-<repo>}" >&2; exit 1; }
|
||||||
|
|
||||||
|
MODE="check"
|
||||||
|
HOST="$(hostname)"
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--apply) MODE="apply"; shift ;;
|
||||||
|
--host) HOST="$2"; shift 2 ;;
|
||||||
|
*) echo "usage: install.sh [--apply] [--host <name>]" >&2; exit 2 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
SUDO() {
|
||||||
|
if [[ -n "${FRANK_SUDO_PW:-}" ]]; then printf '%s' "$FRANK_SUDO_PW" | sudo -S -p '' "$@"
|
||||||
|
else sudo "$@"; fi
|
||||||
|
}
|
||||||
|
|
||||||
|
read_manifest() { # $1 = manifest path; emits package names, strips comments/blanks
|
||||||
|
sed 's/#.*//' "$1" | tr -d '\r' | awk 'NF'
|
||||||
|
}
|
||||||
|
|
||||||
|
# ---- desired-minus-installed delta ------------------------------------------
|
||||||
|
PKGS=()
|
||||||
|
for m in common.pkgs "$HOST.pkgs"; do
|
||||||
|
[[ -f "$REPO/packages/$m" ]] || continue
|
||||||
|
mapfile -t _pkgs < <(read_manifest "$REPO/packages/$m")
|
||||||
|
PKGS+=("${_pkgs[@]}")
|
||||||
|
done
|
||||||
|
|
||||||
|
# AUR phase only when the helper exists or can be bootstrapped from a repo pkg
|
||||||
|
AUR_PKGS=()
|
||||||
|
if [[ -f "$REPO/packages/aur.pkgs" ]]; then
|
||||||
|
mapfile -t AUR_PKGS < <(read_manifest "$REPO/packages/aur.pkgs")
|
||||||
|
fi
|
||||||
|
|
||||||
|
mapfile -t INSTALLED < <(pacman -Qq | sort)
|
||||||
|
DELTAC=()
|
||||||
|
for p in "${PKGS[@]}"; do
|
||||||
|
printf '%s\n' "${INSTALLED[@]}" | grep -qx -- "$p" || DELTAC+=("$p")
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "install.sh [$MODE] host=$HOST"
|
||||||
|
if [[ ${#DELTAC[@]} -eq 0 ]]; then
|
||||||
|
echo "repo pkgs: delta empty — nothing to install"
|
||||||
|
else
|
||||||
|
echo "repo pkgs to install: ${DELTAC[*]}"
|
||||||
|
fi
|
||||||
|
for p in "${AUR_PKGS[@]}"; do
|
||||||
|
printf '%s\n' "${INSTALLED[@]}" | grep -qx -- "$p" || echo "aur pkg pending: $p"
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ "$MODE" == "check" ]] && exit 0
|
||||||
|
|
||||||
|
# ---- apply ------------------------------------------------------------------
|
||||||
|
if [[ ${#DELTAC[@]} -gt 0 ]]; then
|
||||||
|
SUDO pacman -S --needed --noconfirm -- "${DELTAC[@]}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Helper bootstrap: yay itself ships in the cachyos repo (no chicken-and-egg).
|
||||||
|
if [[ ${#AUR_PKGS[@]} -gt 0 ]] && ! pacman -Qq yay >/dev/null 2>&1; then
|
||||||
|
SUDO pacman -S --needed --noconfirm -- yay
|
||||||
|
fi
|
||||||
|
|
||||||
|
for p in "${AUR_PKGS[@]}"; do
|
||||||
|
printf '%s\n' "${INSTALLED[@]}" | grep -qx -- "$p" || {
|
||||||
|
YAYFLAGS="--answerclean None --answerdiff None" SUDO yay -S --needed --noconfirm -- "$p"
|
||||||
|
}
|
||||||
|
done
|
||||||
|
|
||||||
|
# ---- host-gated enablement ---------------------------------------------------
|
||||||
|
case "$HOST" in
|
||||||
|
dankware)
|
||||||
|
# nvidia sleep fix: package hooks already ship /usr/lib/modprobe.d/nvidia-sleep.conf
|
||||||
|
# (UseKernelSuspendNotifiers=1 + TemporaryFilePath); enable the units idempotently.
|
||||||
|
SUDO systemctl enable --now nvidia-suspend nvidia-resume 2>/dev/null || true
|
||||||
|
;;
|
||||||
|
blankpad)
|
||||||
|
# Cezanne iGPU: amdgpu is in-kernel, amd-ucode carried by kernel pkg; no module options.
|
||||||
|
:
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# sshd + firewall — same posture on both hosts (decision 2026-09: ssh open in default zone)
|
||||||
|
if command -v sshd >/dev/null 2>&1 || pacman -Qq openssh >/dev/null 2>&1; then
|
||||||
|
SUDO systemctl enable --now sshd
|
||||||
|
fi
|
||||||
|
if command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state >/dev/null 2>&1; then
|
||||||
|
if ! firewall-cmd --query-service ssh >/dev/null 2>&1; then
|
||||||
|
SUDO firewall-cmd --permanent --zone=public --add-service=ssh
|
||||||
|
SUDO firewall-cmd --reload
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "install.sh [$MODE] host=$HOST done"
|
||||||
Reference in New Issue
Block a user