357 lines
9.0 KiB
Bash
Executable File
357 lines
9.0 KiB
Bash
Executable File
#!/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 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 <<SUMMARY
|
|
┌─────────────────────────────────────────────┐
|
|
│ System Summary │
|
|
├─────────────────────────────────────────────┤
|
|
│ OS: $(grep -oP '^PRETTY_NAME="?\K[^"\n]+' /etc/os-release 2>/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, or install paru manually:"
|
|
tui_info " pacman -S --needed git && git clone https://aur.archlinux.org/paru-bin.git"
|
|
tui_info " cd paru-bin && makepkg -si"
|
|
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 "Downloading paru-bin from AUR..."
|
|
if ! git clone https://aur.archlinux.org/paru-bin.git "$build_dir/paru-bin"; then
|
|
tui_error "Failed to download paru-bin. Check network connectivity."
|
|
rm -rf "$build_dir"
|
|
return 1
|
|
fi
|
|
|
|
tui_info "Building paru-bin with makepkg..."
|
|
if (cd "$build_dir/paru-bin" && makepkg -si --needed --noconfirm); then
|
|
tui_success "paru installed successfully"
|
|
rm -rf "$build_dir"
|
|
else
|
|
local rc=$?
|
|
tui_warn "makepkg failed (exit $rc). Trying yay-bin..."
|
|
rm -rf "$build_dir/paru-bin"
|
|
|
|
if git clone https://aur.archlinux.org/yay-bin.git "$build_dir/yay-bin"; then
|
|
if (cd "$build_dir/yay-bin" && makepkg -si --needed --noconfirm); then
|
|
tui_success "yay installed successfully"
|
|
rm -rf "$build_dir"
|
|
else
|
|
tui_warn "Could not install AUR helper. Install manually:"
|
|
tui_info " cd /tmp && git clone https://aur.archlinux.org/paru-bin.git"
|
|
tui_info " cd paru-bin && makepkg -si"
|
|
rm -rf "$build_dir"
|
|
return 1
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if have paru; then
|
|
tui_info "Verifying paru..."
|
|
if paru --version >/dev/null 2>&1; then
|
|
tui_success "paru works"
|
|
return 0
|
|
else
|
|
tui_warn "paru binary installed but fails to run. Falling back to direct AUR installs."
|
|
tui_info "Will install AUR packages via git clone + makepkg instead."
|
|
fi
|
|
fi
|
|
|
|
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 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
|
|
}
|