#!/bin/bash # # Dotfiles Bootstrap Script # # This script automates the setup of a high-performance, Rust-powered # command-line environment. It uses a hybrid sequential/parallel approach. # # Flags: # --extended: Performs a "desktop" setup: installs GUI fonts and changes the default shell. # --docker: Installs Docker Engine. set -e # Exit immediately if a command exits with a non-zero status. # --- Helper Functions for Logging --- info() { echo -e "\033[1;34m==> $1\033[0m"; } success() { echo -e "\033[1;32m✅ $1\033[0m"; } warn() { echo -e "\033[1;33m⚠️ $1\033[0m"; } # --- Argument Parsing & Environment Setup --- EXTENDED_INSTALL=false DOCKER_INSTALL=false [[ " $* " =~ " --extended " ]] && EXTENDED_INSTALL=true [[ " $* " =~ " --docker " ]] && DOCKER_INSTALL=true # Phased installation package lists PREREQ_PACKAGES=(git stow) SYSTEM_PACKAGES=(curl tmux btop fish) RUST_PACKAGES=( eza bat ripgrep zoxide starship bob-nvim atuin dua-cli cargo-cache ) # Global variables for system context SUDO_CMD="" PM="" OS_ID="" # --- Prerequisite Functions (Unchanged) --- detect_os_and_pm() { info "Detecting OS and Package Manager..." if [ -f /etc/os-release ]; then . /etc/os-release OS_ID=$ID fi if [[ "$(uname)" == "Darwin" ]]; then PM="brew" elif command -v apt-get &>/dev/null; then PM="apt-get" elif command -v dnf &>/dev/null; then PM="dnf" elif command -v pacman &>/dev/null; then PM="pacman" else warn "Could not detect a supported package manager (apt-get, dnf, pacman, brew)." exit 1 fi info "Detected OS: ${OS_ID:-macOS}, Package Manager: $PM" } check_and_setup_sudo() { info "Checking for root privileges and sudo..." if [[ "$(id -u)" -eq 0 ]]; then info "Running as root. 'sudo' is not required." SUDO_CMD="" if ! command -v sudo &>/dev/null; then info "Sudo not found. Installing it for future convenience..." case "$PM" in apt-get) apt-get update && apt-get install -y sudo ;; dnf) dnf install -y sudo ;; pacman) pacman -S --noconfirm sudo ;; esac fi else if ! command -v sudo &>/dev/null; then warn "This script requires 'sudo' to be installed for non-root users." exit 1 fi SUDO_CMD="sudo" info "Running as non-root user. Using 'sudo' for privileged operations." fi } install_build_tools() { info "Installing essential build tools for Rust..." case "$PM" in apt-get) $SUDO_CMD apt-get install -y build-essential ;; dnf) $SUDO_CMD dnf groupinstall -y "Development Tools" ;; pacman) $SUDO_CMD pacman -S --noconfirm --needed base-devel ;; esac } install_rust_toolchain() { if command -v cargo &>/dev/null; then info "Rust toolchain is already installed."; else info "Installing Rust and Cargo via rustup..." curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y fi export PATH="$HOME/.cargo/bin:$PATH" } deploy_dotfiles() { info "Cloning and deploying dotfiles..." local dotfiles_repo="https://github.com/ForeverPyrite/dotfiles.git" local dotfiles_dir="$HOME/dotfiles" if [ ! -d "$dotfiles_dir" ]; then git clone "$dotfiles_repo" "$dotfiles_dir"; else info "Dotfiles directory already exists. Skipping clone."; fi info "Backing up any conflicting default config files..." local conflict_files=("$HOME/.bashrc" "$HOME/.profile" "$HOME/.bash_logout") for file in "${conflict_files[@]}"; do if [ -f "$file" ] && [ ! -L "$file" ]; then mv "$file" "$file.bak" info " -> Moved $file to $file.bak" fi done info "Running 'stow' to link configurations..." cd "$dotfiles_dir" for dir in */; do [ -d "$dir" ] && stow "${dir%/}"; done cd - >/dev/null success "Dotfiles have been deployed." } # --- Parallel Installation Function --- run_parallel_installs() { info "Handing off to Tmux for parallel tool installation..." local session_name="dotfiles" # --- Command Definitions --- local cargo_cmd="export PATH='$HOME/.cargo/bin:$PATH'; for pkg in ${RUST_PACKAGES[@]}; do cargo install --locked \$pkg; done && bob use stable && \ sudo ln -s ~/.local/share/bob/nvim-bob/nvim /usr/bin/nvim && \ cargo cache -a -y && \ echo '✅ Cargo packages installed, Neovim set up, and cache cleaned.'" local fzf_cmd="git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf && ~/.fzf/install --all && echo '✅ fzf installed.'" local tpm_cmd="git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm && echo '✅ Tmux Plugin Manager installed.'" # --- Create Layout & Send Commands --- # This robust method creates the entire layout first, then sends commands to the numbered panes. tmux start-server # Pane 0 tmux new-session -d -s "$session_name" # Pane 1 tmux split-window -h -t "$session_name:1.1" # Pane 2 tmux split-window -v -t "$session_name:1.2" # Send commands to their respective panes tmux send-keys -t "$session_name:1.1" "$cargo_cmd" C-m tmux send-keys -t "$session_name:1.2" "$tpm_cmd" C-m tmux send-keys -t "$session_name:1.3" "$fzf_cmd" C-m # Handle optional installs in new windows if [ "$DOCKER_INSTALL" = true ]; then tmux new-window -t "$session_name" -n "Docker" local docker_cmd="curl -fsSL https://get.docker.com | $SUDO_CMD sh && echo '✅ Docker installed.'" tmux send-keys -t "$session_name:Docker" "$docker_cmd" C-m fi if [ "$EXTENDED_INSTALL" = true ]; then tmux new-window -t "$session_name" -n "Desktop" # Pane 1: Font Installation (your existing command) local font_cmd="mkdir -p ~/.local/share/fonts && curl -fLo f.tar.xz https://github.com/ryanoasis/nerd-fonts/releases/download/v3.2.1/Hack.tar.xz && tar -xf f.tar.xz -C ~/.local/share/fonts && rm f.tar.xz && fc-cache -fv && echo '✅ Fonts installed.'" tmux send-keys -t "$session_name:Desktop.1" "$font_cmd" C-m # Split the window for the next commands tmux split-window -h -t "$session_name:Desktop.1" tmux split-window -v -t "$session_name:Desktop.2" # Pane 2: Change Shell (your existing command) local shell_cmd="FISH_PATH=\$(which fish); if ! grep -q \"\$FISH_PATH\" /etc/shells; then echo \"\$FISH_PATH\" | $SUDO_CMD tee -a /etc/shells; fi; $SUDO_CMD chsh -s \"\$FISH_PATH\" \"$USER\" && echo '✅ Shell changed.'" tmux send-keys -t "$session_name:Desktop.2" "$shell_cmd" C-m warn "The 'chsh' command inside tmux may require your password to complete." # Pane 3: Install Alacritty local alacritty_install_cmd case "$PM" in brew) alacritty_install_cmd="brew install --cask ${GUI_PACKAGES[*]}" ;; apt-get) alacritty_install_cmd="$SUDO_CMD apt-get install -y ${GUI_PACKAGES[*]}" ;; dnf) alacritty_install_cmd="$SUDO_CMD dnf install -y ${GUI_PACKAGES[*]}" ;; pacman) alacritty_install_cmd="$SUDO_CMD pacman -S --noconfirm ${GUI_PACKAGES[*]}" ;; esac alacritty_install_cmd+=" && echo '✅ Alacritty installed.'" tmux send-keys -t "$session_name:Desktop.3" "$alacritty_install_cmd" C-m fi success "Tmux session '$session_name' created. Attach with: tmux a -t $session_name" } # --- Main Execution --- # Phase 0: System Detection & Prerequisite Installation detect_os_and_pm check_and_setup_sudo info "Phase 0: Installing prerequisites (git, stow)..." case "$PM" in brew) brew install "${PREREQ_PACKAGES[@]}" ;; apt-get) $SUDO_CMD apt-get update && $SUDO_CMD apt-get install -y "${PREREQ_PACKAGES[@]}" ;; dnf) if [[ "$OS_ID" == "ol" || "$OS_ID" == "almalinux" || "$OS_ID" == "rockylinux" || "$OS_ID" == "centos" ]]; then $SUDO_CMD dnf install -y epel-release --nogpgcheck; fi $SUDO_CMD dnf install -y "${PREREQ_PACKAGES[@]}" ;; pacman) $SUDO_CMD pacman -Syu --noconfirm "${PREREQ_PACKAGES[@]}" ;; esac success "Prerequisites installed." # Phase 1: Deploy Configurations deploy_dotfiles # Phase 2: Core System Installation info "Phase 2: Installing core system tools..." case "$PM" in brew) brew install "${SYSTEM_PACKAGES[@]}" ;; apt-get) $SUDO_CMD apt-get install -y "${SYSTEM_PACKAGES[@]}" ;; dnf) $SUDO_CMD dnf install -y "${SYSTEM_PACKAGES[@]}" ;; pacman) $SUDO_CMD pacman -S --noconfirm "${SYSTEM_PACKAGES[@]}" ;; esac install_build_tools install_rust_toolchain success "Core system tools installed." # Phase 3: Parallel Tool Installation run_parallel_installs # --- Final Message --- echo "" info "--------------------------------------------------------" success "Bootstrap script finished!" info "Monitor the rest of the installation inside tmux: tmux a -t dotfiles_setup" info "Log out and log back in to apply all changes, especially the new shell." info "--------------------------------------------------------"