Dotfiles/setup/modules/package-managers.sh

99 lines
6.2 KiB
Bash

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