diff --git a/install.sh b/install.sh index 34d3bb9..6546502 100644 --- a/install.sh +++ b/install.sh @@ -4,185 +4,48 @@ set -euo pipefail DOTFILES_REPO="https://gitea.purpleraft.com/ryan/dotfiles" DOTFILES_DIR="$HOME/.dotfiles" -# Handle branch selection -if [ $# -eq 0 ]; then - echo "đŸŒŋ Fetching available branches..." - - # Get list of remote branches - branches=$(git ls-remote --heads "$DOTFILES_REPO" | sed 's/.*refs\/heads\///' | sort) - - if [ -z "$branches" ]; then - echo "âš ī¸ Could not fetch branches, using default 'main'" - BRANCH="main" - else - echo "Available branches:" - branch_array=() - i=1 - while IFS= read -r branch; do - echo "$i. $branch" - branch_array+=("$branch") - ((i++)) - done <<< "$branches" - - echo "$i. Enter custom branch name" - echo "" - read -p "Choose branch (1-$i) [default: main]: " branch_choice - - if [[ "$branch_choice" =~ ^[0-9]+$ ]] && [ "$branch_choice" -ge 1 ] && [ "$branch_choice" -lt "$i" ]; then - # Valid branch selection - BRANCH="${branch_array[$((branch_choice-1))]}" - elif [ "$branch_choice" -eq "$i" ]; then - # Custom branch name - read -p "Enter branch name: " custom_branch - BRANCH="$custom_branch" - else - # Default or invalid choice - if [[ " ${branch_array[*]} " =~ " main " ]]; then - BRANCH="main" - else - BRANCH="${branch_array[0]}" # Use first available branch - fi - echo "Using default branch: $BRANCH" - fi - fi +# Source utilities if available +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +if [ -f "$SCRIPT_DIR/scripts/utils.sh" ]; then + source "$SCRIPT_DIR/scripts/utils.sh" else - BRANCH="$1" + # Fallback logging functions if utils not available + log_info() { echo "â„šī¸ $1"; } + log_success() { echo "✅ $1"; } + log_warning() { echo "âš ī¸ $1"; } + log_error() { echo "❌ $1"; } fi -# Function to install packages from a file -install_packages() { - local package_file="$1" - local description="$2" - - if [ -f "$package_file" ]; then - echo "đŸ“Ļ Installing $description..." - - # Read packages into array, skipping comments and empty lines - packages=() - while IFS= read -r line; do - # Skip comments and empty lines - [[ "$line" =~ ^[[:space:]]*# ]] && continue - [[ -z "${line// }" ]] && continue - packages+=("$line") - done < "$package_file" - - if [ ${#packages[@]} -eq 0 ]; then - echo " No packages found in $package_file" - return - fi - - # Detect package manager and install packages - if command -v apt &> /dev/null; then - # Debian/Ubuntu - sudo apt update && sudo apt install -y "${packages[@]}" - elif command -v yum &> /dev/null; then - # RHEL/CentOS - sudo yum install -y "${packages[@]}" - elif command -v dnf &> /dev/null; then - # Fedora - sudo dnf install -y "${packages[@]}" - elif command -v pacman &> /dev/null; then - # Arch Linux - sudo pacman -S --noconfirm "${packages[@]}" - elif command -v brew &> /dev/null; then - # macOS - brew install "${packages[@]}" - else - echo "âš ī¸ No supported package manager found. Please install packages manually from $package_file" - fi - fi -} - -# Check if stow is installed -if ! command -v stow &> /dev/null; then - echo "❌ GNU Stow is not installed. Please install it first:" - echo " Ubuntu/Debian: sudo apt install stow" - echo " macOS: brew install stow" - echo " Or use the alias: install_stow" - exit 1 -fi - -echo "🚀 Installing dotfiles from branch: $BRANCH" +log_info "🚀 Starting dotfiles installation..." # Clone or update the repo if [ -d "$DOTFILES_DIR/.git" ]; then - echo "🔄 Updating existing dotfiles repo..." - git -C "$DOTFILES_DIR" fetch --quiet - git -C "$DOTFILES_DIR" checkout "$BRANCH" --quiet - git -C "$DOTFILES_DIR" pull --quiet + log_info "Updating existing dotfiles repo..." + git -C "$DOTFILES_DIR" pull --quiet else - echo "đŸ“Ĩ Cloning dotfiles into $DOTFILES_DIR..." - git clone -b "$BRANCH" "$DOTFILES_REPO" "$DOTFILES_DIR" + log_info "Cloning dotfiles into $DOTFILES_DIR..." + git clone "$DOTFILES_REPO" "$DOTFILES_DIR" fi cd "$DOTFILES_DIR" -# Install packages (with user confirmation) -echo "" -echo "Package installation options:" -echo "1. Base packages (MUST HAVE) - curl, git, stow, vim, etc." -echo "2. CLI tools (Nice-to-haves) - bat, fzf, ripgrep, etc." -echo "3. Development tools - nodejs, python, docker, etc." -echo "4. GUI applications - firefox, code, vlc, etc." -echo "5. Skip package installation" -echo "" - -read -p "Choose packages to install (1-5, or comma-separated like 1,2): " package_choice - -# Install selected packages -if [[ "$package_choice" == *"1"* ]]; then - install_packages "packages/base.txt" "base packages" -fi -if [[ "$package_choice" == *"2"* ]]; then - install_packages "packages/cli-tools.txt" "CLI tools" -fi -if [[ "$package_choice" == *"3"* ]]; then - install_packages "packages/dev.txt" "development tools" -fi -if [[ "$package_choice" == *"4"* ]]; then - install_packages "packages/gui.txt" "GUI applications" -fi - -# Backup existing files that would conflict with stow -echo "" -echo "🔗 Setting up dotfile symlinks..." -for config_dir in stow/*/; do - if [ -d "$config_dir" ]; then - config_name=$(basename "$config_dir") - echo " Checking for conflicts with $config_name config..." - - # Find all files that would be stowed and backup if they exist - find "$config_dir" -type f | while read -r file; do - relative_file="${file#$config_dir}" - target_file="$HOME/$relative_file" - - if [ -f "$target_file" ] && [ ! -L "$target_file" ]; then - echo " âš ī¸ Backing up existing file: $target_file -> ${target_file}.bak" - mv "$target_file" "${target_file}.bak" - fi - done - fi -done - -# Use stow to create symlinks for each configuration -cd stow -for config_dir in */; do - if [ -d "$config_dir" ]; then - config_name=$(basename "$config_dir") - echo " 🔗 Stowing $config_name configuration..." - if ! stow -t "$HOME" "$config_name" 2>/dev/null; then - echo " âš ī¸ Stow failed for $config_name, trying with --adopt..." - stow --adopt -t "$HOME" "$config_name" +# Auto-discover and run setup scripts +if [ -d "scripts" ]; then + log_info "Running setup scripts..." + + # Look for numbered scripts and run them in order + for script in scripts/[0-9][0-9]-*.sh; do + if [ -f "$script" ]; then + # Make executable and run + chmod +x "$script" 2>/dev/null || true + script_name=$(basename "$script") + log_info "Running $script_name..." + "$script" "$DOTFILES_DIR" fi - fi -done - -# Optionally source the new bashrc -if [[ $- == *i* ]] && [ -f "$HOME/.bashrc" ]; then - echo "🔄 Reloading Bash config..." - source ~/.bashrc + done +else + log_error "No scripts directory found! Something went wrong with the installation." + exit 1 fi -echo "" -echo "✅ Dotfiles install complete!" -echo "💡 Use 'dotpull' alias to update your dotfiles in the future." +log_success "Dotfiles install complete!" diff --git a/scripts/00-check-dependencies.sh b/scripts/00-check-dependencies.sh new file mode 100644 index 0000000..3a84bb5 --- /dev/null +++ b/scripts/00-check-dependencies.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# scripts/00-check-dependencies.sh - Check for required dependencies + +set -euo pipefail + +# Source utilities +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/utils.sh" + +check_dependencies() { + log_info "Checking dependencies..." + + local missing_deps=() + + # Check for git + if ! command_exists git; then + missing_deps+=("git") + fi + + # Check for stow + if ! command_exists stow; then + missing_deps+=("stow") + fi + + if [ ${#missing_deps[@]} -gt 0 ]; then + log_error "Missing required dependencies: ${missing_deps[*]}" + echo "" + echo "Please install the missing dependencies:" + + for dep in "${missing_deps[@]}"; do + case "$dep" in + "git") + echo " Git:" + echo " Ubuntu/Debian: sudo apt install git" + echo " macOS: brew install git" + echo " Or visit: https://git-scm.com/downloads" + ;; + "stow") + echo " GNU Stow:" + echo " Ubuntu/Debian: sudo apt install stow" + echo " macOS: brew install stow" + echo " Or use the alias: install_stow" + ;; + esac + echo "" + done + + exit 1 + fi + + log_success "All dependencies satisfied" +} + +# Run if called directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + check_dependencies +fi diff --git a/scripts/10-backup-files.sh b/scripts/10-backup-files.sh new file mode 100644 index 0000000..84ef4f1 --- /dev/null +++ b/scripts/10-backup-files.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# scripts/10-backup-files.sh - Backup existing files that would conflict + +set -euo pipefail + +# Source utilities +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/utils.sh" + +backup_files() { + local dotfiles_dir="$1" + + log_info "Checking for file conflicts..." + + # Files that might conflict with stow + local files_to_check=(.bashrc .bash_aliases .inputrc .gitconfig) + local backed_up=() + + for file in "${files_to_check[@]}"; do + if [ -f "$HOME/$file" ] && [ ! -L "$HOME/$file" ]; then + log_warning "Backing up existing file: $HOME/$file -> $HOME/${file}.bak" + mv "$HOME/$file" "$HOME/${file}.bak" + backed_up+=("$file") + fi + done + + if [ ${#backed_up[@]} -gt 0 ]; then + log_info "Backed up ${#backed_up[@]} file(s): ${backed_up[*]}" + else + log_info "No file conflicts found" + fi +} + +# Run if called directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + if [ $# -ne 1 ]; then + log_error "Usage: $0 " + exit 1 + fi + backup_files "$1" +fi diff --git a/scripts/20-setup-stow.sh b/scripts/20-setup-stow.sh new file mode 100644 index 0000000..3fbe526 --- /dev/null +++ b/scripts/20-setup-stow.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# scripts/20-setup-stow.sh - Handle GNU Stow operations + +set -euo pipefail + +# Source utilities +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/utils.sh" + +setup_stow() { + local dotfiles_dir="$1" + + # Change to dotfiles directory and use stow to create symlinks + cd "$dotfiles_dir" + log_info "Using Stow to symlink dotfiles..." + + if ! stow --adopt -t "$HOME" . 2>/dev/null; then + log_warning "Adopting failed, trying regular stow..." + stow -t "$HOME" . + fi + + log_success "Stow setup complete" +} + +# Run if called directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + if [ $# -ne 1 ]; then + log_error "Usage: $0 " + exit 1 + fi + setup_stow "$1" +fi diff --git a/scripts/90-post-install.sh b/scripts/90-post-install.sh new file mode 100644 index 0000000..b136422 --- /dev/null +++ b/scripts/90-post-install.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# scripts/90-post-install.sh - Post-installation tasks + +set -euo pipefail + +# Source utilities +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/utils.sh" + +post_install() { + log_info "Running post-installation tasks..." + + # Source the new bashrc if in interactive shell + if is_interactive && [ -f "$HOME/.bashrc" ]; then + log_info "Reloading Bash config..." + source "$HOME/.bashrc" + fi + + # Show completion message + log_success "Post-installation tasks complete" +} + +# Run if called directly +if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then + post_install +fi diff --git a/scripts/utils.sh b/scripts/utils.sh new file mode 100644 index 0000000..465c702 --- /dev/null +++ b/scripts/utils.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# scripts/utils.sh - Shared utilities and functions + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Logging functions +log_info() { + echo -e "${BLUE}â„šī¸ $1${NC}" +} + +log_success() { + echo -e "${GREEN}✅ $1${NC}" +} + +log_warning() { + echo -e "${YELLOW}âš ī¸ $1${NC}" +} + +log_error() { + echo -e "${RED}❌ $1${NC}" +} + +# Check if command exists +command_exists() { + command -v "$1" &> /dev/null +} + +# Check if we're in an interactive shell +is_interactive() { + [[ $- == *i* ]] +}