From a38a007ce362950f802ce1f77abd2f75a55b7133 Mon Sep 17 00:00:00 2001 From: alvinlollo Date: Thu, 8 Oct 2026 14:02:43 +1100 Subject: [PATCH] Migrate menu from whiptail to gum with label-based dispatch --- README.md | 4 +- install.sh | 89 ++++++++++---------- installbeta.sh | 222 ++++++++++++++++++++++++++++++++----------------- 3 files changed, 192 insertions(+), 123 deletions(-) diff --git a/README.md b/README.md index 2cea5d8..eaaca09 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Single-install-script This script automatically installs my favourite Linux applications I use every day such as: -[Docker](https://www.docker.com/), [zsh, oh-my-zsh](https://github.com/ohmyzsh/ohmyzsh) and [neovim](https://neovim.io/). This uses the [shelly-cli](https://github.com/Seafoam-Labs/Shelly-ALPM) package manager. You can choose what sections to install with the whiptail menu. +[Docker](https://www.docker.com/), [zsh, oh-my-zsh](https://github.com/ohmyzsh/ohmyzsh) and [neovim](https://neovim.io/). This uses the [shelly-cli](https://github.com/Seafoam-Labs/Shelly-ALPM) package manager. You can choose what sections to install with the [gum](https://github.com/charmbracelet/gum) menu. This script will automatically install [shelly-cli](https://github.com/Seafoam-Labs/Shelly-ALPM) if it is not already present. @@ -15,7 +15,7 @@ Please consider staring this project. It helps me see how important this is for ## Usage -> **Warning:** Run this script with **bash**, not fish (or another shell). It uses bash-only syntax and will fail if run under fish. Keep `bash` in the commands below — do not replace it with `fish` or `source` the script. If fish is your default shell, a warning (dialog if whiptail is installed, otherwise a text prompt) will remind you before anything is installed. +> **Warning:** Run this script with **bash**, not fish (or another shell). It uses bash-only syntax and will fail if run under fish. Keep `bash` in the commands below — do not replace it with `fish` or `source` the script. If fish is your default shell, a warning (a `gum confirm` dialog if gum is installed, otherwise a text prompt) will remind you before anything is installed. To use this script paste the following in the Terminal: diff --git a/install.sh b/install.sh index 2357f55..5455b18 100755 --- a/install.sh +++ b/install.sh @@ -8,9 +8,8 @@ fi # Detect fish shell and warn user to run with bash instead (bash-only syntax) if [ -n "${FISH_VERSION:-}" ] || case "$SHELL" in *fish*) ;; *) false ;; esac; then - if command -v whiptail >/dev/null; then - if ! whiptail --title "Warning: use bash, not fish" --yesno \ - "Your default shell appears to be fish.\n\nThis script must be run with bash. It uses bash-only syntax and will fail under fish.\n\nRun it with:\n bash install.sh\n\nContinue anyway?" 15 72; then + if command -v gum >/dev/null; then + if ! gum confirm "$(printf 'Your default shell appears to be fish.\n\nThis script must be run with bash. It uses bash-only syntax and will fail under fish.\n\nRun it with:\n bash install.sh\n\nContinue anyway?')"; then echo "Aborted. Please run this script with bash, not fish. e.g.: bash install.sh" exit 1 fi @@ -84,70 +83,70 @@ fi # Install prerequisites if command -v shelly >/dev/null; then echo "Shelly detected. Installing prerequisites" - shelly install standard git zsh curl wget libnewt rsync whiptail --upgrade --no-confirm + shelly install standard git zsh curl wget libnewt rsync gum --upgrade --no-confirm fi if command -v apt >/dev/null; then echo "apt detected. Installing prerequisites" sudo apt update sudo apt full-upgrade -y - sudo apt install git zsh curl wget whiptail rsync -y + sudo apt install git zsh curl wget rsync gum -y fi -# Ensure whiptail is installed -if ! command -v whiptail >/dev/null; then - echo "whiptail is not installed. Installing it now..." +# Ensure gum is installed +if ! command -v gum >/dev/null; then + echo "gum is not installed. Installing it now..." if command -v shelly >/dev/null; then - echo "shelly detected. Installing whiptail" - shelly install standard whiptail --no-confirm || { - echo "Failed to install whiptail. Exiting." + echo "shelly detected. Installing gum" + shelly install standard gum --no-confirm || { + echo "Failed to install gum. Exiting." exit 1 } fi if command -v apt >/dev/null; then - echo "apt detected. Installing whiptail" - sudo apt install whiptail -y || { - echo "Failed to install whiptail. Exiting." + echo "apt detected. Installing gum" + sudo apt install gum -y || { + echo "Failed to install gum. Exiting." exit 1 } fi fi -# Options for the whiptail menu +# Options for the gum menu OPTIONS=( - 1 "Run zsh setup script" OFF - 2 "Run fish setup script" ON - 3 "Run LazyVim setup script" OFF - 4 "Install Docker" OFF - 5 "Install Standard Packages (Shelly)" ON - 6 "Install AUR Packages (Shelly)" ON - 7 "Install affinity with GUI" OFF - 8 "Run bat setup script" ON + "Run zsh setup script" + "Run fish setup script" + "Run LazyVim setup script" + "Install Docker" + "Install Standard Packages (Shelly)" + "Install AUR Packages (Shelly)" + "Install affinity with GUI" + "Run bat setup script" ) -CHOICE=$(whiptail --title "Installation Options" --checklist \ - "Choose components to install:" 20 78 10 \ - "${OPTIONS[@]}" 3>&1 1>&2 2>&3) - -exitstatus=$? -if [ $exitstatus = 0 ]; then - echo "User selected: $CHOICE" -else +CHOICE=$(gum choose --no-limit --height 14 \ + --header "Tab = select, Enter = confirm:" \ + --selected "Run fish setup script,Install Standard Packages (Shelly),Install AUR Packages (Shelly),Run bat setup script" \ + "${OPTIONS[@]}") || { echo "User cancelled installation." exit 1 -fi +} + +echo "User selected:" +echo "$CHOICE" # Fail on any command. set -euo pipefail -# Process selected options -for selection in $CHOICE; do - clean_selection=$(echo "$selection" | tr -d '"') - case $clean_selection in - "1") +# Process selected options in menu order +while IFS= read -r selection; do + # Skip options the user did not select + grep -qxF "$selection" <<<"$CHOICE" || continue + case "$selection" in + "Run zsh setup script") echo "Running zsh setup script..." # Runs local script unless it does not exist or fails if [[ -f "zsh.sh" ]]; then @@ -157,7 +156,7 @@ for selection in $CHOICE; do curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/zsh.sh | bash -s -- --skip-watermark fi ;; - "2") + "Run fish setup script") echo "Running fish setup script..." # Runs local script unless it does not exist or fails if [[ -f "fish.sh" ]]; then @@ -167,7 +166,7 @@ for selection in $CHOICE; do curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/fish.sh | bash -s -- --skip-watermark fi ;; - "3") + "Run LazyVim setup script") echo "Running LazyVim setup script..." # Runs local script unless it does not exist or fails if [[ -f "LazyVim.sh" ]]; then @@ -177,7 +176,7 @@ for selection in $CHOICE; do curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/LazyVim.sh | bash fi ;; - "4") + "Install Docker") echo "Installing Docker..." if ! command -v docker >/dev/null; then echo "docker is NOT installed. Installing..." @@ -189,7 +188,7 @@ for selection in $CHOICE; do echo "+ sleep 10" && sleep 10 fi ;; - "5") + "Install Standard Packages (Shelly)") echo "Installing Standard Packages via Shelly backup..." # Check if shelly binary is installed if ! command -v shelly >/dev/null; then @@ -215,7 +214,7 @@ for selection in $CHOICE; do echo "+ sleep 10" && sleep 10 fi ;; - "6") + "Install AUR Packages (Shelly)") echo "Installing AUR Packages via Shelly backup..." # Check for shelly before installing AUR packages if ! command -v shelly >/dev/null; then @@ -241,7 +240,7 @@ for selection in $CHOICE; do echo "+ sleep 10" && sleep 10 fi ;; - "7") + "Install affinity with GUI") echo "Installing GUI dependencies" if command -v shelly >/dev/null; then echo "shelly found" @@ -262,7 +261,7 @@ for selection in $CHOICE; do sleep 10 curl -sSL https://raw.githubusercontent.com/ryzendew/AffinityOnLinux/refs/heads/main/AffinityScripts/AffinityLinuxInstaller.py | python3 ;; - "8") + "Run bat setup script") echo "Running bat setup script..." # Runs local script unless it does not exist or fails if [[ -f "bat.sh" ]]; then @@ -277,6 +276,6 @@ for selection in $CHOICE; do echo "Invalid option selected: $selection" ;; esac -done +done < <(printf '%s\n' "${OPTIONS[@]}") echo "Installation process complete." diff --git a/installbeta.sh b/installbeta.sh index bcf5af8..14395dd 100755 --- a/installbeta.sh +++ b/installbeta.sh @@ -7,10 +7,9 @@ if [ "$1" = "--skip-watermark" ]; then fi # Detect fish shell and warn user to run with bash instead (bash-only syntax) -if [ -n "${FISH_VERSION:-}" ] || case "$SHELL" in *fish*) ;; *) false ;; esac; then - if command -v whiptail >/dev/null; then - if ! whiptail --title "Warning: use bash, not fish" --yesno \ - "Your default shell appears to be fish.\n\nThis script must be run with bash. It uses bash-only syntax and will fail under fish.\n\nRun it with:\n bash installbeta.sh\n\nContinue anyway?" 15 72; then +if [ -n "${FISH_VERSION:-}" ] || case "$SHELL" in *fish*) ;; *) false ;; esac then + if command -v gum >/dev/null; then + if ! gum confirm "$(printf 'Your default shell appears to be fish.\n\nThis script must be run with bash. It uses bash-only syntax and will fail under fish.\n\nRun it with:\n bash installbeta.sh\n\nContinue anyway?')"; then echo "Aborted. Please run this script with bash, not fish. e.g.: bash installbeta.sh" exit 1 fi @@ -48,6 +47,34 @@ function error_handler() { # Trap errors trap error_handler ERR +# --- Failure handling & full console log ------------------------------------ +# Everything from here on is teed to a log file in /tmp, and Arch-only step +# failures are recorded instead of aborting the rest of the installation. +TTY_OK=false +[ -t 1 ] && TTY_OK=true + +LOG="/tmp/installbeta-$(date +%Y%m%d-%H%M%S).log" +REPORT="/tmp/installbeta-failures-$(date +%Y%m%d-%H%M%S).txt" +FAILED=() + +exec > >(tee -a "$LOG") 2>&1 + +# gum draws its TUI on stderr - keep that on the real terminal, not the log pipe +gum_tty() { + if [ "$TTY_OK" = true ]; then + gum "$@" 2>/dev/tty + else + gum "$@" + fi +} + +# Record a failed step: remember it, print it now, keep installing +record_failure() { + FAILED+=("$1 — $2") + echo "!! FAILED: $1 — $2 (continuing with the rest of the installation)" + echo "$(date '+%F %T') $1 — $2" >>"$REPORT" +} + # Install shelly as a dependency if not present (Arch-based) if command -v pacman >/dev/null; then # Install build prerequisites for shelly @@ -56,7 +83,7 @@ if command -v pacman >/dev/null; then echo "Failed to install prerequisite packages for Shelly. You can try running it manually:" echo "sudo pacman -S --needed --noconfirm base-devel git" echo "--------------------------------------------------------------------" - exit 1 # exit with an error + record_failure "Shelly bootstrap (Arch-only)" "failed to install base-devel/git prerequisites" fi # Check if shelly binary exists if ! command -v shelly >/dev/null; then @@ -66,13 +93,13 @@ if command -v pacman >/dev/null; then echo "Failed to clone shelly repository. You can try running it manually:" echo "git clone https://aur.archlinux.org/shelly.git /tmp/shelly_install" echo "--------------------------------------------------------------------" - exit 1 # exit with an error + record_failure "Shelly bootstrap (Arch-only)" "failed to clone the shelly AUR repository" elif ! (cd /tmp/shelly_install && makepkg -si --noconfirm); then echo "--------------------------------------------------------------------" echo "Failed to build and install shelly. You can try running it manually:" echo "cd /tmp/shelly_install && makepkg -si --noconfirm" echo "--------------------------------------------------------------------" - exit 1 # exit with an error + record_failure "Shelly bootstrap (Arch-only)" "failed to build shelly with makepkg" fi cd "$PreviousWD" rm -rf /tmp/shelly_install @@ -84,198 +111,241 @@ fi # Install prerequisites if command -v shelly >/dev/null; then echo "Shelly detected. Installing prerequisites" - shelly install standard git zsh curl wget libnewt rsync whiptail --upgrade --no-confirm + shelly install standard git zsh curl wget libnewt rsync gum --upgrade --no-confirm || + record_failure "Prerequisites (shelly)" "installing base packages via shelly failed" fi if command -v apt >/dev/null; then echo "apt detected. Installing prerequisites" - sudo apt update - sudo apt full-upgrade -y - sudo apt install git zsh curl wget whiptail rsync -y + sudo apt update || record_failure "Prerequisites (apt)" "apt update failed" + sudo apt full-upgrade -y || record_failure "Prerequisites (apt)" "apt full-upgrade failed" + sudo apt install git zsh curl wget rsync gum -y || + record_failure "Prerequisites (apt)" "apt install of base packages failed" fi -# Ensure whiptail is installed -if ! command -v whiptail >/dev/null; then - echo "whiptail is not installed. Installing it now..." +# Ensure gum is installed +if ! command -v gum >/dev/null; then + echo "gum is not installed. Installing it now..." if command -v shelly >/dev/null; then - echo "shelly detected. Installing whiptail" - shelly install standard whiptail --no-confirm || { - echo "Failed to install whiptail. Exiting." + echo "shelly detected. Installing gum" + shelly install standard gum --no-confirm || { + echo "Failed to install gum. Exiting." exit 1 } fi if command -v apt >/dev/null; then - echo "apt detected. Installing whiptail" - sudo apt install whiptail -y || { - echo "Failed to install whiptail. Exiting." + echo "apt detected. Installing gum" + sudo apt install gum -y || { + echo "Failed to install gum. Exiting." exit 1 } fi fi -# Options for the whiptail menu +# Options for the gum menu OPTIONS=( - 1 "Run zsh setup script" OFF - 2 "Run fish setup script" ON - 3 "Run LazyVim setup script" OFF - 4 "Install Docker" OFF - 5 "Install Standard Packages (Shelly)" ON - 6 "Install AUR Packages (Shelly)" ON - 7 "Install affinity with GUI" OFF - 8 "Run bat setup script" ON + "Run zsh setup script" + "Run fish setup script" + "Run LazyVim setup script" + "Install Docker" + "Install Standard Packages (Shelly)" + "Install AUR Packages (Shelly)" + "Install affinity with GUI" + "Run bat setup script" ) -CHOICE=$(whiptail --title "Installation Options" --checklist \ - "Choose components to install:" 20 78 10 \ - "${OPTIONS[@]}" 3>&1 1>&2 2>&3) - -exitstatus=$? -if [ $exitstatus = 0 ]; then - echo "User selected: $CHOICE" -else +CHOICE=$(gum_tty choose --no-limit --height 14 \ + --header "Tab = select, Enter = confirm:" \ + --selected "Run fish setup script,Install Standard Packages (Shelly),Install AUR Packages (Shelly),Run bat setup script" \ + "${OPTIONS[@]}") || { echo "User cancelled installation." exit 1 -fi +} + +echo "User selected:" +echo "$CHOICE" # Fail on any command. set -euo pipefail -# Process selected options -for selection in $CHOICE; do - clean_selection=$(echo "$selection" | tr -d '"') - case $clean_selection in - "1") +# Process selected options in menu order +while IFS= read -r selection; do + # Skip options the user did not select + grep -qxF "$selection" <<<"$CHOICE" || continue + case "$selection" in + "Run zsh setup script") echo "Running zsh setup script..." # Runs local script unless it does not exist or fails if [[ -f "zsh.sh" ]]; then echo "Found local script, running..." - bash zsh.sh --skip-watermark + bash zsh.sh --skip-watermark || + record_failure "Run zsh setup script" "zsh.sh exited with status $?" else - curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/zsh.sh | bash -s -- --skip-watermark + curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/zsh.sh | bash -s -- --skip-watermark || + record_failure "Run zsh setup script" "downloaded zsh.sh exited with status $?" fi ;; - "2") + "Run fish setup script") echo "Running fish setup script..." # Runs local script unless it does not exist or fails if [[ -f "fish.sh" ]]; then echo "Found local script, running..." - bash fish.sh --skip-watermark + bash fish.sh --skip-watermark || + record_failure "Run fish setup script" "fish.sh exited with status $?" else - curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/fish.sh | bash -s -- --skip-watermark + curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/fish.sh | bash -s -- --skip-watermark || + record_failure "Run fish setup script" "downloaded fish.sh exited with status $?" fi ;; - "3") + "Run LazyVim setup script") echo "Running LazyVim setup script..." # Runs local script unless it does not exist or fails if [[ -f "LazyVim.sh" ]]; then echo "Found local script, running..." - bash LazyVim.sh + bash LazyVim.sh || + record_failure "Run LazyVim setup script" "LazyVim.sh exited with status $?" else - curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/LazyVim.sh | bash + curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/LazyVim.sh | bash || + record_failure "Run LazyVim setup script" "downloaded LazyVim.sh exited with status $?" fi ;; - "4") + "Install Docker") echo "Installing Docker..." if ! command -v docker >/dev/null; then echo "docker is NOT installed. Installing..." - curl -fsSL https://get.docker.com | sh - sudo usermod -aG docker "$USER" + curl -fsSL https://get.docker.com | sh || + record_failure "Install Docker" "docker installer script exited with status $?" + sudo usermod -aG docker "$USER" || + record_failure "Install Docker" "adding $USER to the docker group failed" else - sudo usermod -aG docker "$USER" + sudo usermod -aG docker "$USER" || + record_failure "Install Docker" "adding $USER to the docker group failed" echo "Docker is already installed." echo "+ sleep 10" && sleep 10 fi ;; - "5") + "Install Standard Packages (Shelly)") echo "Installing Standard Packages via Shelly backup..." # Check if shelly binary is installed if ! command -v shelly >/dev/null; then - echo "Cannot proceed: shelly binary not found" - exit 1 # exit with an error - fi + echo "Cannot proceed: shelly binary not found (Arch-only)" + record_failure "Install Standard Packages (Shelly)" "shelly binary not found (Arch-only)" # Install standard packages from shelly backup # Runs local script unless it does not exist or fails - if [[ -f "./configs/shelly-standard.toml" ]]; then + elif [[ -f "./configs/shelly-standard.toml" ]]; then echo "Found local backup" - shelly backup --import --name shelly-standard --directory ./configs --no-confirm + shelly backup --import --name shelly-standard --directory ./configs --no-confirm || + record_failure "Install Standard Packages (Shelly)" "shelly backup import exited with status $?" elif ! curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/configs/shelly-standard.toml -o /tmp/shelly-standard.toml; then echo "--------------------------------------------------------------------" echo "Failed to download shelly backup. You can try running it manually:" echo "curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/configs/shelly-standard.toml -o /tmp/shelly-standard.toml" echo "--------------------------------------------------------------------" + record_failure "Install Standard Packages (Shelly)" "failed to download shelly-standard.toml" echo "+ sleep 10" && sleep 10 elif ! shelly backup --import --name shelly-standard --directory /tmp --no-confirm; then echo "--------------------------------------------------------------------" echo "Failed to install Standard packages. You can try running it manually:" echo "shelly backup --import --name shelly-standard --directory /tmp --no-confirm" echo "--------------------------------------------------------------------" + record_failure "Install Standard Packages (Shelly)" "shelly backup import failed" echo "+ sleep 10" && sleep 10 fi ;; - "6") + "Install AUR Packages (Shelly)") echo "Installing AUR Packages via Shelly backup..." # Check for shelly before installing AUR packages if ! command -v shelly >/dev/null; then - echo "Cannot proceed: shelly binary not found" - exit 1 # Exit with an error - fi + echo "Cannot proceed: shelly binary not found (Arch-only)" + record_failure "Install AUR Packages (Shelly)" "shelly binary not found (Arch-only)" # Install AUR packages from shelly backup # Runs local script unless it does not exist or fails - if [[ -f "./configs/shelly-aur.toml" ]]; then + elif [[ -f "./configs/shelly-aur.toml" ]]; then echo "Found local backup" - shelly backup --import --name shelly-aur --directory ./configs --no-confirm + shelly backup --import --name shelly-aur --directory ./configs --no-confirm || + record_failure "Install AUR Packages (Shelly)" "shelly backup import exited with status $?" elif ! curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/configs/shelly-aur.toml -o /tmp/shelly-aur.toml; then echo "--------------------------------------------------------------------" echo "Failed to download shelly backup. You can try running it manually:" echo "curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/configs/shelly-aur.toml -o /tmp/shelly-aur.toml" echo "--------------------------------------------------------------------" + record_failure "Install AUR Packages (Shelly)" "failed to download shelly-aur.toml" echo "+ sleep 10" && sleep 10 elif ! shelly backup --import --name shelly-aur --directory /tmp --no-confirm; then echo "--------------------------------------------------------------------" echo "Failed to install AUR packages. You can try running it manually:" echo "shelly backup --import --name shelly-aur --directory /tmp --no-confirm" echo "--------------------------------------------------------------------" + record_failure "Install AUR Packages (Shelly)" "shelly backup import failed" echo "+ sleep 10" && sleep 10 fi ;; - "7") + "Install affinity with GUI") echo "Installing GUI dependencies" if command -v shelly >/dev/null; then echo "shelly found" - shelly install standard python-pyqt6 --no-confirm + shelly install standard python-pyqt6 --no-confirm || + record_failure "Install affinity with GUI" "installing python-pyqt6 via shelly failed" fi if command -v dnf >/dev/null; then echo "dnf found" - sudo dnf install python3-pyqt6 + sudo dnf install python3-pyqt6 || + record_failure "Install affinity with GUI" "installing python3-pyqt6 via dnf failed" fi if command -v apt >/dev/null; then echo "apt found" - sudo apt install python3-pyqt6 -y + sudo apt install python3-pyqt6 -y || + record_failure "Install affinity with GUI" "installing python3-pyqt6 via apt failed" fi echo "Install affinity with ryzendew's gui installer" echo "You must manually select to install in the GUI" echo "Github repo: https://github.com/ryzendew/Linux-Affinity-Installer" echo "+ 10 sleep" sleep 10 - curl -sSL https://raw.githubusercontent.com/ryzendew/AffinityOnLinux/refs/heads/main/AffinityScripts/AffinityLinuxInstaller.py | python3 + curl -sSL https://raw.githubusercontent.com/ryzendew/AffinityOnLinux/refs/heads/main/AffinityScripts/AffinityLinuxInstaller.py | python3 || + record_failure "Install affinity with GUI" "affinity installer exited with status $?" ;; - "8") + "Run bat setup script") echo "Running bat setup script..." # Runs local script unless it does not exist or fails if [[ -f "bat.sh" ]]; then echo "Found local script, running..." - bash bat.sh --skip-watermark + bash bat.sh --skip-watermark || + record_failure "Run bat setup script" "bat.sh exited with status $?" else - curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/bat.sh | bash -s -- --skip-watermark + curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/bat.sh | bash -s -- --skip-watermark || + record_failure "Run bat setup script" "downloaded bat.sh exited with status $?" fi ;; *) echo "Invalid option selected: $selection" ;; esac -done +done < <(printf '%s\n' "${OPTIONS[@]}") echo "Installation process complete." + +# Show (and save) what failed - the run itself never aborts on a failed step +if [ "${#FAILED[@]}" -gt 0 ]; then + { + echo "" + echo "================ FAILURE SUMMARY ================" + echo "installbeta.sh finished at $(date '+%F %T') - ${#FAILED[@]} step(s) failed:" + printf ' - %s\n' "${FAILED[@]}" + echo "" + echo "Full console log: $LOG" + echo "Failure report: $REPORT" + echo "===================================================" + } | tee -a "$REPORT" + + if [ "$TTY_OK" = true ] && command -v gum >/dev/null; then + gum_tty pager < "$REPORT" || true + fi +else + echo "All steps completed with no failures." +fi + +exit 0