mirror of
https://github.com/tw93/Mole.git
synced 2026-03-22 15:00:07 +00:00
fix brew uninstall fallback consistency
This commit is contained in:
@@ -530,15 +530,35 @@ batch_uninstall_applications() {
|
||||
if brew_uninstall_cask "$cask_name" "$app_path"; then
|
||||
used_brew_successfully=true
|
||||
else
|
||||
# Fallback to manual removal if brew fails
|
||||
if [[ "$needs_sudo" == true ]]; then
|
||||
if ! safe_sudo_remove "$app_path"; then
|
||||
reason="brew failed, manual removal failed"
|
||||
# Only fall back to manual app removal when Homebrew no longer
|
||||
# tracks the cask. Otherwise we would recreate the mismatch
|
||||
# where brew still reports the app as installed after Mole
|
||||
# removes the bundle manually.
|
||||
local cask_state=2
|
||||
if command -v is_brew_cask_installed > /dev/null 2>&1; then
|
||||
if is_brew_cask_installed "$cask_name"; then
|
||||
cask_state=0
|
||||
else
|
||||
cask_state=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $cask_state -eq 1 ]]; then
|
||||
if [[ "$needs_sudo" == true ]]; then
|
||||
if ! safe_sudo_remove "$app_path"; then
|
||||
reason="brew cleanup incomplete, manual removal failed"
|
||||
fi
|
||||
else
|
||||
if ! safe_remove "$app_path" true; then
|
||||
reason="brew cleanup incomplete, manual removal failed"
|
||||
fi
|
||||
fi
|
||||
elif [[ $cask_state -eq 0 ]]; then
|
||||
reason="brew uninstall failed, package still installed"
|
||||
suggestion="Run brew uninstall --cask --zap $cask_name"
|
||||
else
|
||||
if ! safe_remove "$app_path" true; then
|
||||
reason="brew failed, manual removal failed"
|
||||
fi
|
||||
reason="brew uninstall failed, package state unknown"
|
||||
suggestion="Run brew uninstall --cask --zap $cask_name"
|
||||
fi
|
||||
fi
|
||||
elif [[ "$needs_sudo" == true ]]; then
|
||||
|
||||
@@ -35,6 +35,21 @@ is_homebrew_available() {
|
||||
command -v brew > /dev/null 2>&1
|
||||
}
|
||||
|
||||
# Check whether a cask is still recorded as installed in Homebrew.
|
||||
# Exit codes:
|
||||
# 0 - cask is installed
|
||||
# 1 - cask is not installed
|
||||
# 2 - install state could not be determined
|
||||
is_brew_cask_installed() {
|
||||
local cask_name="$1"
|
||||
[[ -n "$cask_name" ]] || return 2
|
||||
is_homebrew_available || return 2
|
||||
|
||||
local cask_list
|
||||
cask_list=$(HOMEBREW_NO_ENV_HINTS=1 brew list --cask 2> /dev/null) || return 2
|
||||
grep -qxF "$cask_name" <<< "$cask_list"
|
||||
}
|
||||
|
||||
# Extract cask token from a Caskroom path
|
||||
# Args: $1 - path (must be inside Caskroom)
|
||||
# Prints: cask token to stdout
|
||||
@@ -211,7 +226,12 @@ brew_uninstall_cask() {
|
||||
|
||||
# Verify removal (only if not timed out)
|
||||
local cask_gone=true app_gone=true
|
||||
HOMEBREW_NO_ENV_HINTS=1 brew list --cask 2> /dev/null | grep -qxF "$cask_name" && cask_gone=false
|
||||
if is_brew_cask_installed "$cask_name"; then
|
||||
cask_gone=false
|
||||
else
|
||||
local cask_state=$?
|
||||
[[ $cask_state -eq 1 ]] || cask_gone=false
|
||||
fi
|
||||
[[ -n "$app_path" && -e "$app_path" ]] && app_gone=false
|
||||
|
||||
# Success: uninstall worked and both are gone, or already uninstalled
|
||||
|
||||
@@ -228,6 +228,122 @@ EOF
|
||||
[[ "$output" != *"Checking brew dependencies"* ]]
|
||||
}
|
||||
|
||||
@test "batch_uninstall_applications keeps brew-managed app intact when brew uninstall fails" {
|
||||
local app_bundle="$HOME/Applications/BrewBroken.app"
|
||||
mkdir -p "$app_bundle"
|
||||
|
||||
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/uninstall/batch.sh"
|
||||
|
||||
start_inline_spinner() { :; }
|
||||
stop_inline_spinner() { :; }
|
||||
get_file_owner() { whoami; }
|
||||
get_path_size_kb() { echo "100"; }
|
||||
bytes_to_human() { echo "$1"; }
|
||||
drain_pending_input() { :; }
|
||||
print_summary_block() { :; }
|
||||
force_kill_app() { return 0; }
|
||||
remove_apps_from_dock() { :; }
|
||||
stop_launch_services() { :; }
|
||||
unregister_app_bundle() { :; }
|
||||
remove_login_item() { :; }
|
||||
find_app_files() { return 0; }
|
||||
find_app_system_files() { return 0; }
|
||||
get_diagnostic_report_paths_for_app() { return 0; }
|
||||
calculate_total_size() { echo "0"; }
|
||||
has_sensitive_data() { return 1; }
|
||||
decode_file_list() { return 0; }
|
||||
remove_file_list() { :; }
|
||||
run_with_timeout() { shift; "$@"; }
|
||||
|
||||
safe_remove() {
|
||||
echo "SAFE_REMOVE:$1" >> "$HOME/remove.log"
|
||||
rm -rf "$1"
|
||||
}
|
||||
|
||||
safe_sudo_remove() {
|
||||
echo "SAFE_SUDO_REMOVE:$1" >> "$HOME/remove.log"
|
||||
rm -rf "$1"
|
||||
}
|
||||
|
||||
get_brew_cask_name() { echo "brew-broken-cask"; return 0; }
|
||||
brew_uninstall_cask() { return 1; }
|
||||
is_brew_cask_installed() { return 0; }
|
||||
|
||||
selected_apps=("0|$HOME/Applications/BrewBroken.app|BrewBroken|com.example.brewbroken|0|Never")
|
||||
files_cleaned=0
|
||||
total_items=0
|
||||
total_size_cleaned=0
|
||||
|
||||
printf '\n' | batch_uninstall_applications > /dev/null 2>&1 || true
|
||||
|
||||
[[ -d "$HOME/Applications/BrewBroken.app" ]]
|
||||
[[ ! -f "$HOME/remove.log" ]]
|
||||
EOF
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "batch_uninstall_applications finishes cleanup after brew removes cask record" {
|
||||
local app_bundle="$HOME/Applications/BrewCleanup.app"
|
||||
mkdir -p "$app_bundle"
|
||||
|
||||
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/uninstall/batch.sh"
|
||||
|
||||
start_inline_spinner() { :; }
|
||||
stop_inline_spinner() { :; }
|
||||
get_file_owner() { whoami; }
|
||||
get_path_size_kb() { echo "100"; }
|
||||
bytes_to_human() { echo "$1"; }
|
||||
drain_pending_input() { :; }
|
||||
print_summary_block() { :; }
|
||||
force_kill_app() { return 0; }
|
||||
remove_apps_from_dock() { :; }
|
||||
stop_launch_services() { :; }
|
||||
unregister_app_bundle() { :; }
|
||||
remove_login_item() { :; }
|
||||
find_app_files() { return 0; }
|
||||
find_app_system_files() { return 0; }
|
||||
get_diagnostic_report_paths_for_app() { return 0; }
|
||||
calculate_total_size() { echo "0"; }
|
||||
has_sensitive_data() { return 1; }
|
||||
decode_file_list() { return 0; }
|
||||
remove_file_list() { :; }
|
||||
run_with_timeout() { shift; "$@"; }
|
||||
|
||||
safe_remove() {
|
||||
echo "SAFE_REMOVE:$1" >> "$HOME/remove.log"
|
||||
rm -rf "$1"
|
||||
}
|
||||
|
||||
safe_sudo_remove() {
|
||||
echo "SAFE_SUDO_REMOVE:$1" >> "$HOME/remove.log"
|
||||
rm -rf "$1"
|
||||
}
|
||||
|
||||
get_brew_cask_name() { echo "brew-cleanup-cask"; return 0; }
|
||||
brew_uninstall_cask() { return 1; }
|
||||
is_brew_cask_installed() { return 1; }
|
||||
|
||||
selected_apps=("0|$HOME/Applications/BrewCleanup.app|BrewCleanup|com.example.brewcleanup|0|Never")
|
||||
files_cleaned=0
|
||||
total_items=0
|
||||
total_size_cleaned=0
|
||||
|
||||
printf '\n' | batch_uninstall_applications > /dev/null 2>&1
|
||||
|
||||
[[ ! -d "$HOME/Applications/BrewCleanup.app" ]]
|
||||
grep -q "SAFE_REMOVE:$HOME/Applications/BrewCleanup.app" "$HOME/remove.log"
|
||||
EOF
|
||||
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "brew_uninstall_cask does not trigger extra sudo pre-auth" {
|
||||
run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc << 'EOF'
|
||||
set -euo pipefail
|
||||
|
||||
Reference in New Issue
Block a user