diff --git a/lib/clean/dev.sh b/lib/clean/dev.sh index aa6ec52..4728a3e 100644 --- a/lib/clean/dev.sh +++ b/lib/clean/dev.sh @@ -173,8 +173,56 @@ check_android_ndk() { "Android Studio → SDK Manager" } +clean_xcode_documentation_cache() { + local doc_cache_root="${MOLE_XCODE_DOCUMENTATION_CACHE_DIR:-/Library/Developer/Xcode/DocumentationCache}" + [[ -d "$doc_cache_root" ]] || return 0 + + if pgrep -x "Xcode" > /dev/null 2>&1; then + echo -e " ${GRAY}${ICON_WARNING}${NC} Xcode is running, skipping documentation cache cleanup" + note_activity + return 0 + fi + + local -a index_entries=() + while IFS= read -r -d '' entry; do + index_entries+=("$entry") + done < <(command find "$doc_cache_root" -mindepth 1 -maxdepth 1 \( -name "DeveloperDocumentation.index" -o -name "DeveloperDocumentation*.index" \) -print0 2> /dev/null) + + if [[ ${#index_entries[@]} -le 1 ]]; then + return 0 + fi + + local -a sorted_entries=() + while IFS= read -r line; do + sorted_entries+=("${line#* }") + done < <( + for entry in "${index_entries[@]}"; do + mtime=$(stat -f%m "$entry" 2> /dev/null || echo "0") + printf '%s %s\n' "$mtime" "$entry" + done | sort -rn + ) + + local -a stale_entries=() + local idx=0 + local entry + for entry in "${sorted_entries[@]}"; do + if [[ $idx -eq 0 ]]; then + ((idx++)) + continue + fi + stale_entries+=("$entry") + ((idx++)) + done + + if [[ ${#stale_entries[@]} -gt 0 ]]; then + safe_clean "${stale_entries[@]}" "Xcode documentation cache (old indexes)" + note_activity + fi +} + clean_dev_mobile() { check_android_ndk + clean_xcode_documentation_cache if command -v xcrun > /dev/null 2>&1; then debug_log "Checking for unavailable Xcode simulators" diff --git a/tests/clean_dev_caches.bats b/tests/clean_dev_caches.bats index 97aca2e..da4e5b3 100644 --- a/tests/clean_dev_caches.bats +++ b/tests/clean_dev_caches.bats @@ -90,6 +90,7 @@ clean_dev_cloud() { :; } clean_dev_nix() { :; } clean_dev_shell() { :; } clean_dev_frontend() { :; } +clean_xcode_documentation_cache() { :; } clean_dev_mobile() { :; } clean_dev_jvm() { :; } clean_dev_other_langs() { :; } diff --git a/tests/dev_extended.bats b/tests/dev_extended.bats index d6c19fd..0ecee83 100644 --- a/tests/dev_extended.bats +++ b/tests/dev_extended.bats @@ -136,6 +136,53 @@ EOF [[ "$output" != *"NDK versions"* ]] } +@test "clean_xcode_documentation_cache keeps newest DeveloperDocumentation index" { + local doc_root="$HOME/DocumentationCache" + mkdir -p "$doc_root" + touch "$doc_root/DeveloperDocumentation.index" + touch "$doc_root/DeveloperDocumentation-16.0.index" + touch -t 202402010000 "$doc_root/DeveloperDocumentation.index" + touch -t 202401010000 "$doc_root/DeveloperDocumentation-16.0.index" + + run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" MOLE_XCODE_DOCUMENTATION_CACHE_DIR="$doc_root" bash --noprofile --norc <<'EOF' +set -euo pipefail +source "$PROJECT_ROOT/lib/core/common.sh" +source "$PROJECT_ROOT/lib/clean/dev.sh" +note_activity() { :; } +safe_clean() { + local description="${*: -1}" + local target="$1" + echo "CLEAN:$target:$description" +} +clean_xcode_documentation_cache +EOF + + [ "$status" -eq 0 ] + [[ "$output" == *"CLEAN:$doc_root/DeveloperDocumentation-16.0.index:Xcode documentation cache (old indexes)"* ]] + [[ "$output" != *"CLEAN:$doc_root/DeveloperDocumentation.index:Xcode documentation cache (old indexes)"* ]] +} + +@test "clean_xcode_documentation_cache skips when Xcode is running" { + local doc_root="$HOME/DocumentationCache" + mkdir -p "$doc_root" + touch "$doc_root/DeveloperDocumentation.index" + touch "$doc_root/DeveloperDocumentation-16.0.index" + + run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" MOLE_XCODE_DOCUMENTATION_CACHE_DIR="$doc_root" bash --noprofile --norc <<'EOF' +set -euo pipefail +source "$PROJECT_ROOT/lib/core/common.sh" +source "$PROJECT_ROOT/lib/clean/dev.sh" +note_activity() { :; } +pgrep() { return 0; } +safe_clean() { echo "UNEXPECTED_SAFE_CLEAN"; } +clean_xcode_documentation_cache +EOF + + [ "$status" -eq 0 ] + [[ "$output" == *"skipping documentation cache cleanup"* ]] + [[ "$output" != *"UNEXPECTED_SAFE_CLEAN"* ]] +} + @test "check_rust_toolchains reports multiple toolchains" { run bash -c 'HOME=$(mktemp -d) && mkdir -p "$HOME/.rustup/toolchains"/{stable,nightly,1.75.0}-aarch64-apple-darwin && source "$0" && note_activity() { :; } && NC="" && GREEN="" && GRAY="" && YELLOW="" && ICON_SUCCESS="✓" && rustup() { :; } && export -f rustup && check_rust_toolchains' "$PROJECT_ROOT/lib/clean/dev.sh"