#!/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."