#!/usr/bin/env bash # ============================================================================= # run_once_20-install-user-packages-gentoo.sh.tmpl (gentoo-only) # Install the user package set on gentoo via emerge. # # Equivalent to run_once_20-install-user-packages.sh.tmpl's arch/debian # branches, but using portage. Key differences: # - USE flags matter (e.g. eza has git feature flag, fzf has shell-completion) # - Some packages are only in GURU overlay (eza, lazygit, topgrade, etc.) # - emerge is slow (compiles from source); distcc handles remote builds # - Bun isn't in any gentoo overlay; use the official curl install # # Runs after 00-install-bootstrap-tools.sh and 10-add-gentoo-overlays.sh. # ============================================================================= set -euo pipefail # Make user-local bins (bun, omp, cargo) visible to the script even when # invoked from a non-interactive context (e.g. `chezmoi apply` over SSH). export PATH="/usr/bin:/bin:$HOME/.local/bin:$HOME/.bun/bin:$HOME/.cargo/bin:$PATH" log() { printf '\033[1;34m[packages]\033[0m %s\n' "$*"; } die() { printf '\033[1;31m[packages ERROR]\033[0m %s\n' "$*" >&2; exit 1; } USER_HOME="${HOME:-$(eval echo "~$(whoami)")}" ZSH_CUSTOM="${ZSH_CUSTOM:-$USER_HOME/.oh-my-zsh/custom}" # ----------------------------- GENTOO --------------------------------------- # On gentoo, `emerge` is the only PM (plus the GURU overlay for some # packages). Many of the user packages live in GURU, so we run emerge with # GURU enabled. Distcc is recommended for this box (2-core Ivy Bridge + # MAKEOPTS=-j50 means it's relying on remote build hosts via DISTCC_HOSTS). # # Package selection mirrors the arch/debian script. Where a package is # only available with USE flags, we set them in /etc/portage/package.use/ # before emerging. Where a package is ~amd64-only, we accept_keywords. log "checking user packages (gentoo)" # Step 1: USE flags + accept_keywords for packages that need them # Some packages (eza, lazygit) need explicit USE flags or keyword unmask. # Set them in package.use/package.accept_keywords so emerge sees them. USE_DIR="/etc/portage/package.use" ACCEPT_DIR="/etc/portage/package.accept_keywords" mkdir -p "$USE_DIR" "$ACCEPT_DIR" 2>/dev/null || true sudo mkdir -p "$USE_DIR" "$ACCEPT_DIR" # eza: needs explicit accept_keywords (was masked), USE=git enables git status column # Skip if already set if ! grep -q "^app-misc/eza" "$USE_DIR/zz-gentoo-bootstrap" 2>/dev/null; then log "writing USE flags: app-misc/eza git" echo "app-misc/eza git" | sudo tee "$USE_DIR/zz-gentoo-bootstrap" >/dev/null fi # fzf-tab, zsh-autosuggestions: gentoo has them in app-shells/ but newer # versions may need unmask. Use the ones in the tree first; if too old, # we'll install via oh-my-zsh custom plugins (gentoo's ebuilds can lag). # Step 2: Define the package set # Note: on Gentoo there's no `base-devel` meta-package. The toolchain # (gcc, binutils, glibc, make, patch, etc.) is part of the @system set # which is always installed. We only need to list user-space packages. GENTOO_PKGS=( app-shells/zsh app-shells/zsh-completions app-shells/zsh-syntax-highlighting app-admin/tmux app-editors/neovim dev-vcs/git app-text/bat sys-process/btop sys-process/htop app-text/fastfetch app-misc/eza app-shells/fzf app-misc/fd sys-apps/ripgrep app-shells/zoxide app-shells/starship # lazygit is in GURU (app-misc/lazygit) # topgrade is in GURU (app-misc/topgrade) # media-video/yt-dlp is in main app-text/jq app-arch/unzip app-arch/p7zip net-misc/openssh # bun: NOT in gentoo (main or GURU). Install via official curl. ) # Step 3: Determine what's missing # gentoo's emerge has a "is it installed?" check via `qlist` or `equery`. # Simpler: check if the binary is on PATH. MISSING_PKGS=() for p in "${GENTOO_PKGS[@]}"; do # Use the package basename as a proxy for "is the binary installed" bin_name=$(basename "$p") # Strip the category for the binary lookup (e.g. app-shells/zsh -> zsh) if ! command -v "$bin_name" >/dev/null 2>&1; then MISSING_PKGS+=("$p") fi done # Step 4: Install if (( ${#MISSING_PKGS[@]} > 0 )); then log "emerge --newuse user packages (missing: ${MISSING_PKGS[*]})" log "this may take a while (gentoo compiles from source; distcc helps)" # --ask=n: no prompts # --nospinner: cleaner output # --quiet-build: only show errors during compile # --keep-going: don't abort if one package fails # --with-bdeps=y: include build deps so we don't accidentally skip them sudo emerge --ask=n --nospinner --quiet-build --keep-going \ --with-bdeps=y --autounmask-license=y \ "${MISSING_PKGS[@]}" else log "all user packages already installed; skipping emerge" fi # Step 5: GURU-only packages (lazygit, topgrade) GURU_PKGS=( app-misc/lazygit app-misc/topgrade ) GURU_MISSING=() for p in "${GURU_PKGS[@]}"; do bin_name=$(basename "$p") if ! command -v "$bin_name" >/dev/null 2>&1; then GURU_MISSING+=("$p") fi done if (( ${#GURU_MISSING[@]} > 0 )); then log "emerge GURU packages (missing: ${GURU_MISSING[*]})" sudo emerge --ask=n --nospinner --quiet-build --keep-going \ --with-bdeps=y --autounmask-license=y \ "${GURU_MISSING[@]}" fi # Step 6: bun (no gentoo package) — install via official curl, fallback path if ! command -v bun >/dev/null 2>&1; then log "installing bun via official curl installer (no gentoo package)" curl -fsSL https://bun.sh/install | BUN_INSTALL="$HOME/.local" bash fi # Post-install verification: bun must be on PATH if ! command -v bun >/dev/null 2>&1; then log "ERROR: bun install succeeded but bun is not on PATH" log " check \$BUN_INSTALL/bin/bun exists and is in PATH" exit 1 fi BUN_VER=$(bun --version 2>/dev/null) log "bun: $BUN_VER (from official bun.sh installer; gentoo has no package)" # Step 7: oh-my-zsh + plugins if [[ ! -d "$USER_HOME/.oh-my-zsh" ]]; then log "installing oh-my-zsh" RUNZSH=no KEEP_ZSHRC=yes \ sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" else log "oh-my-zsh already installed" fi # Plugins: zsh-autosuggestions, zsh-syntax-highlighting, zsh-history-substring-search, fzf-tab declare -A PLUGINS=( [zsh-autosuggestions]="https://github.com/zsh-users/zsh-autosuggestions" [zsh-syntax-highlighting]="https://github.com/zsh-users/zsh-syntax-highlighting" [zsh-history-substring-search]="https://github.com/zsh-users/zsh-history-substring-search" [fzf-tab]="https://github.com/Aloxaf/fzf-tab" ) for plugin in "${!PLUGINS[@]}"; do if [[ -d "$ZSH_CUSTOM/plugins/$plugin" ]]; then log "plugin already present: $ZSH_CUSTOM/plugins/$plugin" else log "cloning plugin: $plugin" git clone --depth=1 "${PLUGINS[$plugin]}" "$ZSH_CUSTOM/plugins/$plugin" fi done # Step 8: tpm (tmux plugin manager) if [[ ! -d "$USER_HOME/.tmux/plugins/tpm" ]]; then log "installing tpm" git clone https://github.com/tmux-plugins/tpm "$USER_HOME/.tmux/plugins/tpm" else log "tpm already installed" fi # Step 9: Maple Mono NF font if ! fc-list | grep -qi "Maple Mono NF"; then log "installing Maple Mono NF font" # Download the latest release zip TMPFONT=$(mktemp -d) curl -fsSL "https://github.com/subframe7536/Maple-font/releases/latest/download/MapleMono-NF.zip" \ -o "$TMPFONT/MapleMono-NF.zip" mkdir -p "$USER_HOME/.local/share/fonts" unzip -q "$TMPFONT/MapleMono-NF.zip" -d "$USER_HOME/.local/share/fonts" fc-cache -fv >/dev/null 2>&1 rm -rf "$TMPFONT" else log "Maple Mono NF already installed" fi # Step 10: zsh as login shell if [[ "$(getent passwd rain | cut -d: -f7)" != "/usr/bin/zsh" ]]; then log "changing default shell to /usr/bin/zsh" sudo chsh -s /usr/bin/zsh rain else log "zsh already the login shell" fi log "all user packages installed" zsh --version nvim --version | head -1 tmux -V