#!/usr/bin/env bash set -eo pipefail # Function to manage directory symlinks # Usage: ensure_dir_symlink # Args: # source_dir: The actual directory to symlink to (must be absolute path) # target_link: The symlink location to create # force_flag: true/false - whether to force replacement if exists ensure_dir_symlink() { local source_dir="$1" local target_link="$2" local force_flag="$3" # Expand tilde in paths target_link="${target_link/#\~/$HOME}" source_dir="${source_dir/#\~/$HOME}" # Check if target exists if [[ -e "$target_link" || -L "$target_link" ]]; then # Check if it's already a symlink pointing to the right place if [[ -L "$target_link" ]]; then local current_target current_target="$(readlink "$target_link")" if [[ "$current_target" == "$source_dir" ]]; then echo "✓ $target_link already symlinked correctly" return 0 else # Symlink exists but points to wrong location if [[ "$force_flag" == true ]]; then echo "Replacing symlink $target_link (currently points to $current_target)" rm "$target_link" else echo "⚠ Warning: $target_link exists but points to $current_target (expected $source_dir)" echo " Run with --force-deploy to replace it" return 0 fi fi else # Path exists but is not a symlink if [[ "$force_flag" == true ]]; then echo "Replacing $target_link with symlink (was a regular file/directory)" rm -rf "$target_link" else echo "⚠ Warning: $target_link exists but is not a symlink" echo " Run with --force-deploy to replace it" return 0 fi fi fi # Create parent directory if needed local parent_dir parent_dir="$(dirname "$target_link")" if [[ ! -d "$parent_dir" ]]; then echo "Creating parent directory: $parent_dir" mkdir -p "$parent_dir" fi # Create the symlink echo "Creating symlink: $target_link -> $source_dir" ln -s "$source_dir" "$target_link" echo "✓ Successfully created symlink" } # Parse command line arguments RESET_CONFIG=false FORCE_DEPLOY=false SKIP_BREW=false for arg in "$@"; do case $arg in --reset) RESET_CONFIG=true echo "Resetting configuration (will re-prompt for all variables)..." ;; --force-deploy) FORCE_DEPLOY=true echo "Force deployment mode enabled..." ;; --skip-brew) SKIP_BREW=true echo "Skipping Homebrew package installation..." ;; *) echo "Unknown option: $arg" echo "Usage: $0 [--reset] [--force-deploy] [--skip-brew]" exit 1 ;; esac done echo "Setting up dotfiles environment..." # Detect OS OS="$(uname -s)" if [[ "$SKIP_BREW" == false ]]; then # Check if Homebrew is installed if ! command -v brew &> /dev/null; then echo "Homebrew is not installed. Please install it first:" echo "https://brew.sh" exit 1 fi echo "Updating Homebrew..." brew update # Install packages (available on both macOS and Linux) PACKAGES=( dotter fish dust eza gh htop go jq lazygit neovim asdf bat pandoc ripgrep zoxide zellij p7zip ) echo "Installing packages..." for package in "${PACKAGES[@]}"; do if brew list "$package" &>/dev/null; then echo "✓ $package already installed" else echo "Installing $package..." brew install "$package" fi done # Install casks on macOS only if [[ "$OS" == "Darwin" ]]; then echo "Installing macOS-specific casks..." CASKS=( iterm2 font-fira-code-nerd-font orbstack rectangle-pro maccy ) for cask in "${CASKS[@]}"; do if brew list --cask "$cask" &>/dev/null; then echo "✓ $cask already installed" else echo "Installing $cask..." brew install --cask "$cask" fi done else echo "Skipping macOS-specific casks (not on macOS)" fi fi # Set up GitHub CLI authentication if command -v gh &> /dev/null; then if ! gh auth status &>/dev/null; then echo "" echo "GitHub CLI is installed but not authenticated." echo "Please log in to GitHub CLI:" gh auth login else echo "✓ GitHub CLI already authenticated" fi fi # Configure Dotter echo "" echo "Configuring Dotter..." # Path to user variables file USER_VARS_FILE=".dotter/user_vars.sh" # Source existing variables if not resetting if [[ "$RESET_CONFIG" == false && -f "$USER_VARS_FILE" ]]; then echo "Loading existing configuration..." source "$USER_VARS_FILE" fi # Prompt for missing variables if [[ -z "$GIT_NAME" ]]; then read -p "Enter your Git user name: " GIT_NAME fi if [[ -z "$GIT_EMAIL" ]]; then read -p "Enter your Git email: " GIT_EMAIL fi # Detect Homebrew path if not set if [[ -z "$BREW_PATH" ]]; then if [[ "$OS" == "Darwin" ]]; then if [[ -d "/opt/homebrew" ]]; then BREW_PATH="/opt/homebrew" else BREW_PATH="/usr/local" fi else BREW_PATH="/home/linuxbrew/.linuxbrew" fi echo "Detected Homebrew path: $BREW_PATH" fi # Save variables to file echo "Saving configuration..." cat > "$USER_VARS_FILE" << EOF # Dotter user variables # This file is sourced by setup.sh to avoid re-prompting for values # To reset and re-prompt for all values, run: ./setup.sh --reset GIT_NAME="$GIT_NAME" GIT_EMAIL="$GIT_EMAIL" BREW_PATH="$BREW_PATH" EOF # Generate local.toml echo "Generating Dotter configuration..." cat > .dotter/local.toml << EOF # Machine-specific Dotter configuration # This file is generated by setup.sh packages = ["git", "nvim", "fish", "zellij", "htop", "asdf"] [variables] git_name = "$GIT_NAME" git_email = "$GIT_EMAIL" brew_path = "$BREW_PATH" EOF # Deploy dotfiles echo "" echo "Deploying dotfiles..." if [[ "$FORCE_DEPLOY" == true ]]; then if dotter deploy -f -v; then echo "✓ Dotfiles deployed successfully (forced)!" else echo "⚠ Dotter deployment failed." fi else if dotter deploy -v; then echo "✓ Dotfiles deployed successfully!" else echo "⚠ Dotter deployment failed. You may need to run 'dotter deploy -f' to force deployment." fi fi # Manage directory symlinks (not handled by Dotter) echo "" echo "Setting up directory symlinks..." DOTFILES_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ensure_dir_symlink "$DOTFILES_DIR/fish/functions" "~/.config/fish/functions" "$FORCE_DEPLOY" echo "" echo "✓ Setup complete!" echo "" echo "Configuration saved to: $USER_VARS_FILE" echo "To reconfigure, run: ./setup.sh --reset" echo "To force deployment, run: ./setup.sh --force-deploy" echo "To skip Homebrew packages, run: ./setup.sh --skip-brew" echo "" echo "Next steps:" echo " 1. Consider setting fish as your default shell: chsh -s \$(which fish)" echo " 2. Restart your terminal or source your new shell configuration"