#!/bin/bash # Dotfiles sync script # Automatically checks for updates and applies them set -e DOTFILES_DIR="$HOME/.dotfiles" SYNC_LOG="$DOTFILES_DIR/.sync.log" LAST_SYNC_FILE="$DOTFILES_DIR/.last_sync" SYNC_ENABLED_FILE="$DOTFILES_DIR/.sync_enabled" # Check if sync is enabled (default: enabled) if [[ -f "$SYNC_ENABLED_FILE" ]]; then SYNC_ENABLED=$(cat "$SYNC_ENABLED_FILE") else SYNC_ENABLED="true" echo "true" > "$SYNC_ENABLED_FILE" fi if [[ "$SYNC_ENABLED" != "true" ]]; then exit 0 fi # Function to log with timestamp log() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$SYNC_LOG" } # Function to check if we should sync (avoid too frequent checks) should_sync() { local current_time=$(date +%s) local last_sync_time=0 local manual_sync=${1:-false} if [[ -f "$LAST_SYNC_FILE" ]]; then last_sync_time=$(cat "$LAST_SYNC_FILE") fi # If manual sync, always allow if [[ "$manual_sync" == "true" ]]; then return 0 fi # For auto-sync, only sync if more than 24 hours (86400 seconds) have passed local time_diff=$((current_time - last_sync_time)) if [[ $time_diff -lt 86400 ]]; then return 1 fi return 0 } # Function to perform the sync sync_dotfiles() { cd "$DOTFILES_DIR" # Check if we're in a git repository if ! git rev-parse --git-dir > /dev/null 2>&1; then log "Not in a git repository, skipping sync" return 0 fi # Store current commit hash local current_commit=$(git rev-parse HEAD 2>/dev/null || echo "") # Fetch latest changes (suppress output for smooth terminal startup) if git fetch origin > /dev/null 2>&1; then log "Successfully fetched from origin" else log "Failed to fetch from origin" return 1 fi # Check if there are updates available local remote_commit=$(git rev-parse origin/$(git branch --show-current) 2>/dev/null || echo "") if [[ -n "$current_commit" && -n "$remote_commit" && "$current_commit" != "$remote_commit" ]]; then log "Updates available, pulling changes" # Check for local changes if ! git diff-index --quiet HEAD -- 2>/dev/null; then log "Local changes detected, stashing before pull" git stash push -m "Auto-stash before sync $(date)" > /dev/null 2>&1 local stashed=true fi # Pull changes if git pull origin $(git branch --show-current) > /dev/null 2>&1; then log "Successfully pulled updates" # Re-run install script to apply any new configurations if [[ -x "$DOTFILES_DIR/install.sh" ]]; then log "Re-running install script" "$DOTFILES_DIR/install.sh" > /dev/null 2>&1 fi # Check for any missing packages after sync if [[ -f "$DOTFILES_DIR/lib/package_manager.sh" ]]; then log "Checking for missing packages after sync" source "$DOTFILES_DIR/lib/package_manager.sh" install_all_packages true > /dev/null 2>&1 # Skip optional packages for sync fi # Restore stashed changes if any if [[ "$stashed" == "true" ]]; then log "Restoring stashed changes" git stash pop > /dev/null 2>&1 || log "Failed to restore stashed changes" fi # Notify user (only in interactive shells) if [[ $- == *i* ]]; then echo "🔄 Dotfiles updated! Changes applied automatically." fi else log "Failed to pull updates" return 1 fi else log "No updates available" fi # Update last sync time echo "$(date +%s)" > "$LAST_SYNC_FILE" return 0 } # Main execution main() { local manual_sync=false # Check if this is a manual sync if [[ "${1:-}" == "--manual" ]] || [[ "${1:-}" == "--force" ]]; then manual_sync=true fi # Create log file if it doesn't exist touch "$SYNC_LOG" # Check if we should sync if should_sync "$manual_sync"; then if [[ "$manual_sync" == "true" ]]; then log "Starting manual sync" echo "🔄 Running manual dotfiles sync..." else log "Starting daily auto-sync check" fi sync_dotfiles else if [[ "$manual_sync" == "true" ]]; then # Even for manual sync, show when last sync was if [[ -f "$LAST_SYNC_FILE" ]]; then local last_sync=$(cat "$LAST_SYNC_FILE") local last_sync_date=$(date -d "@$last_sync" 2>/dev/null || echo "Unknown") echo "â„šī¸ Last sync: $last_sync_date" fi log "Manual sync requested but running anyway" sync_dotfiles else log "Auto-sync skipped - last sync was less than 24 hours ago" fi fi } # Run sync in background to avoid blocking terminal startup (only for auto-sync) if [[ "${1:-}" == "--background" ]]; then main & disown elif [[ "${1:-}" == "--manual" ]] || [[ "${1:-}" == "--force" ]]; then main "$1" else main fi