diff --git a/lib/clean/system.sh b/lib/clean/system.sh index 5f1f2b0..a4025fd 100644 --- a/lib/clean/system.sh +++ b/lib/clean/system.sh @@ -263,7 +263,7 @@ clean_time_machine_failed_backups() { echo -e " ${GREEN}${ICON_SUCCESS}${NC} No incomplete backups found" fi } -# Clean local APFS snapshots (older than 24 hours) +# Clean local APFS snapshots (keep the most recent snapshot) clean_local_snapshots() { # Check if tmutil is available if ! command -v tmutil > /dev/null 2>&1; then @@ -278,9 +278,9 @@ clean_local_snapshots() { # Parse and clean snapshots local cleaned_count=0 local total_cleaned_size=0 # Estimation not possible without thin - # Get current time - local current_ts=$(date +%s) - local one_day_ago=$((current_ts - 86400)) + local newest_ts=0 + local newest_name="" + # Find the most recent snapshot to keep at least one version while IFS= read -r line; do # Format: com.apple.TimeMachine.2023-10-25-120000 if [[ "$line" =~ com\.apple\.TimeMachine\.([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]{6}) ]]; then @@ -288,11 +288,57 @@ clean_local_snapshots() { local snap_ts=$(date -j -f "%Y-%m-%d %H:%M:%S" "$date_str" "+%s" 2> /dev/null || echo "0") # Skip if parsing failed [[ "$snap_ts" == "0" ]] && continue - # If snapshot is older than 24 hours - if [[ $snap_ts -lt $one_day_ago ]]; then + if [[ "$snap_ts" -gt "$newest_ts" ]]; then + newest_ts="$snap_ts" + newest_name="${BASH_REMATCH[0]}" + fi + fi + done <<< "$snapshot_list" + + [[ -z "$newest_name" ]] && return 0 + + local deletable_count=0 + while IFS= read -r line; do + if [[ "$line" =~ com\.apple\.TimeMachine\.([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]{6}) ]]; then + if [[ "${BASH_REMATCH[0]}" != "$newest_name" ]]; then + ((deletable_count++)) + fi + fi + done <<< "$snapshot_list" + + [[ $deletable_count -eq 0 ]] && return 0 + + if [[ "$DRY_RUN" != "true" ]]; then + if [[ ! -t 0 ]]; then + echo -e " ${YELLOW}!${NC} Local snapshots found, skipping non-interactive mode" + return 0 + fi + echo -e " ${YELLOW}!${NC} Time Machine local snapshots found" + echo -e " ${GRAY}macOS can recreate them if needed.${NC}" + echo -e " ${GRAY}The most recent snapshot will be kept.${NC}" + echo -ne " ${PURPLE}${ICON_ARROW}${NC} Remove all local snapshots except the most recent one? ${GREEN}Enter${NC} continue, ${GRAY}Space${NC} skip: " + local choice + choice=$(read_key) + if [[ "$choice" == "ENTER" ]]; then + printf "\r\033[K" # Clear the prompt line + else + echo -e " ${GRAY}Skipped${NC}" + return 0 + fi + fi + + while IFS= read -r line; do + # Format: com.apple.TimeMachine.2023-10-25-120000 + if [[ "$line" =~ com\.apple\.TimeMachine\.([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]{6}) ]]; then + local date_str="${BASH_REMATCH[1]}-${BASH_REMATCH[2]}-${BASH_REMATCH[3]} ${BASH_REMATCH[4]:0:2}:${BASH_REMATCH[4]:2:2}:${BASH_REMATCH[4]:4:2}" + local snap_ts=$(date -j -f "%Y-%m-%d %H:%M:%S" "$date_str" "+%s" 2> /dev/null || echo "0") + # Skip if parsing failed + [[ "$snap_ts" == "0" ]] && continue + # Remove all but the most recent snapshot + if [[ "${BASH_REMATCH[0]}" != "$newest_name" ]]; then local snap_name="${BASH_REMATCH[0]}" if [[ "$DRY_RUN" == "true" ]]; then - echo -e " ${YELLOW}${ICON_DRY_RUN}${NC} Old local snapshot: $snap_name ${YELLOW}(dry)${NC}" + echo -e " ${YELLOW}${ICON_DRY_RUN}${NC} Local snapshot: $snap_name ${YELLOW}dry-run${NC}" ((cleaned_count++)) note_activity else @@ -309,6 +355,6 @@ clean_local_snapshots() { fi done <<< "$snapshot_list" if [[ $cleaned_count -gt 0 && "$DRY_RUN" != "true" ]]; then - log_success "Cleaned $cleaned_count old local snapshots" + log_success "Cleaned $cleaned_count local snapshots, kept latest" fi }