#!/usr/bin/env bash # install.sh: Install dependencies and stow all packages. # Run this after cloning on a new machine. set -euo pipefail DOTFILES_DIR="$(cd "$(dirname "$0")" && pwd)" # --------------------------------------------------------------------------- # Detect Linux distribution # --------------------------------------------------------------------------- detect_distro() { if [[ -f /etc/os-release ]]; then . /etc/os-release echo "$ID" else echo "unknown" fi } DISTRO=$(detect_distro) # --------------------------------------------------------------------------- # Dependencies # --------------------------------------------------------------------------- # On Arch-based systems, partial upgrades are unsupported — installing a # package that pulls in a newer library breaks packages built against the old # one. The right fix is 'sudo pacman -Syu', but doing that over SSH risks # a dropped connection mid-kernel-upgrade. So we just warn and let the user # decide. check_arch_updates() { sudo pacman -Sy --noconfirm # refresh databases only, no upgrade local updates updates=$(pacman -Qu 2>/dev/null | wc -l) if [[ "$updates" -gt 0 ]]; then echo "" echo "WARNING: $updates system package(s) are out of date." echo " If pacman fails with dependency conflicts, run 'sudo pacman -Syu'" echo " locally (not over SSH, to avoid kernel upgrade risks), then re-run" echo " this script." echo "" fi } case "$DISTRO" in endeavouros) # EndeavourOS is Arch-based, use pacman PACMAN_PACKAGES=( stow # sway ecosystem swayidle # bar & notifications mako libnotify # notify-send # terminal & launcher fuzzel # audio & display wireplumber # wpctl pipewire-pulse # pactl brightnessctl alsa-utils # speaker-test # screen recording wf-recorder slurp zenity ffmpeg # misc jq firefox ) check_arch_updates echo "Installing packages for EndeavourOS..." sudo pacman -S --noconfirm "${PACMAN_PACKAGES[@]}" ;; fedora) DNF_PACKAGES=( stow # sway ecosystem swayidle # bar & notifications mako libnotify # notify-send # terminal & launcher fuzzel # audio & display wireplumber # wpctl pipewire-utils # pactl brightnessctl alsa-utils # speaker-test # screen recording wf-recorder slurp zenity ffmpeg # needs RPM Fusion: https://rpmfusion.org # misc jq firefox ) echo "Installing packages for Fedora..." sudo dnf install -y "${DNF_PACKAGES[@]}" ;; arch) PACMAN_PACKAGES=( stow # sway ecosystem swayidle # bar & notifications mako libnotify # notify-send # terminal & launcher fuzzel # audio & display wireplumber # wpctl pipewire-pulse # pactl brightnessctl alsa-utils # speaker-test # screen recording wf-recorder slurp zenity ffmpeg # misc jq firefox ) check_arch_updates echo "Installing packages for Arch Linux..." sudo pacman -S --noconfirm "${PACMAN_PACKAGES[@]}" ;; *) echo "ERROR: Unsupported distribution: $DISTRO" echo "Supported distributions: fedora, arch, endeavouros" exit 1 ;; esac # --------------------------------------------------------------------------- # Packages not in Fedora repos - install manually if missing # --------------------------------------------------------------------------- warn_missing() { local cmd="$1" msg="$2" if ! command -v "$cmd" &>/dev/null; then echo "WARNING: '$cmd' not found - $msg" fi } warn_missing autotiling "install via pip: pip install --user autotiling" warn_missing eww "install from https://github.com/elkowar/eww/releases" warn_missing wezterm "install from https://wezfurlong.org/wezterm/install/linux.html" # --------------------------------------------------------------------------- # Starship # --------------------------------------------------------------------------- if ! command -v starship &>/dev/null; then echo "" echo "Installing Starship..." curl -sS https://starship.rs/install.sh | sh else echo "" echo "Starship already installed, skipping." fi # --------------------------------------------------------------------------- # NPM packages # --------------------------------------------------------------------------- echo "" echo "Installing npm packages..." npm install -g @mariozechner/pi-coding-agent # --------------------------------------------------------------------------- # Fonts # --------------------------------------------------------------------------- FONT_DIR="$HOME/.local/share/fonts/JetBrainsMono" if [[ ! -d "$FONT_DIR" ]]; then echo "" echo "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" echo "Font installed." else echo "JetBrains Mono Nerd Font already installed, skipping." fi # --------------------------------------------------------------------------- # Stow all packages # --------------------------------------------------------------------------- echo "" echo "Stowing dotfiles..." # Check for conflicts before stowing CONFLICTS=() for PACKAGE in "$DOTFILES_DIR"/*/; do PACKAGE="$(basename "$PACKAGE")" # Skip hidden directories and .git [[ "$PACKAGE" == .* ]] && continue # Check if package has files that would conflict while IFS= read -r -d '' dotfile; do # Get the target path this would create TARGET_PATH="${HOME}/${dotfile#$DOTFILES_DIR/$PACKAGE/}" # If target exists and is NOT a symlink to the correct location, it's a conflict if [[ -e "$TARGET_PATH" ]] && [[ ! -L "$TARGET_PATH" ]]; then CONFLICTS+=("$PACKAGE (file: $TARGET_PATH)") fi done < <(find "$DOTFILES_DIR/$PACKAGE" -type f -print0 2>/dev/null || true) done if [[ ${#CONFLICTS[@]} -gt 0 ]]; then echo "WARNING: Found conflicts with existing configs:" for conflict in "${CONFLICTS[@]}"; do echo " ✗ $conflict" done echo "" fi # Stow all packages for PACKAGE in "$DOTFILES_DIR"/*/; do PACKAGE="$(basename "$PACKAGE")" # Skip hidden directories [[ "$PACKAGE" == .* ]] && continue echo " $PACKAGE" stow --dir="$DOTFILES_DIR" --target="$HOME" --restow "$PACKAGE" done # --------------------------------------------------------------------------- # Configure shell (after stowing) # --------------------------------------------------------------------------- echo "" echo "Configuring zsh..." # Ensure .zshrc exists (stow should have created it via symlink) if [[ ! -f "$HOME/.zshrc" ]]; then touch "$HOME/.zshrc" fi # Ensure starship is initialized in .zshrc if ! grep -q 'eval "$(starship init zsh)"' "$HOME/.zshrc"; then echo 'eval "$(starship init zsh)"' >> "$HOME/.zshrc" echo " Added starship initialization to ~/.zshrc" else echo " Starship already configured in ~/.zshrc" fi echo "Done."