#!/bin/bash # ╔══════════════════════════════════════════════════════════════════════════════╗ # ║ setup/modules/package-managers.sh — Package manager bootstrap ║ # ║ ║ # ║ PURPOSE: ║ # ║ Installs and configures the additional package managers and language ║ # ║ runtimes that the rest of the setup depends on. This must be the ║ # ║ FIRST module run because others rely on yay, nvm, and rustup. ║ # ║ ║ # ║ INSTALLS: ║ # ║ - Flatpak (via pacman) — universal app sandbox, Flathub remote ║ # ║ - yay — AUR helper (builds packages from the Arch User Repository) ║ # ║ - rustup — Rust toolchain manager; sets stable as default ║ # ║ - nvm + Node.js 22 — JavaScript runtime for CLI tools ║ # ║ ║ # ║ ALL INSTALLS ARE IDEMPOTENT — safe to run multiple times. ║ # ╚══════════════════════════════════════════════════════════════════════════════╝ set -euo pipefail # -e: abort immediately if any command fails (package manager errors are fatal here) # -u: error on unset variables # -o pipefail: pipe failures are caught # Load shared logging helpers (log, skip, warn, err functions) source "$(dirname "${BASH_SOURCE[0]}")/lib/logging.sh" # ── Flatpak + system update ──────────────────────────────────────────────────── # WHY: Run a full system upgrade first (-yu) to avoid partial-upgrade issues # where pacman has a newer database but old packages. This is critical on # Arch which is a rolling release. # Flatpak is installed here (not in core-packages.sh) because it's needed before # the Flathub remote can be added, and some modules call ensure_flatpak() early. log "Updating system and installing Flatpak..." sudo pacman -Syu --noconfirm --needed flatpak # ── yay (AUR helper) ────────────────────────────────────────────────────────── # WHY: The AUR (Arch User Repository) contains thousands of community packages # not in the official repos. yay is the most popular AUR helper — it wraps # pacman and handles PKGBUILD downloading, building, and installing. # HOW: Clone the yay PKGBUILD from AUR, then build and install it with makepkg. # makepkg -si: build the package (-s=sync dependencies) and install (-i). # IDEMPOTENCY: Check for the yay binary first to avoid rebuilding if already present. if ! command -v yay &>/dev/null; then log "Installing yay..." # Use ~/install-tmp rather than /tmp to survive across sudo sessions and avoid # tmpfs size limits on systems with small RAM mkdir -p ~/install-tmp git clone https://aur.archlinux.org/yay.git ~/install-tmp/yay cd ~/install-tmp/yay # --noconfirm: don't prompt during the build/install process makepkg -si --noconfirm cd ~ else skip "yay already installed." fi # ── rustup / Rust toolchain ──────────────────────────────────────────────────── # WHY: Rust is used by many modern CLI tools (yazi, starship, zellij, etc.) and # some AUR packages require cargo to build from source. # rustup is preferred over the `rust` package because it allows switching # between stable/nightly channels and managing multiple targets. # HOW: Install rustup via pacman (it's in the official repos), then set # `stable` as the active toolchain so `cargo` and `rustc` are available. if ! command -v rustup &>/dev/null; then log "Installing rustup..." sudo pacman -S --noconfirm --needed rustup fi # Always run 'rustup default stable' even if rustup exists — this is idempotent # and ensures the correct toolchain is active (guards against nightly being default) rustup default stable # ── nvm + Node.js ───────────────────────────────────────────────────────────── # WHY: Node.js is required for npm-based tools including Claude Code CLI, # LocalTunnel, and other developer utilities. We use nvm (Node Version Manager) # rather than the system `node` package because: # 1. nvm allows per-project Node version pinning via .nvmrc # 2. Global npm packages install to ~/.nvm without needing sudo # 3. Switching to LTS or newer versions is a one-liner # HOW: Download and run the official nvm install script, then source nvm.sh to # activate it in this shell session, then install Node.js LTS v22. # NOTE: nvm installs to ~/.nvm/ and injects itself via .bashrc/.zshrc hooks if ! command -v node &>/dev/null; then log "Installing nvm and Node.js 22..." # Only clone nvm if its directory doesn't exist (guards against partial installs) if [ ! -d "$HOME/.nvm" ]; then # Pin to a specific nvm version for reproducibility curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash fi # Source nvm into the current shell session (normally loaded by .bashrc/.zshrc) . "$HOME/.nvm/nvm.sh" # Install Node.js 22 (current LTS) and set it as the active version nvm install 22 else # Report the currently-installed version so the log shows what's active skip "Node.js already installed: $(node -v)" fi log "Package managers ready."