Debian's 'bat' package is renamed 'batcat' to avoid clashing with an unrelated Debian package. The rename makes .zshrc's 'alias cat=bat' fail. Install upstream bat via cargo instead — gets the real binary at $HOME/.cargo/bin/bat, version-aligned with arch's pacman install. Drop 'bat' from the debian apt install list (no more batcat conflict to work around).
204 lines
No EOL
7.2 KiB
Bash
Executable file
204 lines
No EOL
7.2 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# run_once_20-install-user-packages.sh.tmpl
|
|
# Install zsh, tmux, neovim, fastfetch, plus the modern CLI replacements
|
|
# the .zshrc aliases depend on (bat, btop, eza, fzf, fd, ripgrep, zoxide,
|
|
# starship, lazygit, yt-dlp, etc.)
|
|
#
|
|
# Also: install oh-my-zsh, zsh-autosuggestions, zsh-syntax-highlighting,
|
|
# zsh-history-substring-search.
|
|
#
|
|
# Runs as the unprivileged user, but uses sudo for system packages.
|
|
# =============================================================================
|
|
set -euo pipefail
|
|
|
|
log() { printf '\033[1;34m[packages]\033[0m %s\n' "$*"; }
|
|
die() { printf '\033[1;31m[packages ERROR]\033[0m %s\n' "$*" >&2; exit 1; }
|
|
|
|
USER_HOME="${HOME:-$(eval echo "~$(whoami)")}"
|
|
ZSH_CUSTOM="${ZSH_CUSTOM:-$USER_HOME/.oh-my-zsh/custom}"
|
|
|
|
{{ if eq .os_family "arch" -}}
|
|
# ----------------------------- ARCH ---------------------------------------
|
|
log "pacman -Syu"
|
|
sudo pacman -Syu --noconfirm
|
|
|
|
PACMAN_PKGS=(
|
|
zsh tmux neovim git base-devel
|
|
bat btop htop fastfetch
|
|
eza fzf fd ripgrep zoxide starship
|
|
lazygit yt-dlp jq
|
|
unzip p7zip
|
|
openssh
|
|
)
|
|
|
|
log "installing pacman packages"
|
|
sudo pacman -S --needed --noconfirm "${PACMAN_PKGS[@]}"
|
|
|
|
{{ else if eq .os_family "debian" -}}
|
|
# ----------------------------- DEBIAN --------------------------------------
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
sudo apt-get update -y
|
|
sudo apt-get upgrade -y
|
|
|
|
APT_PKGS=(
|
|
zsh tmux git build-essential
|
|
btop htop fastfetch
|
|
eza fzf fd-find ripgrep zoxide starship
|
|
lazygit yt-dlp jq
|
|
unzip p7zip
|
|
openssh-client
|
|
ca-certificates curl wget
|
|
)
|
|
|
|
log "installing apt packages"
|
|
sudo apt-get install -y --no-install-recommends "${APT_PKGS[@]}"
|
|
|
|
# fd on Debian ships as 'fdfind' to avoid clashing with fd (the dedupe tool).
|
|
# Symlink so .zshrc can find 'fd' on PATH.
|
|
if command -v fdfind >/dev/null 2>&1 && ! command -v fd >/dev/null 2>&1; then
|
|
log "symlinking fdfind -> fd in ~/.local/bin"
|
|
mkdir -p "$USER_HOME/.local/bin"
|
|
ln -sf "$(command -v fdfind)" "$USER_HOME/.local/bin/fd"
|
|
fi
|
|
|
|
# Debian ships 'bat' as 'batcat' due to a name clash with an unrelated
|
|
# package. Install upstream 'bat' via cargo so we get the real binary at
|
|
# $HOME/.cargo/bin/bat. Faster than apt's renamed package, version-aligned
|
|
# with arch's pacman install.
|
|
if command -v cargo >/dev/null 2>&1 && ! command -v bat >/dev/null 2>&1; then
|
|
log "installing bat via cargo (upstream, debian renames it to batcat)"
|
|
cargo install bat --locked 2>&1 | tail -5
|
|
fi
|
|
|
|
# Neovim — install official binary tarball, pinned to a known-good version.
|
|
# Bump NVIM_TARGET_VERSION to upgrade. ~/.local/bin/update-neovim.sh does
|
|
# the same check + download so topgrade can invoke it for upgrades.
|
|
NVIM_TARGET_VERSION="v0.11.4"
|
|
ARCH="$(uname -m)"
|
|
case "$ARCH" in
|
|
x86_64)
|
|
NVIM_TARBALL="nvim-linux64.tar.gz"
|
|
NVIM_EXTRACT_DIR="nvim-linux64"
|
|
;;
|
|
aarch64|arm64)
|
|
NVIM_TARBALL="nvim-linux-arm64.tar.gz"
|
|
NVIM_EXTRACT_DIR="nvim-linux-arm64"
|
|
;;
|
|
*)
|
|
die "unsupported arch for neovim tarball: $ARCH"
|
|
;;
|
|
esac
|
|
|
|
if command -v nvim >/dev/null 2>&1; then
|
|
INSTALLED_VER="$(nvim --version 2>/dev/null | head -1 | awk '{print $2}')"
|
|
if [[ "$INSTALLED_VER" == "$NVIM_TARGET_VERSION" ]]; then
|
|
log "neovim $INSTALLED_VER matches target — skipping"
|
|
NVIM_TARBALL=""
|
|
else
|
|
log "neovim $INSTALLED_VER != target $NVIM_TARGET_VERSION — upgrading"
|
|
fi
|
|
fi
|
|
|
|
if [[ -n "$NVIM_TARBALL" ]]; then
|
|
log "downloading neovim $NVIM_TARGET_VERSION ($NVIM_TARBALL)"
|
|
cd /tmp
|
|
if ! curl -fL --retry 3 \
|
|
"https://github.com/neovim/neovim/releases/download/${NVIM_TARGET_VERSION}/${NVIM_TARBALL}" \
|
|
-o nvim.tar.gz; then
|
|
die "failed to download neovim tarball"
|
|
fi
|
|
sudo rm -rf /opt/nvim-linux* /usr/local/bin/nvim
|
|
sudo tar -xzf nvim.tar.gz -C /opt/
|
|
sudo ln -sf "/opt/${NVIM_EXTRACT_DIR}/bin/nvim" /usr/local/bin/nvim
|
|
rm -f nvim.tar.gz
|
|
fi
|
|
|
|
# Verify neovim is reachable (PATH may need /usr/local/bin explicitly for this run)
|
|
if ! command -v nvim >/dev/null 2>&1 && [[ -x /usr/local/bin/nvim ]]; then
|
|
export PATH="/usr/local/bin:$PATH"
|
|
fi
|
|
|
|
{{ else -}}
|
|
die "unsupported os_family: {{ .os_family }}"
|
|
{{ end -}}
|
|
|
|
# --------------------------- OH-MY-ZSH -------------------------------------
|
|
if [[ ! -d "$USER_HOME/.oh-my-zsh" ]]; then
|
|
log "installing oh-my-zsh (unattended)"
|
|
RUNZSH=no CHSH=no sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
|
|
else
|
|
log "oh-my-zsh already installed"
|
|
fi
|
|
|
|
# zsh plugins (loaded by .zshrc)
|
|
install_zsh_plugin() {
|
|
local repo="$1" target="$2"
|
|
if [[ -d "$target" ]]; then
|
|
log "plugin already present: $target"
|
|
else
|
|
log "cloning plugin: $repo"
|
|
git clone --depth 1 "https://github.com/$repo.git" "$target"
|
|
fi
|
|
}
|
|
|
|
install_zsh_plugin zsh-users/zsh-autosuggestions "$ZSH_CUSTOM/plugins/zsh-autosuggestions"
|
|
install_zsh_plugin zsh-users/zsh-syntax-highlighting "$ZSH_CUSTOM/plugins/zsh-syntax-highlighting"
|
|
install_zsh_plugin zsh-users/zsh-history-substring-search "$ZSH_CUSTOM/plugins/zsh-history-substring-search"
|
|
|
|
# --------------------------- TPM (tmux plugin manager) ---------------------
|
|
if [[ ! -d "$USER_HOME/.tmux/plugins/tpm" ]]; then
|
|
log "cloning tmux plugin manager"
|
|
mkdir -p "$USER_HOME/.tmux/plugins"
|
|
git clone --depth 1 https://github.com/tmux-plugins/tpm "$USER_HOME/.tmux/plugins/tpm"
|
|
else
|
|
log "tpm already installed"
|
|
fi
|
|
|
|
# --------------------------- Maple Mono NF font ----------------------------
|
|
# nvim init.lua references "Maple Mono NF". Install it so the default font works.
|
|
# Pin Maple-font version. Bump manually if a release breaks things.
|
|
MAPLE_FONT_VERSION="v7.9"
|
|
|
|
if fc-list 2>/dev/null | grep -qi "Maple Mono NF"; then
|
|
log "Maple Mono NF already installed"
|
|
else
|
|
{{ if eq .os_family "arch" -}}
|
|
log "installing maplemono-nf-cn from AUR (via paru)"
|
|
paru -S --needed --noconfirm maplemono-nf-cn
|
|
{{ else if eq .os_family "debian" -}}
|
|
log "downloading MapleMono-NF.zip from subframe7536/Maple-font $MAPLE_FONT_VERSION"
|
|
FONT_DIR="$USER_HOME/.local/share/fonts/maple-mono-nf"
|
|
mkdir -p "$FONT_DIR"
|
|
TMP_ZIP="$(mktemp /tmp/maple-font.XXXXXX.zip)"
|
|
if curl -fL --retry 3 \
|
|
"https://github.com/subframe7536/Maple-font/releases/download/${MAPLE_FONT_VERSION}/MapleMono-NF.zip" \
|
|
-o "$TMP_ZIP"; then
|
|
log "extracting font files"
|
|
unzip -q -o "$TMP_ZIP" -d "$FONT_DIR"
|
|
rm -f "$TMP_ZIP"
|
|
log "running fc-cache"
|
|
fc-cache -fv >/dev/null
|
|
else
|
|
log "WARNING: failed to download Maple Mono NF — nvim will warn about missing font"
|
|
log "manual install: https://github.com/subframe7536/Maple-font"
|
|
rm -f "$TMP_ZIP"
|
|
fi
|
|
{{ else -}}
|
|
log "WARNING: font install not configured for os_family={{ .os_family }}"
|
|
{{ end -}}
|
|
fi
|
|
|
|
# --------------------------- set zsh as default shell ---------------------
|
|
USER_SHELL="$(getent passwd "$(whoami)" | cut -d: -f7)"
|
|
if [[ "$USER_SHELL" != "$(command -v zsh)" ]]; then
|
|
log "changing login shell to zsh"
|
|
chsh -s "$(command -v zsh)"
|
|
else
|
|
log "zsh already the login shell"
|
|
fi
|
|
|
|
log "all user packages installed"
|
|
zsh --version
|
|
nvim --version | head -1
|
|
tmux -V |