#!/bin/bash # ABOUTME: Transforms an existing Arch+Wayland system into a Moonarch system. # ABOUTME: Backs up configs, installs packages, deploys all defaults with hard overwrite. set -euo pipefail source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib.sh" # ============================================================ # Phase 1: Prerequisites & Detection # ============================================================ check_not_root check_pacman # Require active Wayland session if [[ "${XDG_SESSION_TYPE:-}" != "wayland" ]] && [[ -z "${WAYLAND_DISPLAY:-}" ]]; then err "No active Wayland session detected. Transform requires Wayland." exit 1 fi # Detect conflicting display managers CONFLICTING_DMS=() for dm in sddm gdm lightdm ly lemurs; do if systemctl is-enabled "${dm}.service" &>/dev/null; then CONFLICTING_DMS+=("$dm") fi done # Detect conflicting packages CONFLICTING_PKGS=() if pacman -Qq pulseaudio &>/dev/null && ! pacman -Qq pipewire-pulse &>/dev/null; then CONFLICTING_PKGS+=("pulseaudio") fi # ============================================================ # Phase 2: Pre-flight Summary # ============================================================ echo "" log "============================================" log " Moonarch Transform — Pre-flight Summary" log "============================================" echo "" log "Wayland session: detected" if [[ ${#CONFLICTING_DMS[@]} -gt 0 ]]; then log "Display managers: ${CONFLICTING_DMS[*]} (will be disabled)" else log "Display managers: none conflicting" fi if [[ ${#CONFLICTING_PKGS[@]} -gt 0 ]]; then log "Package conflicts: ${CONFLICTING_PKGS[*]} (will be removed)" else log "Package conflicts: none" fi echo "" log "Actions:" log " 1. Backup ~/.config/, ~/.zshrc, /etc/xdg/ to ~/moonarch-backup-.tar.gz" log " 2. Install official + AUR packages" log " 3. Disable conflicting DMs, enable greetd" log " 4. Overwrite ALL system configs (/etc/xdg/, /etc/greetd/, ...)" log " 5. Overwrite ALL user configs (~/.config/)" log " 6. Configure zsh, GTK themes, firewall, services" echo "" err "This will REPLACE your current desktop configuration." echo "" if ! confirm "Proceed?"; then log "Transform cancelled." exit 0 fi # ============================================================ # Phase 3: Backup # ============================================================ BACKUP_FILE="$HOME/moonarch-backup-$(date +%Y%m%d-%H%M%S).tar.gz" log "Creating backup: $BACKUP_FILE" # Build list of paths that actually exist BACKUP_PATHS=() [[ -d "$HOME/.config" ]] && BACKUP_PATHS+=(".config") [[ -f "$HOME/.zshrc" ]] && BACKUP_PATHS+=(".zshrc") [[ -d "$HOME/.zshrc.d" ]] && BACKUP_PATHS+=(".zshrc.d") if [[ ${#BACKUP_PATHS[@]} -gt 0 ]]; then tar czf "$BACKUP_FILE" -C "$HOME" "${BACKUP_PATHS[@]}" log " + User configs backed up." fi # Backup system XDG separately (needs sudo) if [[ -d /etc/xdg ]]; then SYSTEM_BACKUP="$HOME/moonarch-backup-system-$(date +%Y%m%d-%H%M%S).tar.gz" sudo tar czf "$SYSTEM_BACKUP" -C / etc/xdg sudo chown "$USER:$USER" "$SYSTEM_BACKUP" log " + System configs backed up: $SYSTEM_BACKUP" fi log "Backup complete: $(du -h "$BACKUP_FILE" | cut -f1)" # ============================================================ # Phase 4: Disable Conflicting Display Managers # ============================================================ if [[ ${#CONFLICTING_DMS[@]} -gt 0 ]]; then log "Disabling conflicting display managers..." for dm in "${CONFLICTING_DMS[@]}"; do sudo systemctl disable "$dm" log " - $dm disabled" done fi # ============================================================ # Phase 5: Remove Conflicting Packages # ============================================================ if pacman -Qq pulseaudio &>/dev/null; then log "Removing PulseAudio (replaced by PipeWire)..." sudo pacman -Rdd --noconfirm pulseaudio pulseaudio-alsa pulseaudio-bluetooth 2>/dev/null || true fi # ============================================================ # Phase 6: Install Packages # ============================================================ log "Installing official packages..." if [[ -f "$OFFICIAL_PACKAGES" ]]; then # shellcheck disable=SC2046 sudo pacman -S --needed --noconfirm $(read_packages "$OFFICIAL_PACKAGES") else err "Package list not found: $OFFICIAL_PACKAGES" exit 1 fi # Install paru if not present if ! command -v paru &>/dev/null; then log "Installing paru..." PARU_TMPDIR=$(mktemp -d) git clone https://aur.archlinux.org/paru.git "$PARU_TMPDIR/paru" (cd "$PARU_TMPDIR/paru" && makepkg -si --noconfirm) rm -rf "$PARU_TMPDIR" else log "paru already installed." fi log "Installing AUR packages..." if [[ -f "$AUR_PACKAGES" ]]; then # shellcheck disable=SC2046 paru -S --needed --noconfirm $(read_packages "$AUR_PACKAGES") else err "AUR package list not found: $AUR_PACKAGES" exit 1 fi # Moonarch custom paru repo log "Setting up Moonarch paru repo..." PARU_CONF="$HOME/.config/paru/paru.conf" mkdir -p "$(dirname "$PARU_CONF")" if ! grep -q '\[moonarch\]' "$PARU_CONF" 2>/dev/null; then cat >> "$PARU_CONF" <<'EOCONF' [moonarch] Url = https://gitea.moonarch.de/nevaforget/moonarch-pkgbuilds.git EOCONF log " + Moonarch repo added to paru.conf." else log " ~ Moonarch repo already in paru.conf." fi paru -Sy --pkgbuilds --noconfirm paru -S --needed --noconfirm moonset-git moonlock-git moongreet-git # Themes log "Installing themes..." "$SCRIPT_DIR/install-themes.sh" # ============================================================ # Phase 7: Deploy System Configs (Hard Overwrite) # ============================================================ log "Deploying XDG defaults to /etc/xdg/..." sudo cp -r "$DEFAULTS_DIR/xdg/"* /etc/xdg/ sudo find /etc/xdg/rofi -name "*.sh" -exec chmod +x {} \; # GTK4 theme symlinks THEME_NAME="Colloid-Catppuccin" THEME_GTK4="/usr/share/themes/$THEME_NAME/gtk-4.0" GTK4_XDG="/etc/xdg/gtk-4.0" if [[ -d "$THEME_GTK4" ]]; then log "Creating system-wide GTK4 symlinks for $THEME_NAME..." sudo ln -sf "$THEME_GTK4/gtk-dark.css" "$GTK4_XDG/gtk.css" sudo ln -sf "$THEME_GTK4/gtk-dark.css" "$GTK4_XDG/gtk-dark.css" sudo rm -f "$GTK4_XDG/assets" sudo ln -s "$THEME_GTK4/assets" "$GTK4_XDG/assets" # libadwaita only reads user CSS from ~/.config/gtk-4.0/ USER_GTK4="$HOME/.config/gtk-4.0" mkdir -p "$USER_GTK4" ln -sf "$THEME_GTK4/gtk-dark.css" "$USER_GTK4/gtk.css" ln -sf "$THEME_GTK4/gtk-dark.css" "$USER_GTK4/gtk-dark.css" rm -f "$USER_GTK4/assets" ln -s "$THEME_GTK4/assets" "$USER_GTK4/assets" else err "GTK4 theme not found: $THEME_GTK4 — libadwaita apps will use fallback theme." fi # gsettings log "Setting gsettings for GTK theme..." gsettings set org.gnome.desktop.interface gtk-theme "$THEME_NAME" gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark' gsettings set org.gnome.desktop.interface icon-theme 'Colloid-Grey-Catppuccin-Dark' gsettings set org.gnome.desktop.interface font-name 'UbuntuSans Nerd Font 11' # Helper scripts log "Installing Moonarch helper scripts to /usr/local/bin/..." sudo install -m 755 "$DEFAULTS_DIR/bin/moonarch-"* /usr/local/bin/ # awww compatibility symlinks if command -v awww &>/dev/null && ! command -v swww &>/dev/null; then log "Creating swww -> awww compatibility symlinks..." sudo ln -s /usr/bin/awww /usr/local/bin/swww sudo ln -s /usr/bin/awww-daemon /usr/local/bin/swww-daemon fi # Zsh configuration log "Installing Zsh default config..." sudo cp "$DEFAULTS_DIR/shell/zshrc" /etc/zsh/zshrc.moonarch if ! grep -q "zshrc.moonarch" /etc/zsh/zshrc 2>/dev/null; then echo '# Moonarch defaults (overridden by ~/.zshrc)' | sudo tee -a /etc/zsh/zshrc > /dev/null echo '[[ ! -f "$HOME/.zshrc" ]] && source /etc/zsh/zshrc.moonarch' | sudo tee -a /etc/zsh/zshrc > /dev/null fi # For transform: always create a fresh .zshrc that sources Moonarch defaults log "Creating ~/.zshrc with Moonarch defaults..." mkdir -p "$HOME/.zshrc.d" echo "# Load Moonarch defaults, add custom overrides in ~/.zshrc.d/ or below" > "$HOME/.zshrc" echo "source /etc/zsh/zshrc.moonarch" >> "$HOME/.zshrc" # greetd / moongreet log "Configuring greetd + moongreet..." sudo mkdir -p /etc/greetd sudo cp "$DEFAULTS_DIR/etc/greetd/config.toml" /etc/greetd/config.toml sudo mkdir -p /etc/moongreet sudo cp "$DEFAULTS_DIR/etc/moongreet/moongreet.toml" /etc/moongreet/moongreet.toml # Niri greeter config (if present) if [[ -f "$DEFAULTS_DIR/etc/greetd/niri-greeter.kdl" ]]; then sudo cp "$DEFAULTS_DIR/etc/greetd/niri-greeter.kdl" /etc/greetd/niri-greeter.kdl fi # Wallpaper log "Installing default wallpaper..." sudo mkdir -p /usr/share/moonarch sudo cp "$DEFAULTS_DIR/backgrounds/wallpaper.jpg" /usr/share/moonarch/wallpaper.jpg # ============================================================ # Phase 8: Deploy User Configs (Hard Overwrite) # ============================================================ # Replace user-level XDG configs for all apps Moonarch manages log "Deploying XDG configs to ~/.config/ (overwrite)..." for src_dir in "$DEFAULTS_DIR/xdg/"*/; do app_name="$(basename "$src_dir")" # gtk-4.0 is handled separately with Colloid-Catppuccin theme symlinks (Phase 7) [[ "$app_name" == "gtk-4.0" ]] && continue dest_dir="$HOME/.config/$app_name" rm -rf "$dest_dir" cp -r "$src_dir" "$dest_dir" log " + $app_name/" done # Deploy user defaults (overwrite, no existence check) log "Deploying user config defaults to ~/.config/ (overwrite)..." USER_DEFAULTS_DIR="$DEFAULTS_DIR/user" if [[ -d "$USER_DEFAULTS_DIR" ]]; then for src_dir in "$USER_DEFAULTS_DIR"/*/; do app_name="$(basename "$src_dir")" dest_dir="$HOME/.config/$app_name" mkdir -p "$dest_dir" find "$src_dir" -type f -print0 | while IFS= read -r -d '' src_file; do rel_path="${src_file#"$src_dir"}" dest_file="$dest_dir/$rel_path" mkdir -p "$(dirname "$dest_file")" cp "$src_file" "$dest_file" log " + $app_name/$rel_path" done done fi # ============================================================ # Phase 9: Services & Finalization # ============================================================ log "Enabling services..." SERVICES=( "NetworkManager" "bluetooth" "docker" "greetd" "systemd-timesyncd" "ufw" "auto-cpufreq" ) for service in "${SERVICES[@]}"; do if systemctl list-unit-files "${service}.service" &>/dev/null; then sudo systemctl enable "$service" log " + $service" else log " ~ $service not found, skipped." fi done # Set shell to zsh if [[ "$SHELL" != */zsh ]]; then log "Setting default shell to zsh..." chsh -s "$(which zsh)" fi # Firewall log "Configuring UFW..." sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw --force enable # Docker group if ! groups | grep -q docker; then log "Adding user to docker group..." sudo usermod -aG docker "$USER" fi # Directories mkdir -p "$HOME/Pictures/Screenshots" mkdir -p "$HOME/Pictures/Wallpaper" # moonarch-update symlink log "Creating moonarch-update command..." sudo ln -sf "$PROJECT_DIR/scripts/update.sh" /usr/local/bin/moonarch-update # ============================================================ # Phase 10: Done # ============================================================ echo "" log "============================================" log " Moonarch transform complete!" log "============================================" echo "" log "Your previous config is backed up at:" log " $BACKUP_FILE" if [[ -n "${SYSTEM_BACKUP:-}" ]]; then log " $SYSTEM_BACKUP" fi echo "" log "Next steps:" log " 1. Reboot (greetd replaces your previous display manager)" log " 2. Place wallpapers in ~/Pictures/Wallpaper/" log " 3. rustup default stable" log " 4. User overrides in ~/.config/ or ~/.zshrc.d/" echo "" err "Do NOT log out — your previous DM is disabled. Reboot instead." echo ""