#!/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 ]] } OMERON_SUDO_PID="" OMERON_SUDO_PID="" sudo_init() { if is_root; then return 0 fi tui_info "Sudo access needed — enter your password once" sudo -v || { tui_error "Sudo authentication failed" return 1 } ( while true; do sleep 240 sudo -v 2>/dev/null || break done ) & OMERON_SUDO_PID=$! } sudo_cleanup() { [[ -n "$OMERON_SUDO_PID" ]] && kill "$OMERON_SUDO_PID" 2>/dev/null || true } sudo_run() { if is_root; then "$@" return fi if [[ -n "${OMERON_SUDO_PID:-}" ]] && kill -0 "$OMERON_SUDO_PID" 2>/dev/null; then sudo -n "$@" 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 0 if command -v expac >/dev/null 2>&1; then expac -Q '%n %P' 2>/dev/null | awk -v pkg="$pkg" ' { for (i=2; i<=NF; i++) if ($i == pkg) {found=1; exit} } END {exit !found} ' && return 0 fi return 1 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 } 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_package() { local pkgname="$1" local build_dir build_dir="$(mktemp -d)" tui_info "Cloning $pkgname from AUR directly..." if ! git clone "https://aur.archlinux.org/$pkgname.git" "$build_dir/$pkgname" 2>/dev/null; then rm -rf "$build_dir" return 1 fi tui_info "Building $pkgname..." if (cd "$build_dir/$pkgname" && makepkg -si --needed --noconfirm); then rm -rf "$build_dir" return 0 fi local rc=$? rm -rf "$build_dir" return $rc } install_aur_helper() { if have paru || have yay; then return 0 fi if is_root; then tui_warn "Running as root — makepkg refuses to run as root." tui_info "Switch to a normal user with sudo access and re-run." return 1 fi command -v git >/dev/null 2>&1 || sudo_run pacman -S --needed --noconfirm git sudo_run pacman -S --needed --noconfirm base-devel local build_dir build_dir="$(mktemp -d)" tui_info "Installing yay-bin (statically linked, works on any libalpm)..." if git clone https://aur.archlinux.org/yay-bin.git "$build_dir/yay-bin" && (cd "$build_dir/yay-bin" && makepkg -si --needed --noconfirm); then tui_success "yay installed" rm -rf "$build_dir" return 0 fi rm -rf "$build_dir" mkdir -p "$build_dir" tui_info "yay-bin failed. Trying paru-bin..." if git clone https://aur.archlinux.org/paru-bin.git "$build_dir/paru-bin" && (cd "$build_dir/paru-bin" && makepkg -si --needed --noconfirm) && paru --version >/dev/null 2>&1; then tui_success "paru works" rm -rf "$build_dir" return 0 fi rm -rf "$build_dir" tui_warn "No working AUR helper. Using direct git clone + makepkg for AUR packages." return 0 } install_aur() { local packages=("$@") local pkg local rc=0 for pkg in "${packages[@]}"; do if is_package_installed "$pkg"; then continue fi if have yay; then tui_info "Installing $pkg from AUR (via yay)..." if yay -S --needed --noconfirm "$pkg"; then tui_success "$pkg installed" continue fi tui_warn "yay failed for $pkg. Trying direct AUR install..." elif have paru && paru --version >/dev/null 2>&1; then tui_info "Installing $pkg from AUR (via paru)..." if paru -S --needed --noconfirm "$pkg"; then tui_success "$pkg installed" continue fi tui_warn "paru failed for $pkg. Trying direct AUR install..." fi if install_aur_package "$pkg"; then tui_success "$pkg installed" else tui_warn "$pkg could not be installed. Try manually:" tui_info " cd /tmp && git clone https://aur.archlinux.org/$pkg.git" tui_info " cd $pkg && makepkg -si" rc=1 fi done return $rc }