#!/usr/bin/env bash # Omeron - Modular System Setup Framework # Usage: ./install.sh [--fresh] [--modules m1,m2] [--skip-packages] [--with-sddm] [--help] set -euo pipefail OMERON_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" export OMERON_ROOT export OMERON_PROJECT_DIR="$OMERON_ROOT" source "$OMERON_ROOT/lib/log.sh" source "$OMERON_ROOT/lib/tui.sh" source "$OMERON_ROOT/lib/utils.sh" source "$OMERON_ROOT/lib/config.sh" source "$OMERON_ROOT/lib/modules.sh" OMERON_FRESH_INSTALL="${OMERON_FRESH_INSTALL:-0}" export OMERON_FRESH_INSTALL DEFAULT_MODULES=( "core/preflight" "core/packages" "core/dotfiles" "core/services" "homelab/setup" "optional/install" "core/sddm" "post/apply-theme" ) FRESH_MODULES=( "core/packages" "core/dotfiles" "core/services" "homelab/setup" "optional/install" "core/sddm" "post/apply-theme" ) RUN_MODULES=() SKIP_MODULES=() WITH_SDDM=0 usage() { cat </dev/null && declare -F "module_description" >/dev/null 2>&1; then description="$(module_description)" fi printf " %-30s %s\n" "$rel_path" "$description" done exit 0 } parse_args() { while [[ $# -gt 0 ]]; do case "$1" in --fresh) OMERON_FRESH_INSTALL=1; shift ;; --modules) IFS=',' read -ra RUN_MODULES <<< "$2"; shift 2 ;; --skip) IFS=',' read -ra SKIP_MODULES <<< "$2"; shift 2 ;; --skip-packages) SKIP_MODULES+=("core/packages"); shift ;; --with-sddm) WITH_SDDM=1; shift ;; --list-modules) list_modules ;; -h|--help) usage ;; *) echo "Unknown option: $1" >&2; usage ;; esac done } detect_environment() { tui_detect if ((!OMERON_HAS_GUM)) && have pacman; then printf '\033[1;36m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m\n' printf '\033[1;36m Ꮎ Ꮇ Ꭼ Ꮢ Ꮎ Ꮑ — Modular System Setup Framework\033[0m\n' printf '\033[1;36m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\033[0m\n' printf '\n' printf ' \033[1;33mgum is not installed.\033[0m Installing it enables the full TUI experience.\n' printf '\n' if tui_install_gum; then printf ' \033[1;32m✓ gum installed!\033[0m\n' else if ((OMERON_HAS_WHIPTAIL)); then printf ' \033[1;33musing whiptail as fallback\033[0m\n' else printf ' \033[1;33musing basic text mode (install gum for UI: pacman -S gum)\033[0m\n' fi fi printf '\n' fi if ((!OMERON_FRESH_INSTALL)) && ((${#RUN_MODULES[@]} == 0)); then log_info "Checking for fresh install..." if is_fresh_install; then OMERON_FRESH_INSTALL=1 export OMERON_FRESH_INSTALL fi fi if ((OMERON_FRESH_INSTALL)) && ((!OMERON_HAS_GUM)) && have pacman; then tui_install_gum 2>/dev/null || true fi } collect_modules() { if ((${#RUN_MODULES[@]})); then for mod in "${RUN_MODULES[@]}"; do local module_file="$OMERON_MODULE_DIR/$mod.sh" [[ -f "$module_file" ]] && printf '%s\n' "$module_file" done return fi local modules=() if ((OMERON_FRESH_INSTALL)); then modules=("${FRESH_MODULES[@]}") else modules=("${DEFAULT_MODULES[@]}") fi for mod in "${modules[@]}"; do local skip=0 for skipped in "${SKIP_MODULES[@]}"; do if [[ "$mod" == "$skipped" || "$mod" == "core/$skipped" ]]; then skip=1 break fi done [[ "$mod" == "core/sddm" && "$WITH_SDDM" -eq 0 && "$OMERON_FRESH_INSTALL" -eq 0 ]] && skip=1 ((skip)) && continue local module_file="$OMERON_MODULE_DIR/$mod.sh" [[ -f "$module_file" ]] && printf '%s\n' "$module_file" done } collect_all_interactive() { exec 3>&1 exec 1>&2 local modules=() if ((OMERON_FRESH_INSTALL)); then modules=("${FRESH_MODULES[@]}") else modules=("${DEFAULT_MODULES[@]}") fi local total=${#modules[@]} local idx=1 local module_order=() for mod in "${modules[@]}"; do local module_file="$OMERON_MODULE_DIR/$mod.sh" [[ -f "$module_file" ]] || continue source "$module_file" 2>/dev/null || continue local description="" if declare -F "module_description" >/dev/null 2>&1; then description="$(module_description)" fi printf '\n' log_step "$idx" "$total" "${description:-$mod}" if declare -F "module_required" >/dev/null 2>&1; then if module_required; then tui_info "Required module — will run" module_order+=("$module_file") ((idx++)) continue fi fi if tui_confirm "${description:-$mod}?"; then module_order+=("$module_file") else log_info "Skipped" fi ((idx++)) done printf '%s\n' "${module_order[@]}" >&3 exec 3>&- } show_banner() { tui_header " Ꮎ Ꮇ Ꭼ Ꮢ Ꮎ Ꮑ " tui_info "Modular System Setup Framework" tui_info "Arch / Hyprland / CachyOS" printf '\n' if ((OMERON_FRESH_INSTALL)); then tui_warn "FRESH INSTALL MODE" tui_info "Will install Hyprland, GPU drivers, and all dependencies." printf '\n' fi } show_summary() { local modules=("$@") tui_separator tui_bold "Installation Summary" tui_info "$(tui_bold "${#modules[@]}") module(s) to run" local gpu gpu="$(detect_gpu)" tui_info "Detected GPU: $(tui_bold "$gpu")" if ((${#modules[@]})); then printf '\n' tui_bold "Steps:" local i=1 for mod in "${modules[@]}"; do printf ' \033[1;36m%d.\033[0m %s\n' "$i" "$(basename "$mod" .sh)" ((i++)) done fi printf '\n' if ! tui_confirm "Proceed with installation?"; then tui_bold "Installation cancelled." exit 0 fi } main() { OMERON_LOG_FILE="${OMERON_LOG_FILE:-$HOME/.local/share/omeron/install-$(date +%Y%m%d-%H%M%S).log}" export OMERON_LOG_FILE parse_args "$@" mkdir -p "$(dirname "$OMERON_LOG_FILE")" log_info "Omeron installation started" log_info "Log file: $OMERON_LOG_FILE" log_info "Project: $OMERON_ROOT" detect_environment show_banner local modules_to_run=() if ((${#RUN_MODULES[@]})); then mapfile -t modules_to_run < <(collect_modules) else mapfile -t modules_to_run < <(collect_all_interactive) fi if ((${#modules_to_run[@]} == 0)); then tui_warn "No modules selected. Nothing to do." exit 0 fi show_summary "${modules_to_run[@]}" local total=${#modules_to_run[@]} local idx=1 for module_path in "${modules_to_run[@]}"; do local description="" if source "$module_path" 2>/dev/null && declare -F "module_description" >/dev/null 2>&1; then description="$(module_description)" fi printf '\n' log_step "$idx" "$total" "${description:-$(basename "$module_path" .sh)}" module_run "$module_path" || { local rc=$? if declare -F "module_required" >/dev/null 2>&1; then source "$module_path" if module_required 2>/dev/null; then tui_error "Required module failed. Aborting." exit $rc fi fi tui_warn "Module completed with warnings" } ((idx++)) done printf '\n' tui_header " Ꮎ Ꮇ Ꭼ Ꮢ Ꮎ Ꮑ " tui_success "Installation Complete!" printf '\n' tui_info "Log: ${OMERON_LOG_FILE}" printf '\n' if ((OMERON_FRESH_INSTALL)); then tui_bold "Your system is ready for Hyprland!" tui_list \ "Start Hyprland: Hyprland" \ "Or enable SDDM: sudo systemctl enable --now sddm" \ "Reload config: hyprctl reload" else tui_bold "What next?" tui_list \ "Reload config: hyprctl reload" \ "Re-run installer: ./install.sh" fi printf '\n' if have notify-send; then notify-send "Omeron" "Installation complete!" >/dev/null 2>&1 || true fi } main "$@"