#!/usr/bin/env bash # ============================================================================= # run_onchange_30-ensure-cargo.sh.tmpl # Make sure rustup/cargo is available. If not, install rustup. # After cargo is ready, install bat from crates.io on debian (apt renames # upstream bat to batcat, which breaks .zshrc's `alias cat=bat`). # Also install topgrade (universal update tool) and cargo-update (so cargo # packages themselves can be bumped). Prefer OS package managers when # available — only fall back to `cargo install` if the package isn't in # apt/pacman/chaotic-aur. # # Runs on every apply because the script body rarely changes but we want a # fresh check after package installs. # ============================================================================= set -euo pipefail log() { printf '\033[1;34m[cargo]\033[0m %s\n' "$*"; } # --- 1. Ensure cargo is on PATH --- if ! command -v cargo >/dev/null 2>&1; then if command -v rustup >/dev/null 2>&1; then log "rustup present but cargo missing — running rustup default" rustup default stable else log "no cargo or rustup — installing rustup" sh -c "$(curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs)" -- -y --default-toolchain stable --profile minimal # shellcheck disable=SC1091 source "$HOME/.cargo/env" fi fi # Ensure subsequent commands in this script can find cargo export PATH="$HOME/.cargo/bin:$PATH" log "rustup installed: $(rustup --version 2>/dev/null || echo unknown)" log "cargo installed: $(cargo --version)" # --- 2. Install bat (upstream binary, not renamed batcat) --- # On debian, apt installs bat as "batcat" (Debian has its own unrelated bat). # The clean fix is cargo install on debian, pacman on arch, portage on gentoo. {{ if eq .os_family "debian" -}} if ! command -v bat >/dev/null 2>&1; then log "installing bat via cargo (debian renames upstream bat to batcat)" cargo install bat --locked log "bat installed: $(bat --version)" else log "bat already installed: $(bat --version)" fi {{ else if eq .os_family "gentoo" -}} # Gentoo: app-text/bat is in main, ships upstream binary if ! command -v bat >/dev/null 2>&1; then log "WARNING: bat not installed — should have been installed by run_once_20" else log "bat already installed (gentoo: app-text/bat): $(bat --version)" fi {{ else -}} # Arch already installs upstream bat via pacman [extra]. log "skipping cargo bat install (os_family={{ .os_family }}, pacman handles it)" {{ end -}} # --- 3. Install topgrade (universal update tool) --- # topgrade walks through system packages, language toolchains, dev tools, # and runs each one's update command. It's a single command for "update # everything on this box." # - arch: topgrade is in [chaotic-aur] (we have chaotic-aur configured). # Use pacman to get system-tracked installs. # - debian: topgrade isn't in apt. Install via cargo (no PM alternative). # - gentoo: topgrade is in GURU overlay. Use emerge. if ! command -v topgrade >/dev/null 2>&1; then {{ if eq .os_family "arch" -}} log "installing topgrade via pacman (chaotic-aur)" sudo pacman -S --needed --noconfirm topgrade {{ else if eq .os_family "debian" -}} log "installing topgrade via cargo (debian has no topgrade package)" cargo install topgrade --locked {{ else if eq .os_family "gentoo" -}} log "installing topgrade via emerge (gentoo: app-misc/topgrade in GURU)" sudo emerge --ask=n --nospinner --quiet-build app-misc/topgrade {{ else -}} log "WARNING: topgrade install not configured for os_family={{ .os_family }}" {{ end -}} log "topgrade installed: $(topgrade --version | head -1)" else log "topgrade already installed: $(topgrade --version | head -1)" fi # --- 4. Install cargo-update (so we can `cargo install-update -a`) --- # Used to bump cargo-installed packages. Arch has it in [extra]; debian # doesn't ship it; gentoo has it in main (dev-util/cargo-update). if ! command -v cargo-install-update >/dev/null 2>&1; then {{ if eq .os_family "arch" -}} log "installing cargo-update via pacman" sudo pacman -S --needed --noconfirm cargo-update {{ else if eq .os_family "debian" -}} log "installing cargo-update via cargo (debian has no cargo-update package)" cargo install cargo-update --locked {{ else if eq .os_family "gentoo" -}} log "installing cargo-update via emerge (gentoo: dev-util/cargo-update)" sudo emerge --ask=n --nospinner --quiet-build dev-util/cargo-update {{ else -}} log "WARNING: cargo-update install not configured for os_family={{ .os_family }}" {{ end -}} log "cargo-update installed" else log "cargo-update already installed" fi