Dotfiles/setup/tui-install.sh

201 lines
10 KiB
Bash
Executable File

#!/bin/bash
# tui-install.sh — TUI installer for the_miro's Arch dotfiles
set -uo pipefail
# ── Paths ─────────────────────────────────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DOTFILES_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
MODULES="$DOTFILES_DIR/setup/modules"
LOG="$HOME/dotfiles-install.log"
TMP_D="$(mktemp -d)"
trap 'rm -rf "$TMP_D"' EXIT
BACKTITLE="the_miro's Arch Dotfiles"
# ── Cyberqueer dialog theme ───────────────────────────────────────────────────
export DIALOGRC="$TMP_D/dialogrc"
cat > "$DIALOGRC" <<'EOF'
use_shadow = ON
use_colors = ON
screen_color = (BLACK,BLACK,ON)
shadow_color = (BLACK,BLACK,ON)
title_color = (MAGENTA,BLACK,ON)
border_color = (MAGENTA,BLACK,ON)
button_active_color = (BLACK,MAGENTA,ON)
button_inactive_color = (WHITE,BLACK,OFF)
button_key_active_color = (BLACK,CYAN,ON)
button_key_inactive_color = (CYAN,BLACK,ON)
button_label_active_color = (BLACK,MAGENTA,ON)
button_label_inactive_color = (WHITE,BLACK,OFF)
inputbox_color = (WHITE,BLACK,OFF)
inputbox_border_color = (MAGENTA,BLACK,ON)
menubox_color = (WHITE,BLACK,OFF)
menubox_border_color = (MAGENTA,BLACK,ON)
item_color = (WHITE,BLACK,OFF)
item_selected_color = (BLACK,MAGENTA,ON)
tag_color = (CYAN,BLACK,ON)
tag_selected_color = (BLACK,CYAN,ON)
tag_key_color = (CYAN,BLACK,ON)
tag_key_selected_color = (BLACK,CYAN,ON)
check_color = (WHITE,BLACK,OFF)
check_selected_color = (BLACK,MAGENTA,ON)
uarrow_color = (MAGENTA,BLACK,ON)
darrow_color = (MAGENTA,BLACK,ON)
EOF
# ── State ─────────────────────────────────────────────────────────────────────
STEP=0
TOTAL=0
# ── Helpers ───────────────────────────────────────────────────────────────────
require_dialog() {
command -v dialog &>/dev/null && return
echo "dialog not found — installing..."
sudo pacman -S --noconfirm dialog || { echo "Failed to install dialog."; exit 1; }
}
die() {
clear
printf "\n Error: %s\n\n" "$1" >&2
exit 1
}
log_sep() {
printf "\n══════════════════════════════════\n %s\n %s\n" "$1" "$(date)" >> "$LOG"
}
# Run a module script in the terminal (dialog is cleared so stdin/stdout work
# normally — pacman prompts, yay builds, etc. all function as expected).
run_module() {
local label="$1" script="$2"
STEP=$(( STEP + 1 ))
log_sep "[$STEP/$TOTAL] $label"
clear
printf "\n\033[1;35m [$STEP/$TOTAL] %s\033[0m\n" "$label"
printf "\033[35m ─────────────────────────────────────────────\033[0m\n\n"
local rc=0
bash "$script" 2>&1 | tee -a "$LOG" || rc=${PIPESTATUS[0]}
if [[ $rc -ne 0 ]]; then
dialog --backtitle "$BACKTITLE" \
--title " Module Failed " \
--yesno "$label exited with code $rc.\n\nContinue anyway?" 8 54 \
|| { clear; exit 1; }
fi
}
count_steps() {
local c="$1" de="$2"
TOTAL=0
[[ "$c" == *"pkg"* ]] && TOTAL=$(( TOTAL + 1 ))
[[ "$c" == *"core"* ]] && TOTAL=$(( TOTAL + 1 ))
[[ "$c" == *"svc"* ]] && TOTAL=$(( TOTAL + 1 ))
[[ "$c" == *"shell"* ]] && TOTAL=$(( TOTAL + 1 ))
[[ "$c" == *"de"* && "$de" != "none" ]] && TOTAL=$(( TOTAL + 1 ))
[[ "$c" == *"py"* ]] && TOTAL=$(( TOTAL + 1 ))
[[ "$c" == *"zfs"* ]] && TOTAL=$(( TOTAL + 1 ))
[[ "$c" == *"game"* ]] && TOTAL=$(( TOTAL + 1 ))
[[ "$c" == *"netdev"* ]] && TOTAL=$(( TOTAL + 1 ))
[[ "$c" == *"wprs"* ]] && TOTAL=$(( TOTAL + 1 ))
}
# ── Preflight ─────────────────────────────────────────────────────────────────
[[ $EUID -eq 0 ]] && die "Run as your normal user (not root)."
command -v pacman &>/dev/null || die "pacman not found — Arch Linux required."
require_dialog
> "$LOG"
printf "Dotfiles install: %s\nDotfiles dir: %s\n" "$(date)" "$DOTFILES_DIR" >> "$LOG"
# ── Welcome ───────────────────────────────────────────────────────────────────
dialog --backtitle "$BACKTITLE" \
--title " Welcome " \
--msgbox "\n\
the_miro's Arch dotfiles installer\n\
Cyberqueer · Wayland · Hyprland\n\
─────────────────────────────────────────\n\
\n\
Arch Linux — network admin, development & gaming\n\
\n\
Source: $DOTFILES_DIR\n\
Log: $LOG\n" 14 62
# ── Component selection ───────────────────────────────────────────────────────
COMPONENTS=$(dialog --backtitle "$BACKTITLE" \
--title " Select Components " \
--checklist "Space toggles · Enter confirms · Esc quits" 22 68 10 \
"pkg" "Package managers yay · nvm · rust" on \
"core" "Core packages 100+ base system packages" on \
"svc" "Core services NetworkManager · cronie · fail2ban" on \
"shell" "Shell setup zsh · nvim · yazi · micro · starship" on \
"de" "Desktop environment (choose on next screen)" off \
"py" "Python tools pyright · pipx · python-pynvim" off \
"zfs" "ZFS support zfs-dkms" off \
"game" "Gaming Steam · Vesktop · Spotify · Prism" off \
"netdev" "Network dev tools nmap · wireshark · kubectl" off \
"wprs" "WPRS wprs-git (AUR)" off \
3>&1 1>&2 2>&3) || { clear; echo "Aborted."; exit 0; }
# ── DE selection ──────────────────────────────────────────────────────────────
DE="none"
if [[ "$COMPONENTS" == *"de"* ]]; then
DE=$(dialog --backtitle "$BACKTITLE" \
--title " Desktop Environment " \
--menu "Select a desktop environment:" 11 56 3 \
"hyprland" "Hyprland — Wayland WM, full setup (primary)" \
"sway" "Sway — Wayland tiling WM" \
"none" "Skip DE installation" \
3>&1 1>&2 2>&3) || DE="none"
fi
# ── Confirmation ──────────────────────────────────────────────────────────────
SUMMARY=""
[[ "$COMPONENTS" == *"pkg"* ]] && SUMMARY+=" ✦ Package managers (yay, nvm, rust)\n"
[[ "$COMPONENTS" == *"core"* ]] && SUMMARY+=" ✦ Core packages\n"
[[ "$COMPONENTS" == *"svc"* ]] && SUMMARY+=" ✦ Core services\n"
[[ "$COMPONENTS" == *"shell"* ]] && SUMMARY+=" ✦ Shell setup\n"
[[ "$COMPONENTS" == *"de"* && "$DE" != "none" ]] && SUMMARY+=" ✦ Desktop environment: $DE\n"
[[ "$COMPONENTS" == *"py"* ]] && SUMMARY+=" ✦ Python tools\n"
[[ "$COMPONENTS" == *"zfs"* ]] && SUMMARY+=" ✦ ZFS support\n"
[[ "$COMPONENTS" == *"game"* ]] && SUMMARY+=" ✦ Gaming packages\n"
[[ "$COMPONENTS" == *"netdev"* ]] && SUMMARY+=" ✦ Network dev tools\n"
[[ "$COMPONENTS" == *"wprs"* ]] && SUMMARY+=" ✦ WPRS\n"
dialog --backtitle "$BACKTITLE" \
--title " Confirm Installation " \
--yesno "\n Components to install:\n\n${SUMMARY}\n Log: $LOG\n\n Proceed?" \
20 62 || { clear; echo "Aborted."; exit 0; }
count_steps "$COMPONENTS" "$DE"
# ── Installation ──────────────────────────────────────────────────────────────
[[ "$COMPONENTS" == *"pkg"* ]] && run_module "Package Managers" "$MODULES/package-managers.sh"
[[ "$COMPONENTS" == *"core"* ]] && run_module "Core Packages" "$MODULES/core-packages.sh"
[[ "$COMPONENTS" == *"svc"* ]] && run_module "Core Services" "$MODULES/core.sh"
[[ "$COMPONENTS" == *"shell"* ]] && run_module "Shell Setup" "$MODULES/shell-setup.sh"
if [[ "$COMPONENTS" == *"de"* && "$DE" != "none" ]]; then
case "$DE" in
hyprland) run_module "Hyprland" "$MODULES/Desktop-Enviroments/hyprland-new.sh" ;;
sway) run_module "Sway" "$MODULES/Desktop-Enviroments/sway.sh" ;;
esac
fi
[[ "$COMPONENTS" == *"py"* ]] && run_module "Python Tools" "$MODULES/optional-Modules/python.sh"
[[ "$COMPONENTS" == *"zfs"* ]] && run_module "ZFS" "$MODULES/optional-Modules/zfs.sh"
[[ "$COMPONENTS" == *"game"* ]] && run_module "Gaming Packages" "$MODULES/optional-Modules/gaming-packages.sh"
[[ "$COMPONENTS" == *"netdev"* ]] && run_module "Network Dev Tools" "$MODULES/optional-Modules/network-developer-packages.sh"
[[ "$COMPONENTS" == *"wprs"* ]] && run_module "WPRS" "$MODULES/optional-Modules/wprs.sh"
# ── Done ──────────────────────────────────────────────────────────────────────
dialog --backtitle "$BACKTITLE" \
--title " Done " \
--msgbox "\n All selected components installed.\n\n Log: $LOG\n\n A reboot may be required for all changes to take effect.\n" 12 58
clear
printf "\n Done. Log: %s\n\n" "$LOG"