Merge branch 'main' into feature/stow-restructure
This commit is contained in:
193
install.sh
193
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
|
||||
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 ""
|
||||
# Auto-discover and run setup scripts
|
||||
if [ -d "scripts" ]; then
|
||||
log_info "Running setup scripts..."
|
||||
|
||||
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"
|
||||
# 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
|
||||
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"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Optionally source the new bashrc
|
||||
if [[ $- == *i* ]] && [ -f "$HOME/.bashrc" ]; then
|
||||
echo "🔄 Reloading Bash config..."
|
||||
source ~/.bashrc
|
||||
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!"
|
||||
|
||||
57
scripts/00-check-dependencies.sh
Normal file
57
scripts/00-check-dependencies.sh
Normal file
@@ -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
|
||||
41
scripts/10-backup-files.sh
Normal file
41
scripts/10-backup-files.sh
Normal file
@@ -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 <dotfiles_directory>"
|
||||
exit 1
|
||||
fi
|
||||
backup_files "$1"
|
||||
fi
|
||||
32
scripts/20-setup-stow.sh
Normal file
32
scripts/20-setup-stow.sh
Normal file
@@ -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 <dotfiles_directory>"
|
||||
exit 1
|
||||
fi
|
||||
setup_stow "$1"
|
||||
fi
|
||||
26
scripts/90-post-install.sh
Normal file
26
scripts/90-post-install.sh
Normal file
@@ -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
|
||||
36
scripts/utils.sh
Normal file
36
scripts/utils.sh
Normal file
@@ -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* ]]
|
||||
}
|
||||
Reference in New Issue
Block a user