From 5b7ed5ede99def898f688481d224026d38606bc5 Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Tue, 27 Oct 2026 13:04:15 +0100 Subject: [PATCH] Package sections: always-on categories + advanced menu installer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Section 6 'Always-installed packages': ALWAYS_PACKAGES array, one line per category (first: Terminals with ghostty + ghostty-bash-completion). Every entry installs on every run, no questions. Add a category by adding a line. Section 7 'Advanced optional tools': menu-driven picker, data-driven — ADV_CATEGORIES + ADV_ arrays ('id:Label:pkgs...'). Ships Virtualisation (qemu/kvm stack, VirtualBox) and Browsers (firefox, chromium, google-chrome, brave; the latter two wire up their repos automatically). Multi-select with comma-separated picks, invalid picks warned and skipped, 'x' backs out, menu is skipped under --yes so unattended runs never hang. Bugs found by harness testing and fixed before shipping: - ${!var} on an array name yields only element[0]: Browsers listed one entry. Now uses a nameref (declare -n). - var assignment was lost in an edit: unbound-variable crash on the menu. - --snapper=no was overwritten by the interactive default; explicit flags now always win. --- setup.sh | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 8e53ee0..01d322b 100755 --- a/setup.sh +++ b/setup.sh @@ -395,7 +395,164 @@ fi #------------------------------------------ # 6 Done #------------------------------------------ -step "7 Summary" + +#------------------------------------------ +# 6 Always-installed packages +#------------------------------------------ +# Add a category here and it is installed on every run, no questions asked. +# Keep each category one line so diffs stay readable. +ALWAYS_PACKAGES=( + # Terminals + "ghostty ghostty-bash-completion" +) + +step "6 Always-installed packages" +rule + +for category in "${ALWAYS_PACKAGES[@]}"; do + # shellcheck disable=SC2086 + install_packages $category +done +ok "Always-packages installed." +pause_if_debug + + +#------------------------------------------ +# 7 Advanced: optional tool selection (menu-driven) +#------------------------------------------ +# Add categories/apps by editing these parallel arrays: +# ADV_CATEGORIES : display order +# ADV_ : "pkg1 pkg2 ..." for each category (dots/minus -> underscore) +ADV_CATEGORIES=( + "Virtualisation" + "Browsers" +) +# shellcheck disable=SC2034 # arrays are read via nameref from ADV_CATEGORIES +ADV_Virtualisation=( + "qemu-kvm:QEMU/KVM (full virt stack):qemu-kvm libvirt virt-install virt-manager virt-viewer edk2-ovmf swtpm guestfs-tools libguestfs-tools" + "virtualbox:VirtualBox (Oracle):VirtualBox kernel-devel kernel-headers dkms akmod-VirtualBox" +) +# shellcheck disable=SC2034 # arrays are read via nameref from ADV_CATEGORIES +ADV_Browsers=( + "firefox:Firefox:firefox" + "chromium:Chromium:chromium" + "google-chrome:Google Chrome (adds repo):google-chrome-stable" + "brave:Brave (adds repo):brave-browser" +) + +run_advanced_menu() { + local done_any=false + while true; do + printf "\n" + color_gray "Optional tools - select a category to pick from:" + printf "\n" + local i=1 cat + for cat in "${ADV_CATEGORIES[@]}"; do + echo " $i) $cat" + i=$((i+1)) + done + echo " x) Done with optional tools" + local choice + if ! read -t 90 -rp "Category [1-${#ADV_CATEGORIES[@]}/x] (default: x): " choice; then + printf "\n"; choice="x" + fi + [[ "${choice,,}" == "x" || -z "$choice" ]] && break + + if [[ ! "$choice" =~ ^[0-9]+$ ]] || (( choice < 1 || choice > ${#ADV_CATEGORIES[@]} )); then + err "Invalid choice: $choice" + continue + fi + cat="${ADV_CATEGORIES[$((choice-1))]}" + + # apps for this category — nameref, because ${!var} on an array name + # would only give element 0 (that bug showed in testing: Browsers + # listed exactly one entry) + local var="ADV_${cat//[ .-]/_}" + local -n entries_ref="$var" + local -a entries + # shellcheck disable=SC2206 + entries=("${entries_ref[@]}") + + printf "\n" + color_cyan "$cat:" + local j=1 entry + local -a ids=() labels=() + for entry in "${entries[@]}"; do + ids+=("${entry%%:*}") # entry id + local rest="${entry#*:}" + labels+=("${rest%%:*}") # display label + echo " $j) ${labels[-1]}" + j=$((j+1)) + done + echo " x) Back" + + local sel + if ! read -t 90 -rp "Install which? (comma-separate for multiple, default: back): " sel; then + printf "\n"; continue + fi + [[ "${sel,,}" == "x" || -z "$sel" ]] && continue + + # Resolve picks to package lists. Entry format: id:Label:packages... + local -a to_install=() + local pick n rest + IFS=',' read -ra picks <<< "$sel" + for pick in "${picks[@]}"; do + pick="${pick// /}" + [[ "$pick" =~ ^[0-9]+$ ]] || { err "Ignoring invalid pick: $pick"; continue; } + n=${#entries[@]} + if (( pick < 1 || pick > n )); then err "Ignoring out-of-range pick: $pick"; continue; fi + entry="${entries[$((pick-1))]}" + rest="${entry#*:}"; rest="${rest#*:}" # drop id and label -> packages + to_install+=("$rest") + done + + if (( ${#to_install[@]} > 0 )); then + step "Installing from $cat: ${to_install[*]}" + # Repos for items that need one are handled in install_optional_pkgs below. + install_category_pkgs "$cat" "${to_install[@]}" + done_any=true + fi + done + $done_any && ok "Optional tools installed." +} + +# Per-category pre-repo wiring. Add third-party repos here when you add an +# app that needs one; packages alone stay generic. +install_category_pkgs() { + local cat="$1"; shift + case "$cat" in + Browsers) + local needs_chrome=false needs_brave=false item + for item in "$@"; do + [[ "$item" == *google-chrome* ]] && needs_chrome=true + [[ "$item" == *brave* ]] && needs_brave=true + done + if $needs_chrome && ! pkg_installed google-chrome-stable; then + info "Adding Google Chrome repo..." + sudo dnf install -y fedora-workstation-repositories 2>/dev/null || true + sudo dnf config-manager setopt google-chrome.enabled=1 2>/dev/null || \ + sudo dnf install -y "https://dl.google.com/linux/direct/google-chrome-stable_current_x86_64.rpm" + fi + if $needs_brave && ! pkg_installed brave-browser; then + info "Adding Brave repo..." + sudo dnf install -y dnf-plugins-core + sudo dnf config-manager add --from-repofile=https://brave-browser-rpm-release.s3.brave.com/brave-browser.repo || \ + true + sudo rpm --import https://brave-browser-rpm-release.s3.brave.com/brave-core.asc 2>/dev/null || true + fi + ;; + esac + install_packages "$@" +} + +# Interactive only: an unattended --yes run must not hang on this menu. +# Skip silently there; use --de/--twm/--dotfiles for everything unattended. +if [[ "$ASSUME_YES" != "true" ]]; then + run_advanced_menu +fi +pause_if_debug + +step "8 Summary" rule ok "DE: $DE" ok "TWM: $TWM"