#!/bin/bash # Honor SOURCE_DIR from caller (run_once template) to avoid chezmoi-state-lock # contention when this script runs as part of `chezmoi apply`. Fall back to # `chezmoi source-path` and finally to the canonical default. SOURCE_DIR="${SOURCE_DIR:-$(chezmoi source-path 2>/dev/null)}" SOURCE_DIR="${SOURCE_DIR:-$HOME/.local/share/chezmoi}" . "$SOURCE_DIR/scripts/utils" # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - install_homebrew() { if ! cmd_exists "brew"; then echo "🍺 Installing Homebrew..." /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" # Setup Homebrew in PATH if [ -f /opt/homebrew/bin/brew ]; then eval "$(/opt/homebrew/bin/brew shellenv)" echo "✅ Homebrew installed and configured" else echo "❌ Failed to install Homebrew" return 1 fi else echo "✅ Homebrew already installed" fi } install_gum() { if ! cmd_exists "gum"; then echo "🎨 Installing gum for enhanced UI..." if cmd_exists "brew"; then brew install gum echo "✅ Gum installed successfully" else echo "❌ Homebrew not available, cannot install gum" return 1 fi else echo "✅ Gum already installed" fi } install_chezmoi() { if ! cmd_exists "chezmoi"; then echo "" print_in_purple "🏠 Installing and configuring Chezmoi" brew install chezmoi # Check if dotfiles are already cloned if [ ! -d "$HOME/.local/share/chezmoi" ]; then git clone git@github.com:joelazar/dotfiles.git ~/.local/share/chezmoi print_result $? "Cloned dotfiles repository" else print_success "Dotfiles repository already exists" fi # Initialize and apply Chezmoi chezmoi init print_result $? "Initialized Chezmoi" chezmoi apply print_result $? "Applied Chezmoi configuration" else print_success "Chezmoi already installed" fi } install_brew_packages() { echo "" print_in_purple "🍺 Installing packages from Brewfile" local brewfile="" if [ "$(chezmoi data | jq -r '.type // ""')" = "work" ]; then print_info "Using work Brewfile" brewfile="$SOURCE_DIR/Brewfile.work" elif [ "$(chezmoi data | jq -r '.type // ""')" = "workstation" ]; then print_info "Using workstation Brewfile" brewfile="$SOURCE_DIR/Brewfile.workstation" else print_info "Using private Brewfile" brewfile="$SOURCE_DIR/Brewfile.private" fi if [ -f "$brewfile" ]; then echo brew bundle --file="$brewfile" brew bundle --file="$brewfile" print_result $? "Installed packages from $(basename "$brewfile")" else print_error "$(basename "$brewfile") not found" fi } install_rust() { if ! cmd_exists "rustc"; then echo "" print_in_purple "🦀 Installing Rust using rustup" curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y print_success "Rust installed and configured" else print_success "Rust already installed" fi } install_magic() { if ! cmd_exists "magic"; then echo "" print_in_purple "🪄 Installing Magic from Modular" # Install Magic curl -ssL https://magic.modular.com/deb13a78-95b6-40bf-8bd0-52802eb302a8 | bash print_result $? "Install Magic" # Add fish completion if fish is the shell if [ "$SHELL" = "/opt/homebrew/bin/fish" ] && [ -d "$HOME/.config/fish/completions" ]; then # Check if completion already added if ! grep -q "magic completion" "$HOME/.config/fish/completions/magic.fish" 2>/dev/null; then echo 'magic completion --shell fish | source' >>"$HOME/.config/fish/completions/magic.fish" if echo 'magic completion --shell fish | source' >>"$HOME/.config/fish/completions/magic.fish"; then print_success "Added Magic completion to fish" else print_error "Failed to add Magic completion to fish" fi else print_success "Magic fish completion already configured" fi fi else print_success "Magic already installed" fi } setup_github_cli() { # Check if gh is installed and authenticated if cmd_exists "gh"; then # Check if authenticated if ! gh auth status &>/dev/null; then print_warning "GitHub CLI not authenticated. Please authenticate first by running:\n gh auth login" print_warning "Plugin installation may fail without authentication." ask_for_confirmation "Would you like to authenticate now?" if answer_is_yes; then execute "gh auth login" "Authenticate GitHub CLI" fi else print_success "GitHub CLI authenticated" fi return 0 else print_error "GitHub CLI (gh) not installed. Install it with 'brew install gh' first." return 1 fi } install_yazi_plugins() { local -a plugin_list=("${@}") if cmd_exists "yazi"; then echo "" print_in_purple "📁 Installing Yazi plugins" # Make sure yazi config directory exists mkdir -p ~/.config/yazi/flavors # Get list of installed plugins installed_plugins=$(ya pkg list 2>/dev/null | awk '{print $1}') for plugin in "${plugin_list[@]}"; do # Declare and assign separately to avoid masking return values local plugin_name plugin_name=$(echo "$plugin" | cut -d: -f2 2>/dev/null || echo "$plugin" | cut -d/ -f2) if ! echo "$installed_plugins" | grep -q "$plugin_name"; then execute "ya pkg add $plugin" "Yazi $plugin_name plugin" else print_success "Yazi $plugin_name plugin already installed" fi done # Install theme if not already present if [ ! -d "$HOME/.config/yazi/flavors/catppuccin-mocha.yazi" ]; then execute "git clone https://github.com/yazi-rs/flavors.git /tmp/yazi-flavors-clone && cp -R /tmp/yazi-flavors-clone/catppuccin-mocha.yazi ~/.config/yazi/flavors/ && rm -rf /tmp/yazi-flavors-clone" "Yazi Catppuccin Mocha theme" else print_success "Yazi Catppuccin Mocha theme already installed" fi # Clean up old tokyo-night theme if [ -d "$HOME/.config/yazi/flavors/tokyo-night.yazi" ]; then rm -rf "$HOME/.config/yazi/flavors/tokyo-night.yazi" print_success "Removed old Yazi Tokyo Night theme" fi else print_warning "Yazi not installed. Skipping Yazi plugins installation." print_warning "Install Yazi first with 'brew install yazi' and re-run this script." fi } install_fish_plugin() { declare -r PACKAGEPATH="$1" declare -r PACKAGENAME="$2" execute "fish -c \"fisher install $PACKAGEPATH\"" "$PACKAGENAME" } install_go_package() { declare -r PACKAGEPATH="$1" declare -r PACKAGENAME="$2" execute "go install $PACKAGEPATH" "$PACKAGENAME" } install_bun_package() { declare -r PACKAGENAME="$1" execute "bun install -g $PACKAGENAME" "$PACKAGENAME" } install_npm_package() { declare -r PACKAGENAME="$1" execute "npm install -g $PACKAGENAME" "$PACKAGENAME" } install_rust_package() { declare -r PACKAGENAME="$1" execute "cargo install $PACKAGENAME" "$PACKAGENAME" } install_pip_package() { declare -r PACKAGENAME="$1" execute "pip install --upgrade $PACKAGENAME" "$PACKAGENAME" } install_gh_plugin() { declare -r PLUGIN="$1" declare -r INSTALLED_PLUGINS=$(gh extension list) if ! echo "$INSTALLED_PLUGINS" | grep -q "$PLUGIN"; then execute "gh extension install $PLUGIN" "$PLUGIN" else print_success "$PLUGIN" fi } install_uv_tool() { declare -r PACKAGENAME="$1" execute "uv tool install $PACKAGENAME" "$PACKAGENAME" } install_pi_package() { declare -r PACKAGENAME="$1" execute "pi install $PACKAGENAME" "$PACKAGENAME" } install_packages_from_list() { local -r type="$1" local -r installer="$2" local -a packages=("${@:3}") # Skip empty package lists so we don't print a header with nothing under it. if [ "${#packages[@]}" -eq 0 ]; then return 0 fi echo "" print_in_purple "$type packages" for package in "${packages[@]}"; do $installer "$package" done }