Files
dotfiles/install-deps.sh
2026-08-04 11:38:03 +02:00

306 lines
8.1 KiB
Bash
Executable File

#!/usr/bin/env bash
# install-deps.sh: Install all system and tooling dependencies.
# Run this after cloning on a new machine (before install-stow.sh).
set -euo pipefail
DOTFILES_DIR="$(cd "$(dirname "$0")" && pwd)"
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
ok() { echo "$*"; }
info() { echo "$*"; }
warn() { echo "$*"; }
header() { echo ""; echo "==> $*"; }
have() { command -v "$1" &>/dev/null; }
# ---------------------------------------------------------------------------
# Detect Linux distribution
# ---------------------------------------------------------------------------
detect_distro() {
if [[ -f /etc/os-release ]]; then
# shellcheck source=/dev/null
. /etc/os-release
echo "$ID"
else
echo "unknown"
fi
}
DISTRO=$(detect_distro)
# ---------------------------------------------------------------------------
# System packages
# ---------------------------------------------------------------------------
header "System packages"
COMMON_PACKAGES=(
stow
swayidle
mako
libnotify
fuzzel
wireplumber
brightnessctl
alsa-utils
wf-recorder
slurp
zenity
jq
firefox
zoxide
# Screenshots / clipboard (sway bindings)
grim
wl-clipboard
# eww status-bar helpers
acpi
upower
inotify-tools
# hdmi-setup.sh math
bc
# Terminal launched by eww wifi popup (nmtui)
alacritty
# polkit auth agent launched from sway
mate-polkit
# Shell, editor and CLI tooling (.zshrc / nvim)
neovim
zsh
tmux
ripgrep
fzf
# Flatpak runtime (Signal)
flatpak
)
case "$DISTRO" in
endeavouros|arch)
DISTRO_PACKAGES=(
pipewire-pulse
ffmpeg
networkmanager
fd
python-i3ipc
yazi
)
PACKAGES=("${COMMON_PACKAGES[@]}" "${DISTRO_PACKAGES[@]}")
# Warn about pending upgrades (partial upgrades are unsupported on Arch)
sudo pacman -Sy --noconfirm &>/dev/null
updates=$(pacman -Qu 2>/dev/null | wc -l)
if [[ "$updates" -gt 0 ]]; then
warn "$updates system package(s) are out of date."
warn "If pacman fails with dependency conflicts, run 'sudo pacman -Syu'"
warn "locally (not over SSH) then re-run this script."
echo ""
fi
# Only install packages that aren't already present
MISSING=()
for pkg in "${PACKAGES[@]}"; do
if ! pacman -Q "$pkg" &>/dev/null; then
MISSING+=("$pkg")
else
ok "$pkg"
fi
done
if [[ ${#MISSING[@]} -gt 0 ]]; then
info "Installing: ${MISSING[*]}"
sudo pacman -S --noconfirm "${MISSING[@]}"
fi
;;
fedora|fedora-asahi-remix)
DISTRO_PACKAGES=(
pipewire-utils
ffmpeg
NetworkManager
fd-find
python3-i3ipc
)
PACKAGES=("${COMMON_PACKAGES[@]}" "${DISTRO_PACKAGES[@]}")
MISSING=()
for pkg in "${PACKAGES[@]}"; do
if rpm -q "$pkg" &>/dev/null; then
ok "$pkg"
else
MISSING+=("$pkg")
fi
done
if [[ ${#MISSING[@]} -gt 0 ]]; then
info "Installing: ${MISSING[*]}"
sudo dnf install -y "${MISSING[@]}"
fi
;;
*)
warn "Unsupported distribution: $DISTRO — skipping system packages."
;;
esac
# ---------------------------------------------------------------------------
# Tools not in distro repos — warn if missing
# ---------------------------------------------------------------------------
header "Optional tools (manual install)"
warn_missing() {
local cmd="$1" msg="$2"
if have "$cmd"; then
ok "$cmd"
else
warn "'$cmd' not found — $msg"
fi
}
warn_missing yazi "not in Fedora repos — enable COPR: 'dnf copr enable atim/yazi && dnf install yazi'"
warn_missing eww "install from https://github.com/elkowar/eww/releases"
warn_missing wezterm "install from https://wezfurlong.org/wezterm/install/linux.html"
warn_missing stylua "nvim formatter — install via :MasonInstall stylua or 'cargo install stylua'"
# ---------------------------------------------------------------------------
# Zsh plugins (git submodules)
# ---------------------------------------------------------------------------
header "Zsh plugins"
(
cd "$DOTFILES_DIR"
if git submodule status | grep -q '^-'; then
info "Initialising git submodules..."
git submodule update --init --recursive
else
info "Updating git submodules..."
git submodule update --recursive --remote
fi
)
for plugin_dir in "$DOTFILES_DIR"/zshrc/.zsh/plugins/*/; do
plugin_name="$(basename "$plugin_dir")"
if [[ -f "$plugin_dir/${plugin_name}.plugin.zsh" || -f "$plugin_dir/${plugin_name}.zsh" ]]; then
ok "$plugin_name"
else
warn "$plugin_name — submodule directory appears empty"
fi
done
# ---------------------------------------------------------------------------
# Starship
# ---------------------------------------------------------------------------
header "Starship"
if have starship; then
ok "starship already installed"
else
info "Installing Starship..."
curl -sS https://starship.rs/install.sh | sh
fi
# ---------------------------------------------------------------------------
# pyenv (.zshrc initializes it)
# ---------------------------------------------------------------------------
header "pyenv"
if [[ -d "$HOME/.pyenv" ]] || have pyenv; then
ok "pyenv already installed"
else
info "Installing pyenv..."
curl -fsSL https://pyenv.run | bash
fi
# ---------------------------------------------------------------------------
# autotiling (pip --user → ~/.local/bin, no pyenv required)
# ---------------------------------------------------------------------------
header "autotiling"
if have autotiling; then
ok "autotiling already installed"
else
info "Installing autotiling via pip..."
pip install --user autotiling
ok "autotiling installed"
fi
# ---------------------------------------------------------------------------
# Signal (flatpak)
# ---------------------------------------------------------------------------
header "Signal"
if have flatpak; then
if flatpak info org.signal.Signal &>/dev/null; then
ok "Signal already installed"
else
info "Installing Signal from Flathub..."
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak install -y flathub org.signal.Signal
fi
else
warn "flatpak not found — skipping Signal install"
fi
# ---------------------------------------------------------------------------
# npm global packages
# ---------------------------------------------------------------------------
header "npm global packages"
if npm list -g --depth=0 @mariozechner/pi-coding-agent &>/dev/null; then
ok "@mariozechner/pi-coding-agent already installed"
else
info "Installing @mariozechner/pi-coding-agent..."
npm install -g @mariozechner/pi-coding-agent
fi
# ---------------------------------------------------------------------------
# pi extension dependencies
# ---------------------------------------------------------------------------
header "pi extension node_modules"
for ext_dir in "$DOTFILES_DIR"/pi/.pi/agent/extensions/*/; do
[[ -f "$ext_dir/package.json" ]] || continue
ext_name="$(basename "$ext_dir")"
if [[ -d "$ext_dir/node_modules" ]]; then
ok "$ext_name (node_modules already present)"
else
info "Running npm install for $ext_name..."
npm install --prefix "$ext_dir" --ignore-scripts
fi
done
# ---------------------------------------------------------------------------
# Fonts
# ---------------------------------------------------------------------------
header "Fonts"
FONT_DIR="$HOME/.local/share/fonts/JetBrainsMono"
if [[ -d "$FONT_DIR" ]]; then
ok "JetBrains Mono Nerd Font already installed"
else
info "Installing JetBrains Mono Nerd Font..."
TMP="$(mktemp -d)"
curl -fLo "$TMP/JetBrainsMono.zip" \
"https://github.com/ryanoasis/nerd-fonts/releases/latest/download/JetBrainsMono.zip"
mkdir -p "$FONT_DIR"
unzip -q "$TMP/JetBrainsMono.zip" -d "$FONT_DIR"
rm -rf "$TMP"
fc-cache -f "$FONT_DIR"
ok "Font installed"
fi
# ---------------------------------------------------------------------------
echo ""
echo "All dependencies done. Run ./install-stow.sh to link configs."