170 lines
5.4 KiB
Bash
170 lines
5.4 KiB
Bash
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
# ====================== Defaults & Args ======================
|
|
WITH_TIDE=0
|
|
KEEP_PROMPT=0
|
|
VERBOSE=0
|
|
NO_PLUGINS=0
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--with-tide) WITH_TIDE=1 ;;
|
|
--keep-prompt) KEEP_PROMPT=1 ;;
|
|
--verbose) VERBOSE=1 ;;
|
|
--no-plugins) NO_PLUGINS=1 ;;
|
|
--) shift; break ;;
|
|
*) echo "Unknown option: $1"; exit 1 ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
# Default plugin set (safe; no prompt change)
|
|
PLUGINS=("jethrokuan/z" "jorgebucaran/nvm.fish")
|
|
if [[ $WITH_TIDE -eq 1 ]]; then
|
|
PLUGINS+=("ilancosman/tide")
|
|
fi
|
|
|
|
log() { echo -e "• $*"; }
|
|
ok() { echo -e "✓ $*"; }
|
|
warn(){ echo -e "! $*" >&2; }
|
|
|
|
# ====================== Progress Bar (single line) ======================
|
|
padright() { printf "%-28s" "$1"; }
|
|
draw_bar() {
|
|
local cur="$1" total="$2" label="$3" width=40
|
|
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"
|
|
}
|
|
|
|
# ====================== Platform Detect ======================
|
|
detect_platform() {
|
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
OS="macos"; PKG_MGR="brew"
|
|
if ! command -v brew &>/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"
|
|
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})"
|
|
}
|
|
|
|
# ====================== Debian repo/key ======================
|
|
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
|
|
}
|
|
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"
|
|
}
|
|
|
|
# ====================== Fish install/update ======================
|
|
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"
|
|
}
|
|
update_fish_if_available() {
|
|
log "Checking Fish updates…"
|
|
case "$PKG_MGR" in
|
|
apt) sudo apt update; apt list --upgradable 2>/dev/null | grep -q "^fish/" && sudo apt install -y fish || true ;;
|
|
dnf|yum) sudo "$PKG_MGR" check-update || true; "$PKG_MGR" list updates | grep -q "^fish" && sudo "$PKG_MGR" update -y fish || true ;;
|
|
pacman) sudo pacman -Sy --noconfirm; pacman -Qu | grep -q "^fish" && sudo pacman -S --noconfirm fish || true ;;
|
|
brew) brew update; brew outdated | grep -q "^fish" && brew upgrade fish || true ;;
|
|
esac
|
|
ok "Fish up to date"
|
|
}
|
|
|
|
# ====================== Fisher & Plugins ======================
|
|
ensure_fisher() {
|
|
# install Fisher quietly and idempotently
|
|
if fish -c 'functions -q fisher' </dev/null >/dev/null 2>&1; then
|
|
ok "Fisher already present"
|
|
return
|
|
fi
|
|
log "Installing Fisher…"
|
|
fish -c 'curl -sL https://git.io/fisher | source && fisher install jorgebucaran/fisher' </dev/null >/dev/null 2>&1
|
|
ok "Fisher installed"
|
|
}
|
|
|
|
install_plugins() {
|
|
[[ $NO_PLUGINS -eq 1 ]] && { ok "Skipping plugins (per flag)"; return; }
|
|
|
|
local total=${#PLUGINS[@]}
|
|
[[ $total -eq 0 ]] && { ok "No plugins requested"; return; }
|
|
|
|
if [[ $VERBOSE -eq 1 ]]; then
|
|
for p in "${PLUGINS[@]}"; do
|
|
echo "Installing (verbose): $p"
|
|
fish -c "fisher install $p" </dev/null
|
|
done
|
|
ok "Plugins installed"
|
|
return
|
|
fi
|
|
|
|
local i=0
|
|
for p in "${PLUGINS[@]}"; do
|
|
i=$((i+1))
|
|
draw_bar "$((i-1))" "$total" "$p"
|
|
# run install in background and animate until it exits
|
|
( fish -c "fisher install $p" </dev/null >/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"
|
|
|
|
# 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
|
|
}
|
|
|
|
# ====================== Main ======================
|
|
detect_platform
|
|
install_gpg_if_needed
|
|
if command -v fish &>/dev/null; then
|
|
ok "Fish already installed"
|
|
update_fish_if_available
|
|
else
|
|
install_fish
|
|
fi
|
|
ensure_fisher
|
|
install_plugins
|
|
ok "Fish + Fisher + plugins ready on ${OS}" |