clone of my dotfiles.ssp.sh
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

WIP restore

sspaeti 26a0569a f3f23f7f

+382
+382
restore_dotfiles.sh
··· 1 + #!/bin/bash 2 + 3 + # Safe dotfiles restore script 4 + # This script provides multiple restoration modes to safely restore dotfiles 5 + # without overwriting existing configurations 6 + 7 + set -e # Exit on any error 8 + 9 + # Color codes for output 10 + RED='\033[0;31m' 11 + GREEN='\033[0;32m' 12 + YELLOW='\033[1;33m' 13 + BLUE='\033[0;34m' 14 + NC='\033[0m' # No Color 15 + 16 + # Configuration 17 + DOTFILES_DIR="$HOME/dotfiles" # Adjust this path 18 + BACKUP_DIR="$HOME/.dotfiles_backup_$(date +%Y%m%d_%H%M%S)" 19 + DRY_RUN=false 20 + INTERACTIVE=true 21 + FORCE=false 22 + 23 + # Usage function 24 + usage() { 25 + echo "Usage: $0 [OPTIONS]" 26 + echo "Options:" 27 + echo " -d, --dotfiles-dir DIR Dotfiles directory (default: $DOTFILES_DIR)" 28 + echo " -b, --backup-dir DIR Backup directory (default: $BACKUP_DIR)" 29 + echo " -n, --dry-run Show what would be done without making changes" 30 + echo " -y, --yes Non-interactive mode (assume yes)" 31 + echo " -f, --force Force overwrite existing files" 32 + echo " -h, --help Show this help" 33 + echo "" 34 + echo "Restoration modes:" 35 + echo " 1. Interactive mode (default): Ask before each file" 36 + echo " 2. Backup mode: Backup existing files before restore" 37 + echo " 3. Merge mode: Attempt to merge configurations" 38 + echo " 4. Symlink mode: Create symlinks instead of copying" 39 + } 40 + 41 + # Parse command line arguments 42 + while [[ $# -gt 0 ]]; do 43 + case $1 in 44 + -d|--dotfiles-dir) 45 + DOTFILES_DIR="$2" 46 + shift 2 47 + ;; 48 + -b|--backup-dir) 49 + BACKUP_DIR="$2" 50 + shift 2 51 + ;; 52 + -n|--dry-run) 53 + DRY_RUN=true 54 + shift 55 + ;; 56 + -y|--yes) 57 + INTERACTIVE=false 58 + shift 59 + ;; 60 + -f|--force) 61 + FORCE=true 62 + shift 63 + ;; 64 + -h|--help) 65 + usage 66 + exit 0 67 + ;; 68 + *) 69 + echo "Unknown option: $1" 70 + usage 71 + exit 1 72 + ;; 73 + esac 74 + done 75 + 76 + # Utility functions 77 + log_info() { 78 + echo -e "${BLUE}[INFO]${NC} $1" 79 + } 80 + 81 + log_success() { 82 + echo -e "${GREEN}[SUCCESS]${NC} $1" 83 + } 84 + 85 + log_warning() { 86 + echo -e "${YELLOW}[WARNING]${NC} $1" 87 + } 88 + 89 + log_error() { 90 + echo -e "${RED}[ERROR]${NC} $1" 91 + } 92 + 93 + ask_user() { 94 + if [[ "$INTERACTIVE" == false ]]; then 95 + return 0 96 + fi 97 + 98 + local prompt="$1" 99 + local default="${2:-n}" 100 + 101 + while true; do 102 + read -p "$prompt [y/N]: " -n 1 -r 103 + echo 104 + if [[ $REPLY =~ ^[Yy]$ ]]; then 105 + return 0 106 + elif [[ $REPLY =~ ^[Nn]$ ]] || [[ -z $REPLY ]]; then 107 + return 1 108 + else 109 + echo "Please answer y or n." 110 + fi 111 + done 112 + } 113 + 114 + # Create backup directory 115 + create_backup_dir() { 116 + if [[ ! -d "$BACKUP_DIR" ]]; then 117 + log_info "Creating backup directory: $BACKUP_DIR" 118 + if [[ "$DRY_RUN" == false ]]; then 119 + mkdir -p "$BACKUP_DIR" 120 + fi 121 + fi 122 + } 123 + 124 + # Backup existing file 125 + backup_file() { 126 + local target="$1" 127 + local backup_path="$BACKUP_DIR/$(dirname "$target")" 128 + 129 + if [[ -e "$target" ]]; then 130 + log_info "Backing up existing file: $target" 131 + if [[ "$DRY_RUN" == false ]]; then 132 + mkdir -p "$backup_path" 133 + cp -r "$target" "$backup_path/" 134 + fi 135 + return 0 136 + fi 137 + return 1 138 + } 139 + 140 + # Safe copy function 141 + safe_copy() { 142 + local source="$1" 143 + local target="$2" 144 + local action="$3" # copy, symlink, or merge 145 + 146 + # Check if source exists 147 + if [[ ! -e "$source" ]]; then 148 + log_warning "Source file does not exist: $source" 149 + return 1 150 + fi 151 + 152 + # Create target directory if it doesn't exist 153 + local target_dir="$(dirname "$target")" 154 + if [[ ! -d "$target_dir" ]]; then 155 + log_info "Creating directory: $target_dir" 156 + if [[ "$DRY_RUN" == false ]]; then 157 + mkdir -p "$target_dir" 158 + fi 159 + fi 160 + 161 + # Handle existing target 162 + if [[ -e "$target" ]]; then 163 + if [[ "$FORCE" == true ]]; then 164 + log_info "Force overwriting: $target" 165 + backup_file "$target" 166 + elif ask_user "File exists: $target. Overwrite?"; then 167 + backup_file "$target" 168 + else 169 + log_info "Skipping: $target" 170 + return 0 171 + fi 172 + fi 173 + 174 + # Perform the action 175 + case "$action" in 176 + copy) 177 + log_info "Copying: $source -> $target" 178 + if [[ "$DRY_RUN" == false ]]; then 179 + cp -r "$source" "$target" 180 + fi 181 + ;; 182 + symlink) 183 + log_info "Symlinking: $source -> $target" 184 + if [[ "$DRY_RUN" == false ]]; then 185 + ln -sf "$source" "$target" 186 + fi 187 + ;; 188 + merge) 189 + log_info "Merging: $source -> $target" 190 + # This is a placeholder - implement specific merge logic per file type 191 + if [[ "$DRY_RUN" == false ]]; then 192 + cp -r "$source" "$target" 193 + fi 194 + ;; 195 + esac 196 + } 197 + 198 + # Platform detection 199 + detect_platform() { 200 + if [[ "$OSTYPE" == "linux-gnu"* ]]; then 201 + echo "linux" 202 + elif [[ "$OSTYPE" == "darwin"* ]]; then 203 + echo "macos" 204 + else 205 + echo "unknown" 206 + fi 207 + } 208 + 209 + # Adjust paths for different platforms 210 + adjust_path() { 211 + local original_path="$1" 212 + local platform="$2" 213 + 214 + case "$platform" in 215 + linux) 216 + # Convert macOS paths to Linux equivalents 217 + echo "$original_path" | sed \ 218 + -e 's|~/Library/ApplicationSupport/Code/User/|~/.config/Code/User/|g' \ 219 + -e 's|~/Library/Application Support/lazygit/|~/.config/lazygit/|g' 220 + ;; 221 + macos) 222 + # Convert Linux paths to macOS equivalents 223 + echo "$original_path" | sed \ 224 + -e 's|~/.config/Code/User/|~/Library/ApplicationSupport/Code/User/|g' \ 225 + -e 's|~/.config/lazygit/|~/Library/Application Support/lazygit/|g' 226 + ;; 227 + *) 228 + echo "$original_path" 229 + ;; 230 + esac 231 + } 232 + 233 + # Main restoration function 234 + restore_dotfiles() { 235 + local platform=$(detect_platform) 236 + local mode="$1" 237 + 238 + log_info "Detected platform: $platform" 239 + log_info "Restoration mode: $mode" 240 + 241 + if [[ "$DRY_RUN" == true ]]; then 242 + log_warning "DRY RUN MODE - No changes will be made" 243 + fi 244 + 245 + create_backup_dir 246 + 247 + # Define file mappings (source -> target) 248 + declare -A file_mappings=( 249 + # VS Code 250 + ["vscode/settings.json"]="$(adjust_path "~/Library/ApplicationSupport/Code/User/settings.json" "$platform")" 251 + ["vscode/keybindings.json"]="$(adjust_path "~/Library/ApplicationSupport/Code/User/keybindings.json" "$platform")" 252 + 253 + # Neovim 254 + ["nvim/init.vim"]="~/.config/nvim/init.vim" 255 + ["nvim-wp/init.vim"]="~/.config/nvim-wp/init.vim" 256 + 257 + # Tmux 258 + ["tmux/tmux.conf"]="~/.tmux.conf" 259 + ["tmux/ide"]="~/.tmux/ide" 260 + 261 + # Zsh 262 + ["zsh/zshrc"]="~/.zshrc" 263 + ["zsh/.secrets"]="~/.dotfiles/zsh/.secrets" 264 + ["zsh/aliases.shrc"]="~/.dotfiles/zsh/aliases.shrc" 265 + 266 + # Kitty 267 + ["kitty/kitty.conf"]="~/.config/kitty/kitty.conf" 268 + ["kitty/gruvbox-kitty.conf"]="~/.config/kitty/gruvbox-kitty.conf" 269 + 270 + # Ghostty 271 + ["ghostty/config"]="~/.config/ghostty/config" 272 + 273 + # Yabai & SKHD (macOS only) 274 + ["yabai/yabairc"]="~/.config/yabai/yabairc" 275 + ["skhd/skhdrc"]="~/.config/skhd/skhdrc" 276 + 277 + # Helix 278 + ["helix/config.toml"]="~/.config/helix/config.toml" 279 + 280 + # Git (be careful with this one) 281 + # ["git/gitconfig"]="~/.gitconfig" 282 + 283 + # Ranger 284 + ["ranger/rc.conf"]="~/.config/ranger/rc.conf" 285 + 286 + # Yazi 287 + ["yazi/yazi.toml"]="~/.config/yazi/yazi.toml" 288 + 289 + # Linting 290 + ["linting/pylintrc"]="~/.pylintrc" 291 + ["linting/flake8"]="~/.config/flake8" 292 + 293 + # Karabiner (macOS only) 294 + ["karabiner/karabiner.json"]="~/.config/karabiner/karabiner.json" 295 + 296 + # Lazygit 297 + ["lazygit/config.yml"]="$(adjust_path "~/Library/Application Support/lazygit/config.yml" "$platform")" 298 + ) 299 + 300 + # Process each file 301 + for source_file in "${!file_mappings[@]}"; do 302 + local source_path="$DOTFILES_DIR/$source_file" 303 + local target_path="${file_mappings[$source_file]}" 304 + 305 + # Expand tilde 306 + target_path="${target_path/#\~/$HOME}" 307 + 308 + # Skip platform-specific files 309 + if [[ "$platform" == "linux" ]] && [[ "$source_file" == *"yabai"* || "$source_file" == *"skhd"* || "$source_file" == *"karabiner"* ]]; then 310 + log_info "Skipping macOS-specific file: $source_file" 311 + continue 312 + fi 313 + 314 + case "$mode" in 315 + copy) 316 + safe_copy "$source_path" "$target_path" "copy" 317 + ;; 318 + symlink) 319 + safe_copy "$source_path" "$target_path" "symlink" 320 + ;; 321 + merge) 322 + safe_copy "$source_path" "$target_path" "merge" 323 + ;; 324 + esac 325 + done 326 + 327 + log_success "Dotfiles restoration completed!" 328 + if [[ -d "$BACKUP_DIR" ]] && [[ "$(ls -A "$BACKUP_DIR" 2>/dev/null)" ]]; then 329 + log_info "Backup of original files created at: $BACKUP_DIR" 330 + fi 331 + } 332 + 333 + # Special handling for sensitive files 334 + handle_sensitive_files() { 335 + local sensitive_files=( 336 + ".ssh" 337 + ".secrets" 338 + "gitconfig" 339 + ) 340 + 341 + for file in "${sensitive_files[@]}"; do 342 + if ask_user "Restore sensitive file: $file?"; then 343 + log_warning "Restoring sensitive file: $file" 344 + # Add specific handling here 345 + fi 346 + done 347 + } 348 + 349 + # Main execution 350 + main() { 351 + log_info "Starting dotfiles restoration" 352 + 353 + # Check if dotfiles directory exists 354 + if [[ ! -d "$DOTFILES_DIR" ]]; then 355 + log_error "Dotfiles directory not found: $DOTFILES_DIR" 356 + exit 1 357 + fi 358 + 359 + # Choose restoration mode 360 + if [[ "$INTERACTIVE" == true ]]; then 361 + echo "Choose restoration mode:" 362 + echo "1. Copy files (default)" 363 + echo "2. Create symlinks" 364 + echo "3. Merge configurations" 365 + read -p "Enter choice [1-3]: " -n 1 -r 366 + echo 367 + 368 + case "$REPLY" in 369 + 2) restore_dotfiles "symlink" ;; 370 + 3) restore_dotfiles "merge" ;; 371 + *) restore_dotfiles "copy" ;; 372 + esac 373 + else 374 + restore_dotfiles "copy" 375 + fi 376 + 377 + # Handle sensitive files separately 378 + handle_sensitive_files 379 + } 380 + 381 + # Run main function 382 + main "$@"