#!/usr/bin/env bash trap 'log WARN "Interrupted by user"; exit 130' INT INSTALL_STATUS="none" # none | partial | complete | failed AUTO_YES=0 for arg in "$@"; do case "$arg" in --yes|--ci|--non-interactive) AUTO_YES=1 ;; esac done log() { local level="$1" shift local color reset='\033[0m' case "$level" in INFO) color='\033[0;34m' ;; # Blue WARN) color='\033[0;33m' ;; # Yellow ERROR) color='\033[0;31m' ;; # Red SUCCESS) color='\033[0;32m' ;; # Green *) color='\033[0m' ;; esac printf '%b[%s] [%s]%b %s\n' \ "$color" "$(date '+%H:%M:%S')" "$level" "$reset" "$*" >&2 } ## Prevent user from running this script as root if [[ "$EUID" -eq 0 ]]; then log ERROR "This script must NOT be run as root." log INFO "If you need elevated privileges, the script will ask for sudo when required." exit 1 fi ## Check if gum is installed if ! command -v gum >/dev/null 2>&1; then echo "gum is required. Install it first." exit 1 fi ## Check if git is installed if ! command -v git >/dev/null 2>&1; then echo "git is required. Install it first." exit 1 fi currentDir="$(dirname "$(readlink -f "$0")")" cd "$currentDir" choose_packages() { local -n arr=$1 gum choose --no-limit \ --selected "$(IFS=,; echo "${arr[*]}")" \ "${arr[@]}" } prompt_style() { gum style \ --border rounded \ --padding "0 1" \ "$1" } gum_warn(){ gum style --bold --foreground 196 "⚠ $1" } gum_to_array() { local -n arr="$1" mapfile -t arr local cleaned=() for item in "${arr[@]}"; do [[ -n "$item" ]] && cleaned+=("$item") done arr=("${cleaned[@]}") } confirm() { local msg="$1" if ((AUTO_YES)); then log INFO "[auto] $msg → yes" return 0 fi gum confirm --default=false "$msg" } ################# ## GATEKEEPING ## ################# DISCLAIMER=$(gum style \ --border double \ --border-foreground 196 \ --padding "1 2" \ --bold \ "⚠️ DISCLAIMER This script is provided AS IS, WITHOUT ANY WARRANTY. There is NO guarantee that it will work on your system. It may: • Modify system files • Overwrite or DELETE existing configuration • Potentially break your setup You are STRONGLY ADVISED to back up: • ~/.config • ~/.local • /etc (if modified) Proceed at your OWN RISK." ) confirm "$DISCLAIMER Do you understand the risks and want to continue?" || exit 1 ########### ## UTILS ## ########### source "$currentDir/packages/pkg_utils.sh" prompt_style "Important utilities (Most likely go with defaults)" if ((AUTO_YES)); then DEV_PKGS=("${pkg_utils[@]}") else gum_to_array UTILITY_PKGS < <(choose_packages pkg_utils) fi ############### ## DEV TOOLS ## ############### source "$currentDir/packages/pkg_dev_tools.sh" prompt_style "Select Development Tools" if ((AUTO_YES)); then DEV_PKGS=("${pkg_dev_tools[@]}") else gum_to_array DEV_PKGS < <(choose_packages pkg_dev_tools) fi ####################### ## OPTIONAL PACKAGES ## ####################### source "$currentDir/packages/pkg_optional.sh" prompt_style "Select Optional Desktop Packages" if ((AUTO_YES)); then OPTIONAL_PKGS=("${pkg_optional[@]}") else gum_to_array OPTIONAL_PKGS < <(choose_packages pkg_optional) fi ################# ## GPU DRIVERS ## ################# source "$currentDir/packages/pkg_gpu.sh" prompt_style "Select GPU drivers" if ((AUTO_YES)); then GPU_PKGS=("${pkg_gpu[@]}") else gum_to_array GPU_PKGS < <(choose_packages pkg_gpu) fi ################## ## AUR PACKAGES ## ################## source "$currentDir/packages/pkg_aur.sh" prompt_style "Select AUR packages" if ((AUTO_YES)); then AUR_PKGS=("${pkg_aur[@]}") else gum_to_array AUR_PKGS < <(choose_packages pkg_aur) fi ########################## ## Configure Everything ## ########################## WARNING=$(gum style \ --border double \ --border-foreground 196 \ --padding "1 2" \ --bold \ "⚠️ This will DELETE any conflicting files and replace them with symlinks from this repo. Make sure you have already backed up all your existing config files (~/.config)") if confirm "$WARNING Proceed with system configuration (stow, shell)?"; then ################### ## Stow dotfiles ## ################### log INFO "Detecting conflicts..." conflicts=$(stow . --no-folding -nv 2>&1 | \ sed -n 's/.*existing target \(.*\) since neither.*/\1/p') if [[ -z "$conflicts" ]]; then log INFO "No conflicts. Running stow normally..." stow . --no-folding \ && log SUCCESS "Dotfiles stowed successfully" \ || log ERROR "Stow failed" else log WARN "These paths conflict and will be removed:" printf ' %s\n' $conflicts read -rp "Proceed with deleting these files? (y/N): " ok if [[ ! "$ok" =~ ^[Yy]$ ]]; then log WARN "Aborted." exit 1 fi # Remove conflicts relative to $HOME for path in $conflicts; do [[ -n "$path" && "$path" != "/" ]] && rm -rf "$HOME/$path" && log INFO "Deleted $path" done log INFO "Running stow..." stow . --no-folding \ && log INFO "✅ Dotfiles stowed with overwrite." \ || log ERROR "Stow failed" fi ################################# ## Change default shell to zsh ## ################################# log INFO "Changing the default shell to ZSH" if [[ "$SHELL" != "$(command -v zsh)" ]]; then chsh -s $(which zsh) \ && log SUCCESS "Default shell successfully set to zsh" \ || log ERROR "Default shell could not be set to zsh" else log INFO "Skipping: zsh is already the default shell" fi else log WARN "Aborted configuration, didn't configure anything" exit 1 fi ######################## ## Install Everything ## ######################## source "$currentDir/packages/pkg_desktop.sh" ALL_PKGS=( "${DEV_PKGS[@]}" "${OPTIONAL_PKGS[@]}" "${GPU_PKGS[@]}" "${UTILITY_PKGS[@]}" "${AUR_PKGS[@]}" "${pkg_desktop[@]}" ) if ((${#ALL_PKGS[@]})); then if confirm "Install all the selected packages?"; then log INFO "Installing selected packages..." ## Installing paru if not installed already if ! command -v paru >/dev/null 2>&1; then log INFO "Installing Paru (AUR package manager)" git clone https://aur.archlinux.org/paru.git (cd paru && makepkg -sri) rm -rf paru fi if paru -Syu --needed "${ALL_PKGS[@]}"; then INSTALL_STATUS="complete" else INSTALL_STATUS="failed" fi else log WARN "Package installation skipped by user" INSTALL_STATUS="partial" fi else log WARN "No packages selected" INSTALL_STATUS="partial" fi ########################## ## Install AUR Packages ## ########################## if ((${#AUR_PKGS[@]})); then if ! command -v paru >/dev/null 2>&1; then log INFO "Installing Paru (AUR package manager)" git clone https://aur.archlinux.org/paru.git (cd paru && makepkg -sri) rm -rf paru fi paru -S --needed "${AUR_PKGS[@]}" else log WARN "No AUR packages selected" fi ################ ## Setup Keyd ## ################ if command -v keyd >/dev/null 2>&1; then if confirm "Configure and enable keyd? "; then log INFO "Copying keyd configuration to /etc/keyd/default.conf" sudo cp "$currentDir/system/etc/keyd/default.conf" /etc/keyd/ sudo systemctl enable --now keyd.service \ && log SUCCESS "Successfully enabled keyd.service" \ || log ERROR "Couldn't enable keyd.service" fi fi case "$INSTALL_STATUS" in complete) gum style \ --border rounded \ --border-foreground 42 \ --padding "1 2" \ --bold \ "✔ Installation Complete! All selected packages were installed successfully. You may now reboot the system for all the changes to apply." ;; partial) gum style \ --border rounded \ --border-foreground 220 \ --padding "1 2" \ --bold \ "⚠ Setup Finished (Partial) Some steps were skipped by user choice. Your system was NOT fully configured." ;; failed) gum style \ --border rounded \ --border-foreground 196 \ --padding "1 2" \ --bold \ "❌ Installation Failed One or more steps did not complete successfully. Check the logs above." ;; *) gum style --bold "Finished." ;; esac