#!/usr/bin/env bash # cleanup_execute.sh — Execute cleanup actions on macOS # Usage: cleanup_execute.sh [--dry-run|--execute] [...] # Targets: user-logs, user-caches, brew-cache, npm-cache, pip-cache, # xcode-derived, xcode-archives, ios-support, docker, trash set -euo pipefail MODE="dry-run" TARGETS=() BACKUP_DIR="${BACKUP_DIR:-$HOME/.config/mac-optimizer-backups}" usage() { echo "Usage: $0 [--dry-run|--execute] [...]" echo "" echo "Options:" echo " --dry-run Show what would be deleted (default)" echo " --execute Actually perform cleanup" echo "" echo "Targets:" echo " user-logs ~/Library/Logs/" echo " user-caches ~/Library/Caches/" echo " brew-cache Homebrew download cache" echo " npm-cache npm cache" echo " pip-cache pip cache" echo " xcode-derived Xcode DerivedData" echo " xcode-archives Xcode Archives" echo " ios-support iOS DeviceSupport files" echo " docker Docker system prune" echo " trash Empty Trash" exit 1 } # Parse args while [[ $# -gt 0 ]]; do case "$1" in --dry-run) MODE="dry-run"; shift ;; --execute) MODE="execute"; shift ;; --help|-h) usage ;; *) TARGETS+=("$1"); shift ;; esac done if [ ${#TARGETS[@]} -eq 0 ]; then echo "Error: No targets specified" usage fi log_action() { local target="$1" action="$2" size="$3" echo "[${MODE}] ${target}: ${action} (${size})" } clean_dir() { local name="$1" path="$2" if [ ! -d "$path" ]; then echo "[skip] ${name}: directory not found (${path})" return fi local size=$(du -sh "$path" 2>/dev/null | awk '{print $1}') if [ "$MODE" = "dry-run" ]; then log_action "$name" "would remove contents of ${path}" "$size" else log_action "$name" "removing contents of ${path}" "$size" find "$path" -mindepth 1 -delete 2>/dev/null || { # Fallback: remove what we can find "$path" -mindepth 1 -maxdepth 1 -exec rm -rf {} + 2>/dev/null || true } echo "[done] ${name}: cleaned" fi } for target in "${TARGETS[@]}"; do case "$target" in user-logs) clean_dir "User Logs" "$HOME/Library/Logs" ;; user-caches) clean_dir "User Caches" "$HOME/Library/Caches" ;; brew-cache) if command -v brew &>/dev/null; then brew_cache=$(brew --cache 2>/dev/null || echo "") if [ -n "$brew_cache" ]; then size=$(du -sh "$brew_cache" 2>/dev/null | awk '{print $1}') if [ "$MODE" = "dry-run" ]; then log_action "Homebrew Cache" "would run brew cleanup" "$size" else log_action "Homebrew Cache" "running brew cleanup" "$size" brew cleanup --prune=0 2>/dev/null || true echo "[done] Homebrew Cache: cleaned" fi fi else echo "[skip] brew-cache: Homebrew not installed" fi ;; npm-cache) if command -v npm &>/dev/null; then npm_cache="$HOME/.npm/_cacache" if [ -d "$npm_cache" ]; then size=$(du -sh "$npm_cache" 2>/dev/null | awk '{print $1}') if [ "$MODE" = "dry-run" ]; then log_action "npm Cache" "would run npm cache clean --force" "$size" else log_action "npm Cache" "running npm cache clean" "$size" npm cache clean --force 2>/dev/null || true echo "[done] npm Cache: cleaned" fi fi else echo "[skip] npm-cache: npm not installed" fi ;; pip-cache) pip_cache="$HOME/Library/Caches/pip" if [ -d "$pip_cache" ]; then size=$(du -sh "$pip_cache" 2>/dev/null | awk '{print $1}') if [ "$MODE" = "dry-run" ]; then log_action "pip Cache" "would run pip cache purge" "$size" else log_action "pip Cache" "running pip cache purge" "$size" pip3 cache purge 2>/dev/null || pip cache purge 2>/dev/null || true echo "[done] pip Cache: cleaned" fi else echo "[skip] pip-cache: no pip cache found" fi ;; xcode-derived) clean_dir "Xcode DerivedData" "$HOME/Library/Developer/Xcode/DerivedData" ;; xcode-archives) clean_dir "Xcode Archives" "$HOME/Library/Developer/Xcode/Archives" ;; ios-support) clean_dir "iOS DeviceSupport" "$HOME/Library/Developer/Xcode/iOS DeviceSupport" ;; docker) if command -v docker &>/dev/null; then if [ "$MODE" = "dry-run" ]; then echo "[dry-run] Docker: would run docker system prune" docker system df 2>/dev/null || echo " (Docker not running)" else echo "[execute] Docker: running docker system prune -f" docker system prune -f 2>/dev/null || echo " Docker prune failed (is Docker running?)" fi else echo "[skip] docker: Docker not installed" fi ;; trash) trash_dir="$HOME/.Trash" if [ -d "$trash_dir" ]; then size=$(du -sh "$trash_dir" 2>/dev/null | awk '{print $1}') if [ "$MODE" = "dry-run" ]; then log_action "Trash" "would empty Trash" "$size" else log_action "Trash" "emptying Trash" "$size" rm -rf "$trash_dir"/* 2>/dev/null || true rm -rf "$trash_dir"/.[!.]* 2>/dev/null || true echo "[done] Trash: emptied" fi fi ;; *) echo "[error] Unknown target: ${target}" ;; esac done