#!/usr/bin/env bash require() { local cmd="$1" local pkg="${2:-$1}" if ! command -v "$cmd" >/dev/null 2>&1; then log_error "Required command '$cmd' not found. Install with: sudo pacman -S $pkg" return 1 fi } require_optional() { local cmd="$1" local pkg="${2:-$1}" if ! command -v "$cmd" >/dev/null 2>&1; then log_warn "'$cmd' not found. Install with: sudo pacman -S $pkg" return 1 fi } have() { command -v "$1" >/dev/null 2>&1 } is_arch() { [[ -f /etc/arch-release ]] || [[ -d /etc/pacman.d ]] } is_root() { [[ "$EUID" -eq 0 ]] } sudo_run() { if is_root; then "$@" else sudo "$@" fi } backup_file() { local target="$1" local backup_dir="${2:-$HOME/.dotfiles-backup/$(date +%Y%m%d-%H%M%S)}" local relative="${target#"$HOME"/}" local backup="$backup_dir/$relative" [[ -e "$target" || -L "$target" ]] || return 0 mkdir -p "$(dirname "$backup")" cp -a "$target" "$backup" log_info "Backed up $target -> $backup" printf '%s' "$backup_dir" } symlink_path() { local source="$1" local target="$2" backup_file "$target" rm -rf "$target" mkdir -p "$(dirname "$target")" ln -sfn "$source" "$target" log_info "Linked $source -> $target" } copy_path() { local source="$1" local target="$2" backup_file "$target" rm -rf "$target" mkdir -p "$(dirname "$target")" cp -a "$source" "$target" log_info "Copied $source -> $target" } platform_packages() { if is_arch; then printf '%s\n' "arch" fi if [[ -f /etc/os-release ]]; then local id id="$(grep -oP '^ID=\K.*' /etc/os-release)" printf '%s\n' "$id" fi } is_package_installed() { local pkg="$1" if command -v pacman >/dev/null 2>&1; then pacman -Qi "$pkg" >/dev/null 2>&1 return $? fi return 1 } install_pacman() { local packages=("$@") local to_install=() local pkg for pkg in "${packages[@]}"; do if ! pacman -Si "$pkg" >/dev/null 2>&1; then log_warn "Package '$pkg' not found in pacman repositories" continue fi if ! is_package_installed "$pkg"; then to_install+=("$pkg") fi done if ((${#to_install[@]})); then log_info "Installing: ${to_install[*]}" sudo_run pacman -S --needed --noconfirm "${to_install[@]}" else log_info "All packages already installed" fi } install_aur() { local packages=("$@") local aur_helper="" if have paru; then aur_helper="paru" elif have yay; then aur_helper="yay" else log_error "No AUR helper found (install paru or yay)" return 1 fi local to_install=() local pkg for pkg in "${packages[@]}"; do if ! is_package_installed "$pkg"; then to_install+=("$pkg") fi done if ((${#to_install[@]})); then log_info "Installing from AUR: ${to_install[*]}" "$aur_helper" -S --needed --noconfirm "${to_install[@]}" else log_info "All AUR packages already installed" fi } replace_home_paths() { local dir="$1" local original_home="${2:-/home/pascal}" if [[ "$original_home" == "$HOME" ]]; then return 0 fi find "$dir" -type f -exec sed -i "s#${original_home}#${HOME}#g" {} + 2>/dev/null || true log_info "Rewrote home paths in $dir" } detect_gpu() { if ! command -v lspci >/dev/null 2>&1; then if have pacman; then sudo_run pacman -S --needed --noconfirm pciutils >/dev/null 2>&1 || true fi fi local gpu_info gpu_info="$(lspci -nn 2>/dev/null | grep -E '\[0300\]|\[0302\]|\[0380\]' || true)" [[ -z "$gpu_info" ]] && gpu_info="$(lspci -nn 2>/dev/null | grep -iE '(VGA|3D|Display).*controller' || true)" if printf '%s' "$gpu_info" | grep -qi "\[10de:"; then printf 'nvidia' elif printf '%s' "$gpu_info" | grep -qi "\[1002:\|\[1022:"; then printf 'amd' elif printf '%s' "$gpu_info" | grep -qi "\[8086:"; then printf 'intel' elif printf '%s' "$gpu_info" | grep -qi "vmware\|qemu\|virtualbox\|virtio"; then printf 'vm' elif printf '%s' "$gpu_info" | grep -qi "nvidia"; then printf 'nvidia' elif printf '%s' "$gpu_info" | grep -qi "amd\|advanced micro devices"; then printf 'amd' elif printf '%s' "$gpu_info" | grep -qi "intel"; then printf 'intel' else printf 'unknown' fi } gpu_packages() { local gpu_type gpu_type="$(detect_gpu)" case "$gpu_type" in intel) printf '%s\n' "xf86-video-intel" "vulkan-intel" "intel-media-driver" "libva-intel-driver" ;; amd) printf '%s\n' "xf86-video-amdgpu" "vulkan-radeon" "libva-mesa-driver" "mesa-vdpau" ;; nvidia) printf '%s\n' "nvidia-dkms" "nvidia-utils" "nvidia-settings" "libva-nvidia-driver" "vulkan-tools" ;; vm) printf '%s\n' "xf86-video-vmware" "mesa" "vulkan-swrast" ;; *) printf '%s\n' "mesa" "vulkan-swrast" ;; esac } is_fresh_install() { have hyprctl && return 1 if have hyprland; then hyprland --version >/dev/null 2>&1 && return 1 fi if [[ -n "${WAYLAND_DISPLAY:-}" || -n "${DISPLAY:-}" ]]; then return 1 fi return 0 } count_missing_packages() { local packages=("$@") local missing=0 local pkg for pkg in "${packages[@]}"; do if ! is_package_installed "$pkg"; then ((missing++)) fi done printf '%d' "$missing" } system_summary() { local gpu gpu="$(detect_gpu)" cat </dev/null | sed 's/"$//' || echo "Arch Linux") │ Kernel: $(uname -r) │ GPU: ${gpu} ($(lspci -nn 2>/dev/null | grep -E '\[0300\]|\[0302\]|\[0380\]' | sed 's/.*: //' | head -1 || echo "unknown")) │ Session: $(printenv XDG_SESSION_TYPE || echo "none (TTY)") │ Hyprland: $(have hyprctl && echo "installed" || echo "NOT installed") │ AUR: $(have paru && echo "paru" || (have yay && echo "yay" || echo "none")) └─────────────────────────────────────────────┘ SUMMARY } install_aur_helper() { if have paru || have yay; then return 0 fi if ! command -v git >/dev/null 2>&1; then sudo_run pacman -S --needed --noconfirm git base-devel fi local build_dir build_dir="$(mktemp -d)" sudo_run pacman -S --needed --noconfirm rustup 2>/dev/null || true if have rustup; then rustup default stable >/dev/null 2>&1 || true fi if git clone https://aur.archlinux.org/paru.git "$build_dir/paru" 2>/dev/null; then (cd "$build_dir/paru" && makepkg -si --needed --noconfirm) 2>&1 | tail -5 || { tui_warn "paru build failed, trying yay..." if git clone https://aur.archlinux.org/yay.git "$build_dir/yay" 2>/dev/null; then (cd "$build_dir/yay" && makepkg -si --needed --noconfirm) 2>&1 | tail -5 || { tui_warn "yay build failed too. Install manually: paru -S paru-bin" } fi } fi rm -rf "$build_dir" }