#!/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" "post/apply-theme" "core/sddm" ) FRESH_MODULES=( "core/packages" "core/dotfiles" "core/services" "homelab/setup" "optional/install" "post/apply-theme" "core/sddm" ) 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 O M E R O N — 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)); then if ((!OMERON_HAS_GUM)) && have pacman; then tui_install_gum 2>/dev/null || true fi if ! have paru && ! have yay; then install_aur_helper fi 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 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 if declare -F "module_required" >/dev/null 2>&1; then if module_required; then module_order+=("$module_file") continue fi fi printf ' ' if tui_confirm "${description:-$mod}"; then module_order+=("$module_file") fi done printf '%s\n' "${module_order[@]}" >&3 exec 3>&- } show_banner() { tui_header "O M E R O N — Modular System Setup" printf '\n' if ((OMERON_FRESH_INSTALL)); then tui_info "Fresh install: Hyprland + GPU drivers + all dependencies" printf '\n' 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 tui_separator printf '\n' if ! tui_confirm "Continue with installation"; then tui_info "Installation cancelled." exit 0 fi printf '\n' 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 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 "O M E R O N — Done" 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 "$@"