Strict mode from the start, contextual errors, non-zero exit in installbeta.sh
- set -Eeuo pipefail at the top (was only enabled after the menu, so
package installs and shelly bootstrap ran unchecked); preamble audited
for guarded vs unguarded commands ([ -t 1 ] && ... became an if, clear
is now 'clear || true')
- error_handler now reports exit status, line number and the failing
command, and the ERR trap is installed after strict mode so preamble
failures abort instead of printing a message and continuing
- exit 1 when any step was recorded as failed (was: always exit 0)
- single STAMP shared by LOG and REPORT; both created via mktemp
(predictable /tmp log names + tee -a was the same symlink class)
- local script/config fallbacks resolved via BASH_SOURCE (SCRIPT_DIR),
not the caller's CWD; falls back to remote fetch when piped
- $? captured via rc=$? inside each failure branch (idempotent under
reordering) for all record_failure call sites
- ${1:-} for the flag check, ${SHELL:-} in the fish detection,
tty-guarded fish warning prompt
This commit is contained in:
+90
-47
@@ -1,12 +1,17 @@
|
|||||||
#!/usr/bin/bash
|
#!/usr/bin/bash
|
||||||
|
|
||||||
|
# Strict mode from the very start: every tolerated failure in this script is
|
||||||
|
# an explicit guard (if ! / || record_failure), so preamble steps are checked
|
||||||
|
# too. -E (errtrace) makes the ERR trap fire inside helper functions as well.
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
skip_watermark=false
|
skip_watermark=false
|
||||||
if [ "$1" = "--skip-watermark" ]; then
|
if [ "${1:-}" = "--skip-watermark" ]; then
|
||||||
skip_watermark=true
|
skip_watermark=true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Detect fish shell and warn user to run with bash instead (bash-only syntax)
|
# 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 [ -n "${FISH_VERSION:-}" ] || case "${SHELL:-}" in *fish*) ;; *) false ;; esac; then
|
||||||
if command -v gum >/dev/null; 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
|
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"
|
echo "Aborted. Please run this script with bash, not fish. e.g.: bash installbeta.sh"
|
||||||
@@ -16,12 +21,14 @@ if [ -n "${FISH_VERSION:-}" ] || case "$SHELL" in *fish*) ;; *) false ;; esac th
|
|||||||
echo "Warning: fish shell detected."
|
echo "Warning: fish shell detected."
|
||||||
echo "This script must be run with bash, not fish (bash-only syntax)."
|
echo "This script must be run with bash, not fish (bash-only syntax)."
|
||||||
echo "Please run it with bash, e.g.: bash installbeta.sh"
|
echo "Please run it with bash, e.g.: bash installbeta.sh"
|
||||||
|
if [ -t 0 ] && [ -e /dev/tty ]; then
|
||||||
read -r -p "Press Enter to continue anyway, or Ctrl+C to cancel..." </dev/tty || true
|
read -r -p "Press Enter to continue anyway, or Ctrl+C to cancel..." </dev/tty || true
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$skip_watermark" = false ]; then
|
if [ "$skip_watermark" = false ]; then
|
||||||
clear
|
clear 2>/dev/null || true
|
||||||
echo '
|
echo '
|
||||||
____ _ _ _ _ _
|
____ _ _ _ _ _
|
||||||
| __ ) _ _ __ _| |_ _(_)_ __ | | ___ | | | ___
|
| __ ) _ _ __ _| |_ _(_)_ __ | | ___ | | | ___
|
||||||
@@ -37,23 +44,32 @@ See the LICENCE for more detail
|
|||||||
'
|
'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Function to display error message
|
# Report errors with context (line + failing command), and only once strict
|
||||||
|
# mode is active so preamble failures abort instead of printing and continuing
|
||||||
function error_handler() {
|
function error_handler() {
|
||||||
|
local rc="$1" line="$2" cmd="$3"
|
||||||
set +x
|
set +x
|
||||||
echo -e "An error occurred. Please check the output above for details."
|
echo ""
|
||||||
|
echo "An error occurred (exit status $rc) at line $line while running:"
|
||||||
|
echo " $cmd"
|
||||||
|
echo "Please check the output above for details."
|
||||||
}
|
}
|
||||||
|
|
||||||
# Trap errors
|
# Trap errors (after set -euo pipefail above)
|
||||||
trap error_handler ERR
|
trap 'error_handler "$?" "$LINENO" "$BASH_COMMAND"' ERR
|
||||||
|
|
||||||
# --- Failure handling & full console log ------------------------------------
|
# --- Failure handling & full console log ------------------------------------
|
||||||
# Everything from here on is teed to a log file in /tmp, and Arch-only step
|
# 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.
|
# failures are recorded instead of aborting the rest of the installation.
|
||||||
TTY_OK=false
|
TTY_OK=false
|
||||||
[ -t 1 ] && TTY_OK=true
|
if [ -t 1 ]; then
|
||||||
|
TTY_OK=true
|
||||||
|
fi
|
||||||
|
|
||||||
LOG="/tmp/installbeta-$(date +%Y%m%d-%H%M%S).log"
|
# One timestamp for both files, mktemp so the names are not predictable
|
||||||
REPORT="/tmp/installbeta-failures-$(date +%Y%m%d-%H%M%S).txt"
|
STAMP="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
LOG="$(mktemp "/tmp/installbeta-$STAMP-XXXXXX.log")"
|
||||||
|
REPORT="$(mktemp "/tmp/installbeta-failures-$STAMP-XXXXXX.txt")"
|
||||||
FAILED=()
|
FAILED=()
|
||||||
|
|
||||||
exec > >(tee -a "$LOG") 2>&1
|
exec > >(tee -a "$LOG") 2>&1
|
||||||
@@ -79,6 +95,14 @@ record_failure() {
|
|||||||
WORK_DIR="$(mktemp -d)"
|
WORK_DIR="$(mktemp -d)"
|
||||||
trap 'rm -rf "$WORK_DIR"' EXIT
|
trap 'rm -rf "$WORK_DIR"' EXIT
|
||||||
|
|
||||||
|
# Resolve where this script lives so local script/config fallbacks do not
|
||||||
|
# depend on the caller's current directory. Empty when piped (curl | bash).
|
||||||
|
if [ -n "${BASH_SOURCE[0]:-}" ] && [ -f "${BASH_SOURCE[0]}" ]; then
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
else
|
||||||
|
SCRIPT_DIR=""
|
||||||
|
fi
|
||||||
|
|
||||||
# Install shelly as a dependency if not present (Arch-based)
|
# Install shelly as a dependency if not present (Arch-based)
|
||||||
if command -v pacman >/dev/null; then
|
if command -v pacman >/dev/null; then
|
||||||
# Install build prerequisites for shelly
|
# Install build prerequisites for shelly
|
||||||
@@ -217,9 +241,6 @@ fi
|
|||||||
echo "User selected:"
|
echo "User selected:"
|
||||||
echo "$CHOICE"
|
echo "$CHOICE"
|
||||||
|
|
||||||
# Fail on any command.
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Process selected options in menu order
|
# Process selected options in menu order
|
||||||
while IFS= read -r selection; do
|
while IFS= read -r selection; do
|
||||||
# Skip options the user did not select
|
# Skip options the user did not select
|
||||||
@@ -227,38 +248,50 @@ while IFS= read -r selection; do
|
|||||||
case "$selection" in
|
case "$selection" in
|
||||||
"Run zsh setup script")
|
"Run zsh setup script")
|
||||||
echo "Running zsh setup script..."
|
echo "Running zsh setup script..."
|
||||||
# Runs local script unless it does not exist or fails
|
# Runs local script unless it does not exist (SCRIPT_DIR, not CWD)
|
||||||
if [[ -f "zsh.sh" ]]; then
|
if [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/zsh.sh" ]; then
|
||||||
echo "Found local script, running..."
|
echo "Found local script, running..."
|
||||||
bash zsh.sh --skip-watermark ||
|
bash "$SCRIPT_DIR/zsh.sh" --skip-watermark || {
|
||||||
record_failure "Run zsh setup script" "zsh.sh exited with status $?"
|
rc=$?
|
||||||
|
record_failure "Run zsh setup script" "zsh.sh exited with status $rc"
|
||||||
|
}
|
||||||
else
|
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 $?"
|
rc=$?
|
||||||
|
record_failure "Run zsh setup script" "downloaded zsh.sh exited with status $rc"
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
"Run fish setup script")
|
"Run fish setup script")
|
||||||
echo "Running fish setup script..."
|
echo "Running fish setup script..."
|
||||||
# Runs local script unless it does not exist or fails
|
# Runs local script unless it does not exist (SCRIPT_DIR, not CWD)
|
||||||
if [[ -f "fish.sh" ]]; then
|
if [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/fish.sh" ]; then
|
||||||
echo "Found local script, running..."
|
echo "Found local script, running..."
|
||||||
bash fish.sh --skip-watermark ||
|
bash "$SCRIPT_DIR/fish.sh" --skip-watermark || {
|
||||||
record_failure "Run fish setup script" "fish.sh exited with status $?"
|
rc=$?
|
||||||
|
record_failure "Run fish setup script" "fish.sh exited with status $rc"
|
||||||
|
}
|
||||||
else
|
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 $?"
|
rc=$?
|
||||||
|
record_failure "Run fish setup script" "downloaded fish.sh exited with status $rc"
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
"Run LazyVim setup script")
|
"Run LazyVim setup script")
|
||||||
echo "Running LazyVim setup script..."
|
echo "Running LazyVim setup script..."
|
||||||
# Runs local script unless it does not exist or fails
|
# Runs local script unless it does not exist (SCRIPT_DIR, not CWD)
|
||||||
if [[ -f "LazyVim.sh" ]]; then
|
if [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/LazyVim.sh" ]; then
|
||||||
echo "Found local script, running..."
|
echo "Found local script, running..."
|
||||||
bash LazyVim.sh ||
|
bash "$SCRIPT_DIR/LazyVim.sh" || {
|
||||||
record_failure "Run LazyVim setup script" "LazyVim.sh exited with status $?"
|
rc=$?
|
||||||
|
record_failure "Run LazyVim setup script" "LazyVim.sh exited with status $rc"
|
||||||
|
}
|
||||||
else
|
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 $?"
|
rc=$?
|
||||||
|
record_failure "Run LazyVim setup script" "downloaded LazyVim.sh exited with status $rc"
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
"Install Docker")
|
"Install Docker")
|
||||||
@@ -287,11 +320,13 @@ while IFS= read -r selection; do
|
|||||||
echo "Cannot proceed: shelly binary not found (Arch-only)"
|
echo "Cannot proceed: shelly binary not found (Arch-only)"
|
||||||
record_failure "Install Standard Packages (Shelly)" "shelly binary not found (Arch-only)"
|
record_failure "Install Standard Packages (Shelly)" "shelly binary not found (Arch-only)"
|
||||||
# Install standard packages from shelly backup
|
# Install standard packages from shelly backup
|
||||||
# Runs local script unless it does not exist or fails
|
# Runs local script unless it does not exist (SCRIPT_DIR, not CWD)
|
||||||
elif [[ -f "./configs/shelly-standard.toml" ]]; then
|
elif [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/configs/shelly-standard.toml" ]; then
|
||||||
echo "Found local backup"
|
echo "Found local backup"
|
||||||
shelly backup --import --name shelly-standard --directory ./configs --no-confirm ||
|
shelly backup --import --name shelly-standard --directory "$SCRIPT_DIR/configs" --no-confirm || {
|
||||||
record_failure "Install Standard Packages (Shelly)" "shelly backup import exited with status $?"
|
rc=$?
|
||||||
|
record_failure "Install Standard Packages (Shelly)" "shelly backup import exited with status $rc"
|
||||||
|
}
|
||||||
elif ! curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/configs/shelly-standard.toml -o "$WORK_DIR/shelly-standard.toml"; then
|
elif ! curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/configs/shelly-standard.toml -o "$WORK_DIR/shelly-standard.toml"; then
|
||||||
echo "--------------------------------------------------------------------"
|
echo "--------------------------------------------------------------------"
|
||||||
echo "Failed to download shelly backup. You can try running it manually:"
|
echo "Failed to download shelly backup. You can try running it manually:"
|
||||||
@@ -315,11 +350,13 @@ while IFS= read -r selection; do
|
|||||||
echo "Cannot proceed: shelly binary not found (Arch-only)"
|
echo "Cannot proceed: shelly binary not found (Arch-only)"
|
||||||
record_failure "Install AUR Packages (Shelly)" "shelly binary not found (Arch-only)"
|
record_failure "Install AUR Packages (Shelly)" "shelly binary not found (Arch-only)"
|
||||||
# Install AUR packages from shelly backup
|
# Install AUR packages from shelly backup
|
||||||
# Runs local script unless it does not exist or fails
|
# Runs local script unless it does not exist (SCRIPT_DIR, not CWD)
|
||||||
elif [[ -f "./configs/shelly-aur.toml" ]]; then
|
elif [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/configs/shelly-aur.toml" ]; then
|
||||||
echo "Found local backup"
|
echo "Found local backup"
|
||||||
shelly backup --import --name shelly-aur --directory ./configs --no-confirm ||
|
shelly backup --import --name shelly-aur --directory "$SCRIPT_DIR/configs" --no-confirm || {
|
||||||
record_failure "Install AUR Packages (Shelly)" "shelly backup import exited with status $?"
|
rc=$?
|
||||||
|
record_failure "Install AUR Packages (Shelly)" "shelly backup import exited with status $rc"
|
||||||
|
}
|
||||||
elif ! curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/configs/shelly-aur.toml -o "$WORK_DIR/shelly-aur.toml"; then
|
elif ! curl -fsSL https://raw.githubusercontent.com/alvinlollo/Single-install-script/refs/heads/main/configs/shelly-aur.toml -o "$WORK_DIR/shelly-aur.toml"; then
|
||||||
echo "--------------------------------------------------------------------"
|
echo "--------------------------------------------------------------------"
|
||||||
echo "Failed to download shelly backup. You can try running it manually:"
|
echo "Failed to download shelly backup. You can try running it manually:"
|
||||||
@@ -367,14 +404,18 @@ while IFS= read -r selection; do
|
|||||||
;;
|
;;
|
||||||
"Run bat setup script")
|
"Run bat setup script")
|
||||||
echo "Running bat setup script..."
|
echo "Running bat setup script..."
|
||||||
# Runs local script unless it does not exist or fails
|
# Runs local script unless it does not exist (SCRIPT_DIR, not CWD)
|
||||||
if [[ -f "bat.sh" ]]; then
|
if [ -n "$SCRIPT_DIR" ] && [ -f "$SCRIPT_DIR/bat.sh" ]; then
|
||||||
echo "Found local script, running..."
|
echo "Found local script, running..."
|
||||||
bash bat.sh --skip-watermark ||
|
bash "$SCRIPT_DIR/bat.sh" --skip-watermark || {
|
||||||
record_failure "Run bat setup script" "bat.sh exited with status $?"
|
rc=$?
|
||||||
|
record_failure "Run bat setup script" "bat.sh exited with status $rc"
|
||||||
|
}
|
||||||
else
|
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 $?"
|
rc=$?
|
||||||
|
record_failure "Run bat setup script" "downloaded bat.sh exited with status $rc"
|
||||||
|
}
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -401,8 +442,10 @@ if [ "${#FAILED[@]}" -gt 0 ]; then
|
|||||||
if [ "$TTY_OK" = true ] && command -v gum >/dev/null; then
|
if [ "$TTY_OK" = true ] && command -v gum >/dev/null; then
|
||||||
gum_tty pager < "$REPORT" || true
|
gum_tty pager < "$REPORT" || true
|
||||||
fi
|
fi
|
||||||
else
|
|
||||||
echo "All steps completed with no failures."
|
# Non-zero so callers and CI can detect the failed run
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "All steps completed with no failures."
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
Reference in New Issue
Block a user