#!/bin/bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(dirname "$SCRIPT_DIR")" REBOOT_MARKER="$REPO_ROOT/.setup-reboot-required" REPO_SECRET_FILE="$REPO_ROOT/Zsh/.zsh_secrets" HOME_SECRET_FILE="$HOME/.zsh_secrets" BACKUP_ROOT="$HOME/.dotzsh-pre-stow-backup" handle_reboot_marker() { if [ -f "$REBOOT_MARKER" ]; then rm -f "$REBOOT_MARKER" echo "Package layering finished. Reboot, then rerun the same command." exit 0 fi } sync_repo_managed_secret_file() { local home_secret_resolved repo_secret_resolved mkdir -p "$(dirname "$REPO_SECRET_FILE")" if [ -L "$HOME_SECRET_FILE" ]; then home_secret_resolved="$(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$HOME_SECRET_FILE")" repo_secret_resolved="$(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$REPO_SECRET_FILE")" if [ "$home_secret_resolved" = "$repo_secret_resolved" ]; then return 0 fi if [ -f "$home_secret_resolved" ]; then if [ ! -f "$REPO_SECRET_FILE" ] || [ ! -s "$REPO_SECRET_FILE" ]; then cp "$home_secret_resolved" "$REPO_SECRET_FILE" rm -f "$HOME_SECRET_FILE" return 0 fi if cmp -s "$home_secret_resolved" "$REPO_SECRET_FILE"; then rm -f "$HOME_SECRET_FILE" return 0 fi fi echo "Conflict: $HOME_SECRET_FILE points to a different secret file than $REPO_SECRET_FILE." echo "Please merge them manually, then rerun the command." exit 1 fi if [ -f "$HOME_SECRET_FILE" ]; then if [ ! -f "$REPO_SECRET_FILE" ] || [ ! -s "$REPO_SECRET_FILE" ]; then mv "$HOME_SECRET_FILE" "$REPO_SECRET_FILE" return 0 fi if cmp -s "$HOME_SECRET_FILE" "$REPO_SECRET_FILE"; then rm -f "$HOME_SECRET_FILE" return 0 fi echo "Conflict: both $HOME_SECRET_FILE and $REPO_SECRET_FILE exist with different contents." echo "Please merge them manually, then rerun the command." exit 1 fi touch "$REPO_SECRET_FILE" } backup_conflicting_home_files() { local backup_dir backed_up_any=0 source_file filename target_file target_resolved source_resolved backup_dir="$BACKUP_ROOT/$(date +%Y%m%d-%H%M%S)" while IFS= read -r source_file; do filename="$(basename "$source_file")" target_file="$HOME/$filename" if [ -L "$target_file" ]; then target_resolved="$(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$target_file")" source_resolved="$(python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$source_file")" if [ "$target_resolved" = "$source_resolved" ]; then continue fi mkdir -p "$backup_dir" mv "$target_file" "$backup_dir/$filename" echo "Backed up existing linked $target_file -> $backup_dir/$filename" backed_up_any=1 elif [ -e "$target_file" ]; then mkdir -p "$backup_dir" mv "$target_file" "$backup_dir/$filename" echo "Backed up existing $target_file -> $backup_dir/$filename" backed_up_any=1 fi done < <(find "$REPO_ROOT/Zsh" -mindepth 1 -maxdepth 1 -type f -name '.*' ! -name '.zsh_secrets') if [ "$backed_up_any" -eq 1 ]; then echo "Existing unmanaged dotfiles were backed up before stowing." fi } stow_dotfiles() { echo "Preparing repo-managed secrets for stow..." sync_repo_managed_secret_file echo "Checking for conflicting home dotfiles before stow..." backup_conflicting_home_files echo "Cleaning existing Zsh stow links..." stow --dir="$REPO_ROOT" -D Zsh --target="$HOME" 2>/dev/null || true echo "Stowing Zsh dotfiles..." stow --dir="$REPO_ROOT" Zsh --target="$HOME" echo "Zsh dotfiles stowed." } bootstrap_only() { rm -f "$REBOOT_MARKER" bash "$SCRIPT_DIR/base.sh" handle_reboot_marker stow_dotfiles echo "Bootstrap setup completed." } full_setup() { rm -f "$REBOOT_MARKER" bash "$SCRIPT_DIR/base.sh" handle_reboot_marker bash "$SCRIPT_DIR/node.sh" bash "$SCRIPT_DIR/go.sh" bash "$SCRIPT_DIR/rust.sh" bash "$SCRIPT_DIR/python.sh" handle_reboot_marker bash "$SCRIPT_DIR/r.sh" handle_reboot_marker stow_dotfiles echo "Full setup completed." } case "${1:-}" in --bootstrap-only) bootstrap_only ;; --stow-only) stow_dotfiles ;; "") full_setup ;; *) echo "Usage: $0 [--bootstrap-only|--stow-only]" exit 1 ;; esac