Sunshine's global_prep_cmd now runs hypr/scripts/SunshineIdle.sh, which holds a systemd idle inhibitor for the length of a stream (hypridle respects it) and unlocks hyprlock if the session was already locked. With that in place hypridle starts at login again. Sunshine's config (sunshine.conf, apps.json, prep scripts) moves into the dotfiles; credentials, logs and state stay local and are gitignored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
169 lines
5.8 KiB
Bash
Executable File
169 lines
5.8 KiB
Bash
Executable File
#!/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"
|
|
# Sunshine keeps credentials and logs beside its config; those must stay out of git
|
|
mkdir -p "$HOME/.config/sunshine"
|
|
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"
|