diff --git a/lib/clean/user.sh b/lib/clean/user.sh index 82d2b6d..6826755 100644 --- a/lib/clean/user.sh +++ b/lib/clean/user.sh @@ -5,9 +5,7 @@ clean_user_essentials() { start_section_spinner "Scanning caches..." safe_clean ~/Library/Caches/* "User app cache" stop_section_spinner - start_section_spinner "Scanning empty items..." - clean_empty_library_items - stop_section_spinner + safe_clean ~/Library/Logs/* "User app logs" if is_path_whitelisted "$HOME/.Trash"; then note_activity @@ -17,65 +15,7 @@ clean_user_essentials() { fi } -clean_empty_library_items() { - if [[ ! -d "$HOME/Library" ]]; then - return 0 - fi - # 1. Clean top-level empty directories and files in Library - local -a empty_dirs=() - while IFS= read -r -d '' dir; do - [[ -d "$dir" ]] && empty_dirs+=("$dir") - done < <(find "$HOME/Library" -mindepth 1 -maxdepth 1 -type d -empty -print0 2> /dev/null) - - if [[ ${#empty_dirs[@]} -gt 0 ]]; then - safe_clean "${empty_dirs[@]}" "Empty Library folders" - fi - - # 2. Clean empty subdirectories in Application Support and other key locations - # Iteratively remove empty directories until no more are found - local -a key_locations=( - "$HOME/Library/Application Support" - "$HOME/Library/Caches" - ) - - for location in "${key_locations[@]}"; do - [[ -d "$location" ]] || continue - - # Limit passes to keep cleanup fast; 3 iterations handle most nested scenarios. - local max_iterations=3 - local iteration=0 - - while [[ $iteration -lt $max_iterations ]]; do - local -a nested_empty_dirs=() - # Find empty directories - while IFS= read -r -d '' dir; do - # Skip if whitelisted - if is_path_whitelisted "$dir"; then - continue - fi - # Skip protected system components - local dir_name=$(basename "$dir") - if is_critical_system_component "$dir_name"; then - continue - fi - [[ -d "$dir" ]] && nested_empty_dirs+=("$dir") - done < <(find "$location" -mindepth 1 -type d -empty -print0 2> /dev/null) - - # If no empty dirs found, we're done with this location - if [[ ${#nested_empty_dirs[@]} -eq 0 ]]; then - break - fi - - local location_name=$(basename "$location") - safe_clean "${nested_empty_dirs[@]}" "Empty $location_name subdirs" - - ((iteration++)) - done - done - - # Empty file cleanup is skipped to avoid removing app sentinel files. -} # Remove old Google Chrome versions while keeping Current. clean_chrome_old_versions() { diff --git a/tests/clean_apps.bats b/tests/clean_apps.bats index 9955117..7533315 100644 --- a/tests/clean_apps.bats +++ b/tests/clean_apps.bats @@ -114,3 +114,4 @@ EOF [ "$status" -eq 0 ] [[ "$output" == "ok" ]] } + diff --git a/tests/clean_core.bats b/tests/clean_core.bats index 9a0c41f..d526d7b 100644 --- a/tests/clean_core.bats +++ b/tests/clean_core.bats @@ -264,91 +264,4 @@ EOF [[ "$output" == *"Time Machine backup in progress, skipping cleanup"* ]] } -@test "clean_empty_library_items removes nested empty directories in Application Support" { - # Create nested empty directory structure - mkdir -p "$HOME/Library/Application Support/UninstalledApp1/SubDir/DeepDir" - mkdir -p "$HOME/Library/Application Support/UninstalledApp2/Cache" - mkdir -p "$HOME/Library/Application Support/ActiveApp/Data" - mkdir -p "$HOME/Library/Caches/EmptyCache/SubCache" - # Create a file in ActiveApp to make it non-empty - touch "$HOME/Library/Application Support/ActiveApp/Data/config.json" - - # Create top-level empty directory in Library - mkdir -p "$HOME/Library/EmptyTopLevel" - - run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc << 'EOF' -set -euo pipefail -source "$PROJECT_ROOT/lib/core/common.sh" -source "$PROJECT_ROOT/lib/clean/user.sh" - -# Mock dependencies -is_path_whitelisted() { return 1; } -is_critical_system_component() { return 1; } -bytes_to_human() { echo "$1"; } -note_activity() { :; } -safe_clean() { - # Actually remove the directories for testing - for path in "$@"; do - if [ "$path" != "${@: -1}" ]; then # Skip the description (last arg) - rm -rf "$path" 2>/dev/null || true - fi - done -} - -clean_empty_library_items -EOF - - [ "$status" -eq 0 ] - - # Empty nested dirs should be removed - [ ! -d "$HOME/Library/Application Support/UninstalledApp1" ] - [ ! -d "$HOME/Library/Application Support/UninstalledApp2" ] - [ ! -d "$HOME/Library/Caches/EmptyCache" ] - [ ! -d "$HOME/Library/EmptyTopLevel" ] - - # Non-empty directory should remain - [ -d "$HOME/Library/Application Support/ActiveApp" ] - [ -f "$HOME/Library/Application Support/ActiveApp/Data/config.json" ] -} - -@test "clean_empty_library_items respects whitelist for empty directories" { - mkdir -p "$HOME/Library/Application Support/ProtectedEmptyApp" - mkdir -p "$HOME/Library/Application Support/UnprotectedEmptyApp" - mkdir -p "$HOME/.config/mole" - - run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc << 'EOF' -set -euo pipefail -source "$PROJECT_ROOT/lib/core/common.sh" -source "$PROJECT_ROOT/lib/clean/user.sh" - -# Mock dependencies -is_critical_system_component() { return 1; } -bytes_to_human() { echo "$1"; } -note_activity() { :; } - -# Mock whitelist to protect ProtectedEmptyApp -is_path_whitelisted() { - [[ "$1" == *"ProtectedEmptyApp"* ]] -} - -safe_clean() { - # Actually remove the directories for testing - for path in "$@"; do - if [ "$path" != "${@: -1}" ]; then # Skip the description (last arg) - rm -rf "$path" 2>/dev/null || true - fi - done -} - -clean_empty_library_items -EOF - - [ "$status" -eq 0 ] - - # Whitelisted directory should remain even if empty - [ -d "$HOME/Library/Application Support/ProtectedEmptyApp" ] - - # Non-whitelisted directory should be removed - [ ! -d "$HOME/Library/Application Support/UnprotectedEmptyApp" ] -} diff --git a/tests/clean_user_core.bats b/tests/clean_user_core.bats index dd918d8..d2675d8 100644 --- a/tests/clean_user_core.bats +++ b/tests/clean_user_core.bats @@ -103,21 +103,7 @@ EOF [ "$status" -eq 0 ] } -@test "clean_empty_library_items cleans empty dirs and files" { - run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" /bin/bash --noprofile --norc <<'EOF' -set -euo pipefail -source "$PROJECT_ROOT/lib/core/common.sh" -source "$PROJECT_ROOT/lib/clean/user.sh" -safe_clean() { echo "$2"; } -WHITELIST_PATTERNS=() -mkdir -p "$HOME/Library/EmptyDir" -touch "$HOME/Library/empty.txt" -clean_empty_library_items -EOF - [ "$status" -eq 0 ] - [[ "$output" == *"Empty Library folders"* ]] -} @test "clean_browsers calls expected cache paths" { run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc <<'EOF'