From 9d4089f515b3db34b2b6d1819b2346ef8942ec84 Mon Sep 17 00:00:00 2001 From: Ade Thompson Date: Sat, 9 Aug 2025 16:59:55 +0100 Subject: [PATCH] Amended --- fish_installer.sh | 369 ++++++++++++++++++---------------------------- 1 file changed, 146 insertions(+), 223 deletions(-) diff --git a/fish_installer.sh b/fish_installer.sh index 7f067b9..e632b4b 100644 --- a/fish_installer.sh +++ b/fish_installer.sh @@ -1,261 +1,184 @@ #!/bin/bash -set -euo pipefail +set -e -# ====================== Flags ====================== -WITH_TIDE=0 -KEEP_PROMPT=0 -REMOVE_TIDE=0 -VERBOSE=0 -NO_PLUGINS=0 -UPDATE_MODE="prompt" # prompt | yes | no - -while [[ $# -gt 0 ]]; do - case "$1" in - --with-tide) WITH_TIDE=1 ;; - --keep-prompt) KEEP_PROMPT=1 ;; - --remove-tide) REMOVE_TIDE=1 ;; - --verbose) VERBOSE=1 ;; - --no-plugins) NO_PLUGINS=1 ;; - --update-check) UPDATE_MODE="yes" ;; - --no-update-check) UPDATE_MODE="no" ;; - --) shift; break ;; - *) echo "Unknown option: $1"; exit 1 ;; - esac - shift -done - -# Default plugin set (safe; no prompt change) -PLUGINS=("jethrokuan/z" "jorgebucaran/nvm.fish") -[[ $WITH_TIDE -eq 1 ]] && PLUGINS+=("ilancosman/tide") - -# ====================== UI Helpers ====================== -log() { echo -e "• $*"; } -ok() { echo -e "✓ $*"; } -warn(){ echo -e "! $*" >&2; } - -padright() { printf "%-28s" "$1"; } -draw_bar() { - local cur="$1" total="$2" label="$3" width=40 - (( total == 0 )) && total=1 - local percent=$(( cur * 100 / total )) - (( percent > 100 )) && percent=100 - local filled=$(( width * cur / total )) - (( filled > width )) && filled=$width - local empty=$(( width - filled )) - printf "\rInstalling: %s [%s%s] %3d%%" \ - "$(padright "$label")" \ - "$(printf '%0.s#' $(seq 1 $filled))" \ - "$(printf '%0.s.' $(seq 1 $empty))" \ - "$percent" -} - -prompt_yn_tty() { - local prompt="${1:-Proceed (y/N): }" - local d="${2:-N}" ans="" - if [ -r /dev/tty ] && [ -w /dev/tty ]; then - read -r -p "$prompt" ans /dev/null; then - log "Installing Homebrew…" - /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile - eval "$(/opt/homebrew/bin/brew shellenv)" - ok "Homebrew installed" + if [[ "$OSTYPE" == "darwin"* ]]; then + OS="macos"; PKG_MGR="brew" + if ! command -v brew &>/dev/null; then + echo "🍺 Installing Homebrew..." + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> ~/.zprofile + eval "$(/opt/homebrew/bin/brew shellenv)" + fi + elif command -v apt &>/dev/null; then + OS="debian"; PKG_MGR="apt" + elif command -v dnf &>/dev/null; then + OS="rhel"; PKG_MGR="dnf" + elif command -v yum &>/dev/null; then + OS="rhel"; PKG_MGR="yum" + elif command -v pacman &>/dev/null; then + OS="arch"; PKG_MGR="pacman" + else + echo "❌ Unsupported platform"; exit 1 fi - elif command -v apt &>/dev/null; then OS="debian"; PKG_MGR="apt" - elif command -v dnf &>/dev/null; then OS="rhel"; PKG_MGR="dnf" - elif command -v yum &>/dev/null; then OS="rhel"; PKG_MGR="yum" - elif command -v pacman &>/dev/null; then OS="arch"; PKG_MGR="pacman" - else warn "Unsupported platform"; exit 1; fi - ok "Detected ${OS} (${PKG_MGR})" + echo "✓ Detected $OS ($PKG_MGR)" } -# ====================== Debian repo/key ====================== +# 🔐 Install gpg if needed (Debian/Ubuntu) install_gpg_if_needed() { - if [[ "${OS}" == "debian" ]] && ! command -v gpg &>/dev/null; then - log "Installing gnupg…" - sudo apt update && sudo apt install -y gnupg - ok "gnupg installed" - fi + if [[ "$OS" == "debian" ]] && ! command -v gpg &>/dev/null; then + echo "🔑 Installing gpg..." + sudo apt update && sudo apt install -y gnupg + fi } + +# 📦 Add Fish repo (Debian/Ubuntu) add_fish_repo_debian() { - log "Adding Fish repo (Debian)…" - echo 'deb http://download.opensuse.org/repositories/shells:/fish:/release:/4/Debian_12/ /' \ - | sudo tee /etc/apt/sources.list.d/fish.list >/dev/null - curl -fsSL https://download.opensuse.org/repositories/shells:fish:release:4/Debian_12/Release.key \ - | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/fish.gpg >/dev/null - sudo apt update - ok "Repo added" + echo "• Adding Fish repo..." + echo 'deb http://download.opensuse.org/repositories/shells:/fish:/release:/4/Debian_12/ /' | \ + sudo tee /etc/apt/sources.list.d/fish.list >/dev/null + curl -fsSL https://download.opensuse.org/repositories/shells:fish:release:4/Debian_12/Release.key | \ + gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/fish.gpg > /dev/null + sudo apt update } -# ====================== Fish install/update ====================== +# 🐟 Install Fish shell install_fish() { - log "Installing Fish…" - case "$OS" in - debian) add_fish_repo_debian; sudo apt install -y fish ;; - rhel) sudo "$PKG_MGR" install -y fish ;; - arch) sudo pacman -Sy --noconfirm fish ;; - macos) brew install fish ;; - esac - ok "Fish installed" + echo "• Installing Fish..." + case "$OS" in + debian) add_fish_repo_debian; sudo apt install -y fish ;; + rhel) sudo $PKG_MGR install -y fish ;; + arch) sudo pacman -Sy --noconfirm fish ;; + macos) brew install fish ;; + esac } -should_check_updates() { - case "$UPDATE_MODE" in - yes) return 0 ;; - no) return 1 ;; - prompt) - prompt_yn_tty "Check for Fish updates (may run a repo refresh)? (y/N): " "N" - return $? ;; - esac +# 🔎 Detect if an update seems available (without doing a refresh) +fish_update_available() { + case "$PKG_MGR" in + apt) + # Compare Installed vs Candidate using current cache (no apt update) + local installed candidate + installed="$(dpkg-query -W -f='${Version}\n' fish 2>/dev/null || true)" + candidate="$(apt-cache policy fish 2>/dev/null | awk '/Candidate:/ {print $2}')" + [[ -n "$installed" && -n "$candidate" && "$candidate" != "(none)" && "$candidate" != "$installed" ]] + ;; + dnf|yum) + # Fast check; may contact repos briefly but doesn't install + $PKG_MGR -q check-update fish >/dev/null 2>&1 + [[ $? -eq 100 ]] # 100 = updates available + ;; + pacman) + # No refresh; just check queued upgrades + pacman -Qu 2>/dev/null | grep -q '^fish ' + ;; + brew) + # No brew update; check current outdated list + brew outdated --quiet 2>/dev/null | grep -q '^fish$' + ;; + esac } -update_fish_if_available() { - log "Checking Fish updates…" - case "$PKG_MGR" in - apt) - if should_check_updates; then - sudo apt update - apt list --upgradable 2>/dev/null | grep -q "^fish/" && sudo apt install -y fish || true - else - ok "Skipped update check" - fi - ;; - dnf|yum) - if should_check_updates; then - sudo "$PKG_MGR" check-update || true - "$PKG_MGR" list updates | grep -q "^fish" && sudo "$PKG_MGR" update -y fish || true - else - ok "Skipped update check" - fi - ;; - pacman) - if should_check_updates; then - sudo pacman -Sy --noconfirm - pacman -Qu | grep -q "^fish" && sudo pacman -S --noconfirm fish || true - else - ok "Skipped update check" - fi - ;; - brew) - if should_check_updates; then - brew update - brew outdated | grep -q "^fish" && brew upgrade fish || true - else - ok "Skipped update check" - fi - ;; - esac - ok "Fish up to date" +# ♻️ Update flow (only prompt if an update looks available) +maybe_update_fish() { + echo "• Checking Fish updates…" + if fish_update_available; then + read -rp "A newer Fish appears available. Refresh repos and update now? (y/N): " confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + case "$PKG_MGR" in + apt) + sudo apt update + sudo apt install -y fish && echo "✓ Fish updated" + ;; + dnf|yum) + sudo $PKG_MGR check-update || true + sudo $PKG_MGR update -y fish && echo "✓ Fish updated" + ;; + pacman) + sudo pacman -Sy --noconfirm + sudo pacman -S --noconfirm fish && echo "✓ Fish updated" + ;; + brew) + brew update + brew upgrade fish && echo "✓ Fish updated" + ;; + esac + else + echo "✓ Skipped update" + fi + else + echo "✓ No update detected (based on current cache)" + fi } -# ====================== Fisher & Plugins ====================== -ensure_fisher() { - if fish -c 'functions -q fisher' /dev/null 2>&1; then - ok "Fisher already present" - else - log "Installing Fisher…" - fish -c 'curl -sL https://git.io/fisher | source && fisher install jorgebucaran/fisher' /dev/null 2>&1 - ok "Fisher installed" - fi +# 🎣 Install Fisher +install_fisher() { + if fish -c "functions -q fisher" &>/dev/null; then + echo "✓ Fisher already present" + else + echo "• Installing Fisher..." + # isolate stdin so curl|bash doesn’t leak into fish + fish -c 'curl -sL https://git.io/fisher | source && fisher install jorgebucaran/fisher' /dev/null 2>&1 ) & - pid=$! - while kill -0 "$pid" 2>/dev/null; do - draw_bar "$((i-1))" "$total" "$p" - sleep 0.08 - done - draw_bar "$i" "$total" "$p" - done - echo - ok "Plugins installed" + echo "✓ All requested plugins already installed" fi - fi - - # If Tide installed but user wants to keep default prompt - if [[ $WITH_TIDE -eq 1 && $KEEP_PROMPT -eq 1 ]]; then - log "Keeping default Fish prompt (disabling Tide init)…" - rm -f ~/.config/fish/functions/fish_prompt.fish \ - ~/.config/fish/conf.d/_tide_init.fish 2>/dev/null || true - ok "Default prompt preserved" - fi } -remove_tide_if_requested() { - [[ $REMOVE_TIDE -eq 0 ]] && return +# 🐚 Ask to set Fish as default shell (only if not already) +set_fish_default() { + local fish_path current_shell + fish_path="$(command -v fish)" + current_shell="$(getent passwd "$USER" | cut -d: -f7)" - ensure_fisher # make sure fisher exists so removal works - - # Only remove if installed - if fish -c 'fisher list' /dev/null | grep -Fxq "ilancosman/tide"; then - log "Removing Tide…" - if [[ $VERBOSE -eq 1 ]]; then - fish -c "fisher remove ilancosman/tide" /dev/null 2>&1 + if [[ "$current_shell" == "$fish_path" ]]; then + echo "✓ Fish is already your default shell" + return fi - fi - # Clean any prompt overrides - rm -f ~/.config/fish/functions/fish_prompt.fish \ - ~/.config/fish/conf.d/_tide_init.fish 2>/dev/null || true - ok "Tide removed and default prompt restored" + read -rp "Set Fish as your default shell? (y/N): " confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + if ! grep -q "^$fish_path$" /etc/shells; then + echo "$fish_path" | sudo tee -a /etc/shells >/dev/null + fi + chsh -s "$fish_path" + echo "✓ Fish set as default shell (applies to new sessions)" + else + echo "✓ Keeping current default shell" + fi } -# ====================== Main ====================== +# 🚀 Main flow detect_platform +install_gpg_if_needed if command -v fish &>/dev/null; then - ok "Fish already installed" - update_fish_if_available + echo "✓ Fish already installed" + maybe_update_fish else - install_gpg_if_needed - install_fish + install_fish fi -ensure_fisher +install_fisher install_plugins -remove_tide_if_requested +set_fish_default -ok "Fish + Fisher + plugins ready on ${OS}" \ No newline at end of file +echo "✓ Fish + Fisher + plugins ready on $OS" \ No newline at end of file