diff --git a/.gitignore b/.gitignore index 2557ddb..f8a8138 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ Thumbs.db .env.* secrets/ EOF +.git-credentials diff --git a/README.md b/README.md new file mode 100644 index 0000000..15742ee --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# dotfiles +Aaron D. Lee's dotfiles for Linux/MacOs diff --git a/bin/deploy-zshtheme-systemwide.sh b/bin/deploy-zshtheme-systemwide.sh new file mode 100755 index 0000000..b0d57e7 --- /dev/null +++ b/bin/deploy-zshtheme-systemwide.sh @@ -0,0 +1,596 @@ +#!/usr/bin/env bash +# ============================================================================ +# ADLee Theme System-wide Deployment Script (Enhanced) +# ============================================================================ +# This script deploys the adlee.zsh-theme system-wide via symlinks +# Usage: +# sudo ./deploy-theme-systemwide.sh # Interactive mode +# sudo ./deploy-theme-systemwide.sh --all # All users with TTY +# sudo ./deploy-theme-systemwide.sh --current # Current user + root only +# sudo ./deploy-theme-systemwide.sh --force # Force replace all links + +set -euo pipefail + +# Configuration +MASTER_THEME_DIR="/usr/local/share/zsh/themes" +MASTER_THEME_PATH="${MASTER_THEME_DIR}/adlee.zsh-theme" +THEME_NAME="adlee.zsh-theme" +SOURCE_THEME="${HOME}/.dotfiles/zsh/themes/${THEME_NAME}" +FORCE_REPLACE=false + +# Colors for output +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +RED='\033[0;31m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +# ============================================================================ +# Helper Functions +# ============================================================================ + +print_success() { + echo -e "${GREEN}✓${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}⚠${NC} $1" +} + +print_error() { + echo -e "${RED}✗${NC} $1" +} + +print_info() { + echo -e "${CYAN}ℹ${NC} $1" +} + +print_step() { + echo -e "\n${GREEN}==>${NC} $1" +} + +print_header() { + echo -e "\n${BLUE}╔════════════════════════════════════════════════════════════╗${NC}" + echo -e "${BLUE}║${NC} ADLee Theme System-wide Deployment ${BLUE}║${NC}" + echo -e "${BLUE}╚════════════════════════════════════════════════════════════╝${NC}\n" +} + +# Check if running as root +check_root() { + if [[ $EUID -ne 0 ]]; then + print_error "This script must be run as root (use sudo)" + echo "Usage: sudo $0 [--all|--current]" + exit 1 + fi +} + +# Ask yes/no question +ask_yes_no() { + local prompt="$1" + local default="${2:-y}" + + if [[ "$default" == "y" ]]; then + prompt="$prompt [Y/n]: " + else + prompt="$prompt [y/N]: " + fi + + read -p "$prompt" response + response=${response:-$default} + + [[ "$response" =~ ^[Yy]$ ]] +} + +# Check if a path is a symlink pointing to master theme +is_system_symlink() { + local path="$1" + [[ -L "$path" ]] && [[ "$(readlink -f "$path")" == "$MASTER_THEME_PATH" ]] +} + +# Check if a path is a local symlink (from dotfiles) +is_local_symlink() { + local path="$1" + if [[ -L "$path" ]]; then + local target=$(readlink -f "$path") + [[ "$target" == *"/.dotfiles/"* ]] + else + return 1 + fi +} + +# Check if a path is a regular file +is_regular_file() { + local path="$1" + [[ -f "$path" ]] && [[ ! -L "$path" ]] +} + +# Get link status description +get_link_status() { + local path="$1" + + if [[ ! -e "$path" ]] && [[ ! -L "$path" ]]; then + echo "not_present" + elif is_system_symlink "$path"; then + echo "system_link" + elif is_local_symlink "$path"; then + echo "local_link" + elif is_regular_file "$path"; then + echo "regular_file" + elif [[ -L "$path" ]]; then + echo "other_link" + else + echo "unknown" + fi +} + +# ============================================================================ +# Master Theme Setup +# ============================================================================ + +setup_master_location() { + print_step "Setting up master theme location" + + # Create directory if it doesn't exist + if [[ ! -d "$MASTER_THEME_DIR" ]]; then + mkdir -p "$MASTER_THEME_DIR" + print_success "Created directory: $MASTER_THEME_DIR" + fi + + # Determine source file + local source_file="" + + if [[ -f "$SOURCE_THEME" ]]; then + source_file="$SOURCE_THEME" + elif [[ -f "$THEME_NAME" ]]; then + source_file="$THEME_NAME" + elif [[ -f "$HOME/.oh-my-zsh/themes/$THEME_NAME" ]]; then + source_file="$HOME/.oh-my-zsh/themes/$THEME_NAME" + fi + + # Copy or verify master theme + if [[ -f "$MASTER_THEME_PATH" ]]; then + print_info "Master theme already exists: $MASTER_THEME_PATH" + + if [[ -n "$source_file" ]]; then + # Check if update is needed + if ! diff -q "$source_file" "$MASTER_THEME_PATH" &>/dev/null; then + print_warning "Source theme differs from master" + if ask_yes_no "Update master theme from source?"; then + cp "$source_file" "$MASTER_THEME_PATH" + chmod 644 "$MASTER_THEME_PATH" + print_success "Master theme updated" + fi + else + print_success "Master theme is up to date" + fi + fi + else + if [[ -z "$source_file" ]]; then + print_error "Theme file not found. Please ensure $THEME_NAME exists in:" + echo " - $SOURCE_THEME" + echo " - ./$THEME_NAME" + echo " - ~/.oh-my-zsh/themes/$THEME_NAME" + exit 1 + fi + + cp "$source_file" "$MASTER_THEME_PATH" + chmod 644 "$MASTER_THEME_PATH" + print_success "Copied theme to master location" + fi +} + +# ============================================================================ +# User Detection and Selection +# ============================================================================ + +get_users_with_tty() { + local users=() + + # Add root if oh-my-zsh is installed + if [[ -d "/root/.oh-my-zsh" ]]; then + users+=("root") + fi + + # Find regular users with oh-my-zsh + while IFS=: read -r username _ uid _ _ home_dir shell; do + # Skip system users (UID < 1000) + [[ $uid -lt 1000 ]] && continue + + # Check if user has oh-my-zsh + if [[ -d "$home_dir/.oh-my-zsh" ]]; then + users+=("$username") + fi + done < /etc/passwd + + echo "${users[@]}" +} + +get_current_user() { + # Get the user who invoked sudo + if [[ -n "${SUDO_USER:-}" ]]; then + echo "$SUDO_USER" + else + # Fallback to first non-root user with oh-my-zsh + while IFS=: read -r username _ uid _ _ home_dir _; do + if [[ $uid -ge 1000 ]] && [[ -d "$home_dir/.oh-my-zsh" ]]; then + echo "$username" + return + fi + done < /etc/passwd + fi +} + +select_users() { + local mode="$1" + local users=() + + case "$mode" in + all) + users=($(get_users_with_tty)) + ;; + current) + local current_user=$(get_current_user) + if [[ -n "$current_user" ]]; then + users=("$current_user") + fi + if [[ -d "/root/.oh-my-zsh" ]]; then + users+=("root") + fi + ;; + interactive) + local all_users=($(get_users_with_tty)) + + if [[ ${#all_users[@]} -eq 0 ]]; then + print_error "No users with oh-my-zsh found" + exit 1 + fi + + echo "Users with oh-my-zsh detected:" + for i in "${!all_users[@]}"; do + echo " $((i+1)). ${all_users[$i]}" + done + echo + + if ask_yes_no "Deploy to all users?"; then + users=("${all_users[@]}") + else + local current_user=$(get_current_user) + if [[ -n "$current_user" ]]; then + users=("$current_user") + print_info "Selected: $current_user" + fi + + if [[ -d "/root/.oh-my-zsh" ]]; then + if ask_yes_no "Include root user?"; then + users+=("root") + fi + fi + fi + ;; + esac + + echo "${users[@]}" +} + +# ============================================================================ +# Deployment Functions +# ============================================================================ + +analyze_user_theme() { + local username="$1" + local home_dir + + if [[ "$username" == "root" ]]; then + home_dir="/root" + else + home_dir=$(eval echo "~$username") + fi + + local theme_path="$home_dir/.oh-my-zsh/themes/$THEME_NAME" + local status=$(get_link_status "$theme_path") + + echo "$status" +} + +deploy_for_user() { + local username="$1" + local home_dir + + # Get home directory + if [[ "$username" == "root" ]]; then + home_dir="/root" + else + home_dir=$(eval echo "~$username") + fi + + # Check if user's home directory exists + if [[ ! -d "$home_dir" ]]; then + print_warning "Home directory not found for user: $username" + return 1 + fi + + local oh_my_zsh_themes="$home_dir/.oh-my-zsh/themes" + local theme_link="$oh_my_zsh_themes/$THEME_NAME" + + # Check if oh-my-zsh is installed + if [[ ! -d "$home_dir/.oh-my-zsh" ]]; then + print_warning "oh-my-zsh not installed for user: $username" + return 1 + fi + + # Analyze current status + local status=$(get_link_status "$theme_link") + + case "$status" in + system_link) + if [[ "$FORCE_REPLACE" == true ]]; then + print_info "Recreating system-wide link for: $username" + else + print_success "✓ Already using system-wide theme: $username" + return 0 + fi + ;; + local_link) + print_info "Converting local symlink → system-wide for: $username" + ;; + regular_file) + print_warning "Replacing regular file → system-wide for: $username" + ;; + other_link) + print_warning "Replacing unknown symlink → system-wide for: $username" + ;; + not_present) + print_info "Creating new system-wide link for: $username" + ;; + esac + + # Create themes directory if it doesn't exist + if [[ ! -d "$oh_my_zsh_themes" ]]; then + mkdir -p "$oh_my_zsh_themes" + if [[ "$username" != "root" ]]; then + chown "$username:$(id -gn "$username" 2>/dev/null || echo "$username")" "$oh_my_zsh_themes" + fi + fi + + # Remove existing file/link (this is the key fix!) + if [[ -e "$theme_link" ]] || [[ -L "$theme_link" ]]; then + rm -f "$theme_link" + fi + + # Create symlink to master theme + ln -sf "$MASTER_THEME_PATH" "$theme_link" + + # Fix ownership + if [[ "$username" != "root" ]]; then + chown -h "$username:$(id -gn "$username" 2>/dev/null || echo "$username")" "$theme_link" 2>/dev/null || true + fi + + # Verify the symlink was created correctly + if is_system_symlink "$theme_link"; then + print_success "✓ Deployed system-wide theme for: $username" + else + print_error "✗ Failed to create system-wide link for: $username" + return 1 + fi +} + +# ============================================================================ +# Status and Reporting +# ============================================================================ + +show_deployment_status() { + print_step "Current deployment status" + + local users=($(get_users_with_tty)) + + if [[ ${#users[@]} -eq 0 ]]; then + print_warning "No users with oh-my-zsh found" + return + fi + + echo + printf "%-20s %-20s %s\n" "User" "Status" "Details" + printf "%-20s %-20s %s\n" "----" "------" "-------" + + for user in "${users[@]}"; do + local status=$(analyze_user_theme "$user") + local home_dir + + if [[ "$user" == "root" ]]; then + home_dir="/root" + else + home_dir=$(eval echo "~$user") + fi + + local theme_path="$home_dir/.oh-my-zsh/themes/$THEME_NAME" + + case "$status" in + system_link) + printf "%-20s ${GREEN}%-20s${NC} %s\n" "$user" "System-wide ✓" "→ $MASTER_THEME_PATH" + ;; + local_link) + local target=$(readlink "$theme_path") + printf "%-20s ${YELLOW}%-20s${NC} %s\n" "$user" "Local symlink" "→ $target" + ;; + regular_file) + printf "%-20s ${CYAN}%-20s${NC} %s\n" "$user" "Regular file" "(standalone copy)" + ;; + other_link) + local target=$(readlink "$theme_path" 2>/dev/null || echo "broken") + printf "%-20s ${YELLOW}%-20s${NC} %s\n" "$user" "Other symlink" "→ $target" + ;; + not_present) + printf "%-20s ${RED}%-20s${NC} %s\n" "$user" "Not installed" "" + ;; + *) + printf "%-20s ${RED}%-20s${NC} %s\n" "$user" "Unknown" "" + ;; + esac + done + echo +} + +# ============================================================================ +# Main Execution +# ============================================================================ + +show_summary() { + echo + echo "============================================================================" + echo "Deployment Summary" + echo "============================================================================" + echo "Master theme location: $MASTER_THEME_PATH" + echo + echo "To update the theme in the future:" + echo " 1. Edit: $MASTER_THEME_PATH" + echo " 2. All users will get updates automatically (via symlinks)" + echo + echo "Alternatively, update from your dotfiles:" + echo " sudo cp ~/.dotfiles/zsh/themes/$THEME_NAME $MASTER_THEME_PATH" + echo + echo "To check deployment status:" + echo " sudo $0 --status" + echo "============================================================================" +} + +main() { + local mode="interactive" + local status_only=false + + # Parse arguments + for arg in "$@"; do + case "$arg" in + --all) + mode="all" + ;; + --current) + mode="current" + ;; + --force) + FORCE_REPLACE=true + ;; + --status|-s) + status_only=true + ;; + --help|-h) + echo "Usage: sudo $0 [OPTIONS]" + echo + echo "Options:" + echo " --all Deploy to all users with oh-my-zsh" + echo " --current Deploy to current user and root only" + echo " --force Force replacement even if system-wide link exists" + echo " --status Show current deployment status" + echo " --help Show this help message" + echo + echo "Examples:" + echo " sudo $0 # Interactive mode" + echo " sudo $0 --all # Deploy to all users" + echo " sudo $0 --current --force # Force update for current user + root" + echo + exit 0 + ;; + *) + print_error "Unknown option: $arg" + echo "Use --help for usage information" + exit 1 + ;; + esac + done + + print_header + check_root + + # Status only mode + if [[ "$status_only" == true ]]; then + show_deployment_status + exit 0 + fi + + # Show current status first + show_deployment_status + + # Setup master location + setup_master_location + + # Select users + local users=($(select_users "$mode")) + + if [[ ${#users[@]} -eq 0 ]]; then + print_error "No users selected for deployment" + exit 1 + fi + + # Print info about selected mode + case "$mode" in + all) + print_info "Deploying to all users with oh-my-zsh" + ;; + current) + print_info "Deploying to current user and root" + ;; + esac + + echo + print_step "Deploying to ${#users[@]} user(s): ${users[*]}" + + if [[ "$FORCE_REPLACE" == true ]]; then + print_warning "Force mode: will replace ALL existing links" + fi + + echo + + # Interactive confirmation for converting local links + if [[ "$mode" == "interactive" ]]; then + local has_local_links=false + for user in "${users[@]}"; do + local status=$(analyze_user_theme "$user") + if [[ "$status" == "local_link" ]]; then + has_local_links=true + break + fi + done + + if [[ "$has_local_links" == true ]]; then + echo "⚠ Some users have local dotfiles symlinks." + echo "This will replace them with system-wide symlinks pointing to:" + echo " $MASTER_THEME_PATH" + echo + if ! ask_yes_no "Convert local symlinks to system-wide?"; then + print_warning "Deployment cancelled" + exit 0 + fi + fi + fi + + if ! ask_yes_no "Proceed with deployment?"; then + print_warning "Deployment cancelled" + exit 0 + fi + + # Deploy to each user + echo + local deployed_count=0 + local failed_count=0 + for user in "${users[@]}"; do + if deploy_for_user "$user"; then + ((deployed_count++)) + else + ((failed_count++)) + fi + done + + echo + if [[ $failed_count -eq 0 ]]; then + print_success "Deployment complete! ($deployed_count/${#users[@]} users)" + else + print_warning "Deployment finished with errors ($deployed_count succeeded, $failed_count failed)" + fi + + # Show updated status + echo + show_deployment_status + show_summary +} + +main "$@" diff --git a/git/.gitconfig b/git/.gitconfig index 200c0c9..1861da9 100644 --- a/git/.gitconfig +++ b/git/.gitconfig @@ -1,2 +1,7 @@ [init] defaultBranch = master +[user] + email = aaron.daniel.lee@gmail.com + name = Aaron D. Lee +[credential] + helper = store diff --git a/zsh/.zshrc b/zsh/.zshrc index 7aaccc7..fea1689 100644 --- a/zsh/.zshrc +++ b/zsh/.zshrc @@ -106,4 +106,16 @@ source $ZSH/oh-my-zsh.sh # alias ohmyzsh="mate ~/.oh-my-zsh" alias vispresso="vim ~/.config/espanso/match/base.yml" - +# GitHub token helper +gh-token-setup() { + echo "Enter your GitHub username:" + read gh_user + echo "Enter your GitHub personal access token:" + read -s gh_token + + git config --global credential.helper store + echo "https://${gh_user}:${gh_token}@github.com" > ~/.git-credentials + chmod 600 ~/.git-credentials + + echo "✓ GitHub token configured!" +}