1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-04 17:24:45 +00:00

feat(clean): add large file review and unify warnings

This commit is contained in:
Tw93
2026-01-22 20:15:13 +08:00
parent 9d824d0ad2
commit cde39aaeb2
5 changed files with 113 additions and 82 deletions

View File

@@ -699,7 +699,7 @@ start_cleanup() {
echo "" echo ""
if [[ "$DRY_RUN" != "true" && -t 0 ]]; then if [[ "$DRY_RUN" != "true" && -t 0 ]]; then
echo -e "${GRAY}${ICON_SOLID} Use --dry-run to preview, --whitelist to manage protected paths${NC}" echo -e "${GRAY}${ICON_WARNING} Use --dry-run to preview, --whitelist to manage protected paths${NC}"
fi fi
if [[ "$DRY_RUN" == "true" ]]; then if [[ "$DRY_RUN" == "true" ]]; then
@@ -979,6 +979,11 @@ perform_cleanup() {
clean_time_machine_failed_backups clean_time_machine_failed_backups
end_section end_section
# ===== 16. Large files to review (report only) =====
start_section "Large files to review"
check_large_file_candidates
end_section
# ===== Final summary ===== # ===== Final summary =====
echo "" echo ""

View File

@@ -269,7 +269,7 @@ tm_is_running() {
grep -qE '(^|[[:space:]])("Running"|Running)[[:space:]]*=[[:space:]]*1([[:space:]]*;|$)' <<< "$st" grep -qE '(^|[[:space:]])("Running"|Running)[[:space:]]*=[[:space:]]*1([[:space:]]*;|$)' <<< "$st"
} }
# Local APFS snapshots (keep the most recent). # Local APFS snapshots (report only).
clean_local_snapshots() { clean_local_snapshots() {
if ! command -v tmutil > /dev/null 2>&1; then if ! command -v tmutil > /dev/null 2>&1; then
return 0 return 0
@@ -279,93 +279,25 @@ clean_local_snapshots() {
tm_is_running || rc_running=$? tm_is_running || rc_running=$?
if [[ $rc_running -eq 2 ]]; then if [[ $rc_running -eq 2 ]]; then
echo -e " ${YELLOW}!${NC} Could not determine Time Machine status; skipping snapshot cleanup" echo -e " ${YELLOW}!${NC} Could not determine Time Machine status; skipping snapshot check"
return 0 return 0
fi fi
if [[ $rc_running -eq 0 ]]; then if [[ $rc_running -eq 0 ]]; then
echo -e " ${YELLOW}!${NC} Time Machine is active; skipping snapshot cleanup" echo -e " ${YELLOW}!${NC} Time Machine is active; skipping snapshot check"
return 0 return 0
fi fi
start_section_spinner "Checking local snapshots..." start_section_spinner "Checking local snapshots..."
local snapshot_list local snapshot_list
snapshot_list=$(tmutil listlocalsnapshots / 2> /dev/null) snapshot_list=$(run_with_timeout 3 tmutil listlocalsnapshots / 2> /dev/null || true)
stop_section_spinner stop_section_spinner
[[ -z "$snapshot_list" ]] && return 0 [[ -z "$snapshot_list" ]] && return 0
local cleaned_count=0
local total_cleaned_size=0 # Estimation not possible without thin
local newest_ts=0
local newest_name=""
local -a snapshots=()
while IFS= read -r line; do
if [[ "$line" =~ com\.apple\.TimeMachine\.([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]{6}) ]]; then
local snap_name="${BASH_REMATCH[0]}"
snapshots+=("$snap_name")
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")
[[ "$snap_ts" == "0" ]] && continue
if [[ "$snap_ts" -gt "$newest_ts" ]]; then
newest_ts="$snap_ts"
newest_name="$snap_name"
fi
fi
done <<< "$snapshot_list"
[[ ${#snapshots[@]} -eq 0 ]] && return 0 local snapshot_count
[[ -z "$newest_name" ]] && return 0 snapshot_count=$(echo "$snapshot_list" | grep -Eo 'com\.apple\.TimeMachine\.[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{6}' | wc -l | awk '{print $1}')
if [[ "$snapshot_count" =~ ^[0-9]+$ && "$snapshot_count" -gt 0 ]]; then
local deletable_count=$((${#snapshots[@]} - 1)) echo -e " ${YELLOW}${ICON_WARNING}${NC} Time Machine local snapshots: ${GREEN}${snapshot_count}${NC}${GRAY}, Review: tmutil listlocalsnapshots /${NC}"
[[ $deletable_count -le 0 ]] && return 0 note_activity
if [[ "$DRY_RUN" != "true" ]]; then
if [[ ! -t 0 ]]; then
echo -e " ${YELLOW}!${NC} ${#snapshots[@]} local snapshot(s) found, skipping non-interactive mode"
echo -e " ${GRAY}${ICON_WARNING}${NC} ${GRAY}Tip: Snapshots may cause Disk Utility to show different 'Available' values${NC}"
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
if type read_key > /dev/null 2>&1; then
choice=$(read_key)
else
IFS= read -r -s -n 1 choice || choice=""
if [[ -z "$choice" || "$choice" == $'\n' || "$choice" == $'\r' ]]; then
choice="ENTER"
fi
fi
if [[ "$choice" == "ENTER" ]]; then
printf "\r\033[K" # Clear the prompt line
else
echo -e " ${GRAY}Skipped${NC}"
return 0
fi
fi
local snap_name
for snap_name in "${snapshots[@]}"; do
if [[ "$snap_name" =~ com\.apple\.TimeMachine\.([0-9]{4})-([0-9]{2})-([0-9]{2})-([0-9]{6}) ]]; then
if [[ "${BASH_REMATCH[0]}" != "$newest_name" ]]; then
if [[ "$DRY_RUN" == "true" ]]; then
echo -e " ${YELLOW}${ICON_DRY_RUN}${NC} Local snapshot: $snap_name ${YELLOW}dry-run${NC}"
((cleaned_count++))
note_activity
else
if sudo tmutil deletelocalsnapshots "${BASH_REMATCH[1]}-${BASH_REMATCH[2]}-${BASH_REMATCH[3]}-${BASH_REMATCH[4]}" > /dev/null 2>&1; then
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Removed snapshot: $snap_name"
((cleaned_count++))
note_activity
else
echo -e " ${YELLOW}!${NC} Failed to remove: $snap_name"
fi
fi
fi
fi
done
if [[ $cleaned_count -gt 0 && "$DRY_RUN" != "true" ]]; then
log_success "Cleaned $cleaned_count local snapshots, kept latest"
fi fi
} }

View File

@@ -600,13 +600,107 @@ check_ios_device_backups() {
local backup_human=$(command du -sh "$backup_dir" 2> /dev/null | awk '{print $1}') local backup_human=$(command du -sh "$backup_dir" 2> /dev/null | awk '{print $1}')
if [[ -n "$backup_human" ]]; then if [[ -n "$backup_human" ]]; then
note_activity note_activity
echo -e " Found ${GREEN}${backup_human}${NC} iOS backups" echo -e " ${YELLOW}${ICON_WARNING}${NC} iOS backups: ${GREEN}${backup_human}${NC}${GRAY}, Path: $backup_dir${NC}"
echo -e " You can delete them manually: ${backup_dir}"
fi fi
fi fi
fi fi
return 0 return 0
} }
# Large file candidates (report only, no deletion).
check_large_file_candidates() {
local threshold_kb=$((1024 * 1024)) # 1GB
local found_any=false
local mail_dir="$HOME/Library/Mail"
if [[ -d "$mail_dir" ]]; then
local mail_kb
mail_kb=$(get_path_size_kb "$mail_dir")
if [[ "$mail_kb" -ge "$threshold_kb" ]]; then
local mail_human
mail_human=$(bytes_to_human "$((mail_kb * 1024))")
echo -e " ${YELLOW}${ICON_WARNING}${NC} Mail data: ${GREEN}${mail_human}${NC}${GRAY}, Path: $mail_dir${NC}"
found_any=true
fi
fi
local mail_downloads="$HOME/Library/Mail Downloads"
if [[ -d "$mail_downloads" ]]; then
local downloads_kb
downloads_kb=$(get_path_size_kb "$mail_downloads")
if [[ "$downloads_kb" -ge "$threshold_kb" ]]; then
local downloads_human
downloads_human=$(bytes_to_human "$((downloads_kb * 1024))")
echo -e " ${YELLOW}${ICON_WARNING}${NC} Mail downloads: ${GREEN}${downloads_human}${NC}${GRAY}, Path: $mail_downloads${NC}"
found_any=true
fi
fi
local installer_path
for installer_path in /Applications/Install\ macOS*.app; do
if [[ -e "$installer_path" ]]; then
local installer_kb
installer_kb=$(get_path_size_kb "$installer_path")
if [[ "$installer_kb" -gt 0 ]]; then
local installer_human
installer_human=$(bytes_to_human "$((installer_kb * 1024))")
echo -e " ${YELLOW}${ICON_WARNING}${NC} macOS installer: ${GREEN}${installer_human}${NC}${GRAY}, Path: $installer_path${NC}"
found_any=true
fi
fi
done
local updates_dir="$HOME/Library/Updates"
if [[ -d "$updates_dir" ]]; then
local updates_kb
updates_kb=$(get_path_size_kb "$updates_dir")
if [[ "$updates_kb" -ge "$threshold_kb" ]]; then
local updates_human
updates_human=$(bytes_to_human "$((updates_kb * 1024))")
echo -e " ${YELLOW}${ICON_WARNING}${NC} macOS updates cache: ${GREEN}${updates_human}${NC}${GRAY}, Path: $updates_dir${NC}"
found_any=true
fi
fi
if [[ "${SYSTEM_CLEAN:-false}" != "true" ]] && command -v tmutil > /dev/null 2>&1; then
local snapshot_list snapshot_count
snapshot_list=$(run_with_timeout 3 tmutil listlocalsnapshots / 2> /dev/null || true)
if [[ -n "$snapshot_list" ]]; then
snapshot_count=$(echo "$snapshot_list" | grep -Eo 'com\.apple\.TimeMachine\.[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{6}' | wc -l | awk '{print $1}')
if [[ "$snapshot_count" =~ ^[0-9]+$ && "$snapshot_count" -gt 0 ]]; then
echo -e " ${YELLOW}${ICON_WARNING}${NC} Time Machine local snapshots: ${GREEN}${snapshot_count}${NC}${GRAY}, Review: tmutil listlocalsnapshots /${NC}"
found_any=true
fi
fi
fi
if command -v docker > /dev/null 2>&1; then
local docker_output
docker_output=$(run_with_timeout 3 docker system df --format '{{.Type}}\t{{.Size}}\t{{.Reclaimable}}' 2> /dev/null || true)
if [[ -n "$docker_output" ]]; then
echo -e " ${YELLOW}${ICON_WARNING}${NC} Docker storage:"
while IFS=$'\t' read -r dtype dsize dreclaim; do
[[ -z "$dtype" ]] && continue
echo -e " ${GRAY}$dtype: $dsize, Reclaimable: $dreclaim${NC}"
done <<< "$docker_output"
found_any=true
else
docker_output=$(run_with_timeout 3 docker system df 2> /dev/null || true)
if [[ -n "$docker_output" ]]; then
echo -e " ${YELLOW}${ICON_WARNING}${NC} Docker storage:"
echo -e " ${GRAY}• Run: docker system df${NC}"
found_any=true
fi
fi
fi
if [[ "$found_any" == "false" ]]; then
echo -e " ${GREEN}${ICON_SUCCESS}${NC} No large items detected in common locations"
fi
note_activity
return 0
}
# Apple Silicon specific caches (IS_M_SERIES). # Apple Silicon specific caches (IS_M_SERIES).
clean_apple_silicon_caches() { clean_apple_silicon_caches() {
if [[ "${IS_M_SERIES:-false}" != "true" ]]; then if [[ "${IS_M_SERIES:-false}" != "true" ]]; then

View File

@@ -31,7 +31,7 @@ readonly ICON_CONFIRM="◎"
readonly ICON_ADMIN="⚙" readonly ICON_ADMIN="⚙"
readonly ICON_SUCCESS="✓" readonly ICON_SUCCESS="✓"
readonly ICON_ERROR="☻" readonly ICON_ERROR="☻"
readonly ICON_WARNING="" readonly ICON_WARNING=""
readonly ICON_EMPTY="○" readonly ICON_EMPTY="○"
readonly ICON_SOLID="●" readonly ICON_SOLID="●"
readonly ICON_LIST="•" readonly ICON_LIST="•"

View File

@@ -332,7 +332,7 @@ batch_uninstall_applications() {
while IFS= read -r file; do while IFS= read -r file; do
if [[ -n "$file" && -e "$file" ]]; then if [[ -n "$file" && -e "$file" ]]; then
if [[ $sys_file_count -lt $max_files ]]; then if [[ $sys_file_count -lt $max_files ]]; then
echo -e " ${BLUE}${ICON_SOLID}${NC} System: $file" echo -e " ${BLUE}${ICON_WARNING}${NC} System: $file"
fi fi
((sys_file_count++)) ((sys_file_count++))
fi fi