#!/usr/bin/env bash # Sets up a fresh Arch install: drivers, packages, dotfiles and system config. # Safe to re-run; anything already installed is skipped. # # Usage: ./bootstrap.sh [--svt-av1 | --no-svt-av1] # --svt-av1 also install svt-av1-essential-git and rebuild ffmpeg against it # --no-svt-av1 skip that without asking # (neither) ask set -euo pipefail repo="$(cd "$(dirname "$0")" && pwd)" list="$repo/system/packages.txt" svt_av1=ask for arg in "$@"; do case "$arg" in --svt-av1) svt_av1=yes ;; --no-svt-av1) svt_av1=no ;; *) echo "Unknown option: $arg" >&2; exit 1 ;; esac done if (( EUID == 0 )); then echo "Run this as your normal user, not root (it uses sudo where needed)." >&2 exit 1 fi step() { printf '\n\033[1;34m==> %s\033[0m\n' "$*"; } # Prints the packages under a [section] of packages.txt, skipping comments packages() { awk -v want="[$1]" ' /^\[/ { section = $1; next } section == want { sub(/#.*/, ""); if (NF) print $1 } ' "$list" } # --- System config ----------------------------------------------------------- step "System config (pacman options)" "$repo/system/install.sh" step "Enabling multilib (needed for Steam and 32-bit drivers)" if ! grep -q '^\[multilib\]' /etc/pacman.conf; then sudo sed -i '/^#\[multilib\]/,/^#Include/ s/^#//' /etc/pacman.conf fi sudo pacman -Syu --needed --noconfirm pciutils git base-devel # --- Hardware ---------------------------------------------------------------- step "Detecting CPU and GPU" hw=() case "$(grep -m1 '^vendor_id' /proc/cpuinfo | awk '{print $3}')" in AuthenticAMD) hw+=(amd-ucode); echo "CPU: AMD" ;; GenuineIntel) hw+=(intel-ucode); echo "CPU: Intel" ;; *) echo "CPU: unknown vendor, skipping microcode" ;; esac # Vendor column of every display controller, e.g. "NVIDIA Corporation" gpus="$(lspci -mm | awk -F'"' '$2 ~ /VGA|3D|Display/ { print $4 }')" if grep -q NVIDIA <<<"$gpus"; then echo "GPU: NVIDIA" # nvidia-open only ships modules for the stock `linux` kernel; any other # kernel needs the DKMS build. Supports Turing (GTX 16xx / RTX 20xx) and newer. if pacman -Qq linux-lts linux-zen linux-hardened >/dev/null 2>&1; then hw+=(nvidia-open-dkms linux-headers) else hw+=(nvidia-open) fi hw+=(nvidia-utils lib32-nvidia-utils libva-nvidia-driver) fi if grep -q 'Advanced Micro Devices' <<<"$gpus"; then echo "GPU: AMD" hw+=(mesa lib32-mesa vulkan-radeon lib32-vulkan-radeon) fi if grep -q 'Intel Corporation' <<<"$gpus"; then echo "GPU: Intel" hw+=(mesa lib32-mesa vulkan-intel lib32-vulkan-intel intel-media-driver) fi # Installed before the main list so Steam's 32-bit Vulkan dependency is # already satisfied by the right driver if (( ${#hw[@]} )); then sudo pacman -S --needed --noconfirm "${hw[@]}" fi # --- Packages ---------------------------------------------------------------- step "Official repo packages" mapfile -t pkgs < <(packages pacman) sudo pacman -S --needed --noconfirm "${pkgs[@]}" step "yay (AUR helper)" if ! command -v yay >/dev/null; then build="$(mktemp -d)" git clone https://aur.archlinux.org/yay-bin.git "$build/yay-bin" (cd "$build/yay-bin" && makepkg -si --noconfirm) rm -rf "$build" else echo "already installed" fi step "AUR packages" mapfile -t pkgs < <(packages aur) yay -S --needed --noconfirm "${pkgs[@]}" step "Flatpak apps" sudo flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo mapfile -t pkgs < <(packages flatpak) sudo flatpak install -y --noninteractive flathub "${pkgs[@]}" step "Apps from official install scripts" mkdir -p "$HOME/.local/bin" for app in $(packages installer); do if command -v "$app" >/dev/null || [[ -x "$HOME/.local/bin/$app" ]]; then echo "$app: already installed" continue fi case "$app" in claude) curl -fsSL https://claude.ai/install.sh | bash ;; oh-my-posh) curl -fsSL https://ohmyposh.dev/install.sh | bash -s -- -d "$HOME/.local/bin" ;; *) echo "$app: no install recipe in bootstrap.sh, skipping" >&2 ;; esac done # --- Optional: SVT-AV1 essential + ffmpeg rebuild ---------------------------- if [[ $svt_av1 == ask ]]; then read -rp $'\nInstall svt-av1-essential-git and rebuild ffmpeg against it? (slow) [y/N] ' reply [[ $reply == [yY]* ]] && svt_av1=yes || svt_av1=no fi if [[ $svt_av1 == yes ]]; then step "svt-av1-essential-git" # Interactive on purpose: pacman asks to replace the conflicting svt-av1, # and --noconfirm would answer no yay -S --needed svt-av1-essential-git step "Rebuilding ffmpeg against svt-av1-essential-git" "$repo/system/rebuild-ffmpeg.sh" fi # --- Services ---------------------------------------------------------------- step "Enabling services" # Not started now: sddm would take over the screen mid-script. They come up on reboot. mapfile -t units < <(packages services) sudo systemctl enable "${units[@]}" # --- Dotfiles ---------------------------------------------------------------- step "Linking dotfiles with stow" # Create real parent dirs first, otherwise stow symlinks the whole directory # (e.g. ~/.config) into the repo and every app's files end up in git mkdir -p "$HOME/.config" "$HOME/.local/bin" "$HOME/.local/share" "$HOME/Pictures" mkdir -p -m 700 "$HOME/.ssh" if ! stow -d "$repo" -t "$HOME" --restow dotfiles; then echo "stow hit conflicts (listed above). Move those files aside, then run:" >&2 echo " stow -d \"$repo\" -t \"\$HOME\" dotfiles" >&2 fi if [[ "$(getent passwd "$USER" | cut -d: -f7)" != */zsh ]]; then step "Setting zsh as login shell" chsh -s /usr/bin/zsh fi step "Done — reboot to load drivers and start Hyprland"