184 lines
6.0 KiB
Bash
184 lines
6.0 KiB
Bash
#!/bin/bash
|
||
set -e
|
||
|
||
# 🎯 Detect OS & package manager
|
||
detect_platform() {
|
||
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
|
||
echo "✓ Detected $OS ($PKG_MGR)"
|
||
}
|
||
|
||
# 🔐 Install gpg if needed (Debian/Ubuntu)
|
||
install_gpg_if_needed() {
|
||
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() {
|
||
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
|
||
}
|
||
|
||
# 🐟 Install Fish shell
|
||
install_fish() {
|
||
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
|
||
}
|
||
|
||
# 🔎 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 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
|
||
}
|
||
|
||
# 🎣 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
|
||
fi
|
||
}
|
||
|
||
# 🧩 Install plugins (idempotent)
|
||
install_plugins() {
|
||
local plugins=( jethrokuan/z ilancosman/tide jorgebucaran/nvm.fish )
|
||
local install_list=()
|
||
local installed
|
||
installed="$(fish -c 'fisher list' </dev/null 2>/dev/null || true)"
|
||
for p in "${plugins[@]}"; do
|
||
if ! grep -Fxq "$p" <<<"$installed"; then
|
||
install_list+=("$p")
|
||
fi
|
||
done
|
||
if [[ ${#install_list[@]} -gt 0 ]]; then
|
||
echo "• Installing plugins: ${install_list[*]}"
|
||
fish -c "fisher install ${install_list[*]}" </dev/null
|
||
echo "✓ Plugins installed"
|
||
else
|
||
echo "✓ All requested plugins already installed"
|
||
fi
|
||
}
|
||
|
||
# 🐚 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)"
|
||
|
||
if [[ "$current_shell" == "$fish_path" ]]; then
|
||
echo "✓ Fish is already your default shell"
|
||
return
|
||
fi
|
||
|
||
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 flow
|
||
detect_platform
|
||
install_gpg_if_needed
|
||
|
||
if command -v fish &>/dev/null; then
|
||
echo "✓ Fish already installed"
|
||
maybe_update_fish
|
||
else
|
||
install_fish
|
||
fi
|
||
|
||
install_fisher
|
||
install_plugins
|
||
set_fish_default
|
||
|
||
echo "✓ Fish + Fisher + plugins ready on $OS" |