#!/bin/bash set -eo pipefail # Exit on error, treat unset variables as an error (implicitly), and propagate pipeline errors # --- Configuration --- # These can be overridden by environment variables if needed : "${GIT_REPO_URL:=https://github.com/xPathin/windsurf-bin-arch.git}" : "${CLONED_REPO_DIR_NAME:=windsurf-bin-arch}" # Local directory name for the cloned repo : "${PKGBUILD_SUBDIR:=package}" # Subdirectory within the repo containing the PKGBUILD : "${WINDSURF_STANDARD_PKG_NAME:=windsurf-bin}" : "${WINDSURF_ELECTRON_PKG_NAME:=windsurf-bin-electron-latest}" # --- Helper Functions --- log() { echo "[INFO] $(date +'%T') - $1" } error_exit() { echo "[ERROR] $(date +'%T') - $1" >&2 # Cleanup is handled by trap exit 1 } check_command() { command -v "$1" >/dev/null 2>&1 || error_exit "Required command '$1' not found. Please install it." } get_installed_version() { local pkg_name="$1" if pacman -Q "$pkg_name" &>/dev/null; then pacman -Q "$pkg_name" | awk '{print $2}' else echo "" # Not installed fi } get_pkgbuild_version() { local pkgbuild_file="$1" if [ ! -f "$pkgbuild_file" ]; then error_exit "PKGBUILD file not found at $pkgbuild_file" fi # Source PKGBUILD in a subshell to avoid polluting current environment ( # shellcheck source=/dev/null source "$pkgbuild_file" if [ -z "${pkgver:-}" ] || [ -z "${pkgrel:-}" ]; then error_exit "pkgver or pkgrel not defined in $pkgbuild_file" fi echo "${pkgver}-${pkgrel}" ) } # --- Pre-flight Checks --- log "Performing pre-flight checks..." check_command "git" check_command "pacman" check_command "makepkg" check_command "curl" # Useful if script is fetched via curl, or PKGBUILDs need it # --- Cleanup and Signal Handling --- cleanup_action() { local dir_to_clean="$1" local reason="$2" if [ -n "$dir_to_clean" ] && [ -d "$dir_to_clean" ]; then log "Cleaning up temporary directory: $dir_to_clean (Reason: $reason)" # Attempt to return to initial CWD. If it fails, proceed with rm from current location. (cd "$INITIAL_CWD" && rm -rf "$dir_to_clean") || rm -rf "$dir_to_clean" log "Cleanup finished for $dir_to_clean." elif [ -n "$reason" ] && [ "$reason" != "Normal Exit" ]; then log "No temporary directory to clean or already cleaned ('$dir_to_clean' was not a valid directory)." fi } # Trap for normal exit (will also be triggered by set -e exits if not handled by signal traps) trap 'cleanup_action "$TEMP_DIR" "Normal Exit"; TEMP_DIR=""' EXIT # Trap for specific signals handle_signal() { local signal_name="$1" # Unset the general EXIT trap to prevent double cleanup if we exit via kill trap - EXIT cleanup_action "$TEMP_DIR" "$signal_name" TEMP_DIR="" # Mark as cleaned log "Exiting due to $signal_name." trap - "$signal_name" # Restore default handler for the signal kill -s "$signal_name" "$$" # Re-send the signal to self to exit with default action/code } trap 'handle_signal INT' SIGINT trap 'handle_signal TERM' SIGTERM # --- Main Script --- INITIAL_CWD=$(pwd) TEMP_DIR="" # Initialize TEMP_DIR for cleanup traps # 1. Determine Installation Choice TARGET_PKG_NAME="" INSTALL_TYPE_FRIENDLY_NAME="" # Check environment variable WINDSURF_INSTALL_CHOICE # Values: "standard", "electron", or empty/unset for prompt USER_CHOICE="${WINDSURF_INSTALL_CHOICE:-}" if [ -z "$USER_CHOICE" ]; then # Redirect stdin for this entire block from /dev/tty { echo "--------------------------------------------------------------------" echo " Windsurf Installer" echo "--------------------------------------------------------------------" echo "Please choose which Windsurf package to install:" echo " 1) Windsurf (Standard - ${WINDSURF_STANDARD_PKG_NAME})" echo " 2) Windsurf (Electron - ${WINDSURF_ELECTRON_PKG_NAME})" echo "--------------------------------------------------------------------" # Explicitly print prompt to /dev/tty and read from /dev/tty (via block redirection) printf "Enter your choice (1 or 2, default: 1): " >&2 # Print prompt to stderr, which should be tty read -r choice_num # read from stdin of this block, which is /dev/tty choice_num=${choice_num:-1} # Default to 1 if user presses Enter case "$choice_num" in 1) USER_CHOICE="standard" ;; 2) USER_CHOICE="electron" ;; *) # error_exit already prints to stderr error_exit "Invalid choice. Exiting." ;; esac } &2 read -r reinstall_choice &2 read -r upgrade_choice &2 read -r install_new_choice