diff --git a/bin/uninstall.sh b/bin/uninstall.sh index 42e4a93..d47dcd6 100755 --- a/bin/uninstall.sh +++ b/bin/uninstall.sh @@ -135,6 +135,16 @@ uninstall_resolve_display_name() { if [[ "$display_name" == /* ]]; then display_name="$app_name" fi + + # Keep versioned bundle names when metadata collapses distinct installs. + if [[ -n "$display_name" && "$app_name" == "$display_name"* && "$app_name" != "$display_name" ]]; then + local suffix + suffix="${app_name#"$display_name"}" + if [[ "$suffix" == *[0-9]* ]]; then + display_name="$app_name" + fi + fi + display_name="${display_name%.app}" display_name="${display_name//|/-}" display_name="${display_name//[$'\t\r\n']/}" diff --git a/lib/clean/dev.sh b/lib/clean/dev.sh index 97c0905..04aff0d 100644 --- a/lib/clean/dev.sh +++ b/lib/clean/dev.sh @@ -146,6 +146,41 @@ clean_dev_go() { fi note_activity } + +get_mise_cache_path() { + if [[ -n "${MISE_CACHE_DIR:-}" && "${MISE_CACHE_DIR}" == /* ]]; then + echo "$MISE_CACHE_DIR" + return 0 + fi + + if command -v mise > /dev/null 2>&1; then + local mise_cache_path + mise_cache_path=$(run_with_timeout 2 mise cache path 2> /dev/null || echo "") + if [[ -n "$mise_cache_path" && "$mise_cache_path" == /* ]]; then + echo "$mise_cache_path" + return 0 + fi + fi + + echo "$HOME/Library/Caches/mise" +} + +clean_dev_mise() { + local mise_cache_path + mise_cache_path=$(get_mise_cache_path) + + if command -v mise > /dev/null 2>&1; then + if [[ "$DRY_RUN" != "true" ]]; then + clean_tool_cache "mise cache" bash -c 'mise cache clear > /dev/null 2>&1 || true' + note_activity + else + echo -e " ${YELLOW}${ICON_DRY_RUN}${NC} mise cache ยท would clean" + note_activity + fi + fi + + safe_clean "$mise_cache_path"/* "mise cache" +} # Rust/cargo caches. clean_dev_rust() { safe_clean ~/.cargo/registry/cache/* "Rust cargo cache" @@ -1040,6 +1075,7 @@ clean_developer_tools() { clean_dev_npm clean_dev_python clean_dev_go + clean_dev_mise clean_dev_rust check_rust_toolchains clean_dev_docker diff --git a/tests/clean_dev_caches.bats b/tests/clean_dev_caches.bats index dfa12b0..a1be431 100644 --- a/tests/clean_dev_caches.bats +++ b/tests/clean_dev_caches.bats @@ -206,6 +206,23 @@ EOF [[ "$output" == *"Docker unused data|Docker unused data docker system prune -af --volumes"* ]] } +@test "clean_dev_mise respects MISE_CACHE_DIR and only targets cache" { + run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" MISE_CACHE_DIR="/tmp/mise-cache" bash --noprofile --norc <<'EOF' +set -euo pipefail +source "$PROJECT_ROOT/lib/core/common.sh" +source "$PROJECT_ROOT/lib/clean/dev.sh" +safe_clean() { echo "$2|$1"; } +clean_tool_cache() { :; } +note_activity() { :; } +run_with_timeout() { shift; "$@"; } +clean_dev_mise +EOF + + [ "$status" -eq 0 ] + [[ "$output" == *"mise cache|/tmp/mise-cache/*"* ]] + [[ "$output" != *".local/share/mise"* ]] +} + @test "clean_developer_tools runs key stages" { run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc <<'EOF' set -euo pipefail @@ -217,6 +234,7 @@ clean_homebrew() { echo "brew"; } clean_project_caches() { :; } clean_dev_python() { :; } clean_dev_go() { :; } +clean_dev_mise() { echo "mise"; } clean_dev_rust() { :; } check_rust_toolchains() { :; } check_android_ndk() { :; } @@ -248,6 +266,7 @@ EOF [ "$status" -eq 0 ] [[ "$output" == *"npm"* ]] + [[ "$output" == *"mise"* ]] [[ "$output" == *"brew"* ]] } diff --git a/tests/uninstall.bats b/tests/uninstall.bats index 0c55367..6e53467 100644 --- a/tests/uninstall.bats +++ b/tests/uninstall.bats @@ -260,6 +260,44 @@ EOF [ "$status" -eq 0 ] } +@test "uninstall_resolve_display_name keeps versioned app names when metadata is generic" { + run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc <<'EOF' +set -euo pipefail +source "$PROJECT_ROOT/lib/core/common.sh" + +function run_with_timeout() { + shift + "$@" +} + +function mdls() { + echo "Xcode" +} + +function plutil() { + if [[ "$3" == *"Info.plist" ]]; then + echo "Xcode" + return 0 + fi + return 1 +} + +MOLE_UNINSTALL_USER_LC_ALL="" +MOLE_UNINSTALL_USER_LANG="" + +eval "$(sed -n '/^uninstall_resolve_display_name()/,/^}/p' "$PROJECT_ROOT/bin/uninstall.sh")" + +app_path="$HOME/Applications/Xcode 16.4.app" +mkdir -p "$app_path/Contents" +touch "$app_path/Contents/Info.plist" + +result=$(uninstall_resolve_display_name "$app_path" "Xcode 16.4.app") +[[ "$result" == "Xcode 16.4" ]] || exit 1 +EOF + + [ "$status" -eq 0 ] +} + @test "decode_file_list handles empty input" { run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc <<'EOF' set -euo pipefail