**Related issue:** Resolves #48638, resolves #48225 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [ ] Input data is properly validated, `SELECT *` is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters. - [x] Timeouts are implemented and retries are limited to avoid infinite loops ## Testing - [x] QA'd all new/changed functionality manually ## Details Follow-up to #49030 (GitHub Desktop, #48639), which fixed one instance of this bug. An audit for the raw pattern found **15 more custom FMA scripts** carrying the same broken check that #42951 fixed in the generated helpers: gating on the **exit status** of `osascript -e 'application id "..." is running'`. osascript exits 0 whether it prints `true` or `false`, so a fully-quit app is misclassified as running whenever the bundle id resolves. Impact by script: - **Relaunch after every patch (user-visible — the filed bugs):** `zoom_install.sh` (#48638) and `google_chrome_install.sh` (#48225) set `*_WAS_RUNNING=true` unconditionally and reopen the app after `installer`, even when the user had nothing open. - **Broken check, no relaunch step (needless quit attempts, misleading logs):** install scripts for 1Password, Adobe CC, ExpressVPN, Grammarly, LogiTune, Microsoft Edge, P4V, Slack; uninstall scripts for Adobe CC, CleanMyMac, GPG Suite, Microsoft Word, P4V. Note `tell application id X to quit` against a not-running app can briefly launch it to deliver the quit event, so these aren't purely cosmetic either. The fix is the same one-line pattern everywhere, style-matched to each script (`local`/POSIX `[ ]`/top-level variants preserved): capture osascript output and compare it to `"true"`. No other behavior changed — this PR deliberately does not touch relaunch methods or console-user guards. Regenerated the 13 affected darwin manifests with `go run ./cmd/maintained-apps -slug <slug>`. All diffs are script-ref-only except `google-chrome/darwin.json`, which also picked up the legitimate upstream 150.0.7871.115 version bump during regeneration (the daily ingest cron would publish it tonight regardless). An unrelated `google-chrome/windows.json` winget bump was excluded. ## Manual QA Reproduced the bug live on macOS with the shipped Zoom script logic (ref `05e6a85c`) against a **fully-quit** Zoom (verified `is running` = `false`, zero processes): the exit-status check set `ZOOM_WAS_RUNNING=true` and the relaunch step launched Zoom — exactly the customer report, no background helpers needed. The corrected output-compare check on the same state correctly reported not running. Equivalent verification for the shared-helper variant was done against GitHub Desktop in #49030 (both the fully-quit and running→quit→relaunch paths). Verified for all 16 scripts: `bash -n` passes, no `if [!] osascript -e "application id ...` pattern remains anywhere under `inputs/homebrew/scripts/`, and every regenerated manifest ref carries the output-compare check. Remaining by-design behavior (unchanged): an app running with a dock icon but no visible window is genuinely running and will still be quit and relaunched; window-aware relaunching would be a separate enhancement. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved app detection before install/uninstall steps, reducing unnecessary quit attempts and making setup flows more reliable. * Updated several app install/uninstall workflows to better handle running apps, cleanup, and restart behavior. * Refined a few app package definitions to point to newer supported versions. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
135 lines
4.1 KiB
Bash
Executable File
135 lines
4.1 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# variables
|
|
APPDIR="/Applications/"
|
|
LOGGED_IN_USER=$(scutil <<< "show State:/Users/ConsoleUser" | awk '/Name :/ { print $3 }')
|
|
|
|
# functions
|
|
|
|
quit_application() {
|
|
local bundle_id="$1"
|
|
local timeout_duration=10
|
|
|
|
# check if the application is running
|
|
local app_running
|
|
app_running=$(osascript -e "application id \"$bundle_id\" is running" 2>/dev/null)
|
|
if [[ "$app_running" != "true" ]]; then
|
|
return
|
|
fi
|
|
|
|
local console_user
|
|
console_user=$(stat -f "%Su" /dev/console)
|
|
if [[ $EUID -eq 0 && "$console_user" == "root" ]]; then
|
|
echo "Not logged into a non-root GUI; skipping quitting application ID '$bundle_id'."
|
|
return
|
|
fi
|
|
|
|
echo "Quitting application '$bundle_id'..."
|
|
|
|
# try to quit the application within the timeout period
|
|
local quit_success=false
|
|
SECONDS=0
|
|
while (( SECONDS < timeout_duration )); do
|
|
if osascript -e "tell application id \"$bundle_id\" to quit" >/dev/null 2>&1; then
|
|
if ! pgrep -f "$bundle_id" >/dev/null 2>&1; then
|
|
echo "Application '$bundle_id' quit successfully."
|
|
quit_success=true
|
|
break
|
|
fi
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
if [[ "$quit_success" = false ]]; then
|
|
echo "Application '$bundle_id' did not quit."
|
|
fi
|
|
}
|
|
|
|
remove_launchctl_service() {
|
|
local service="$1"
|
|
local booleans=("true" "false")
|
|
local plist_status
|
|
local paths
|
|
local should_sudo
|
|
|
|
echo "Removing launchctl service ${service}"
|
|
|
|
for should_sudo in "${booleans[@]}"; do
|
|
plist_status=$(launchctl list "${service}" 2>/dev/null)
|
|
|
|
if [[ $plist_status == \{* ]]; then
|
|
if [[ $should_sudo == "true" ]]; then
|
|
sudo launchctl remove "${service}"
|
|
else
|
|
launchctl remove "${service}"
|
|
fi
|
|
sleep 1
|
|
fi
|
|
|
|
paths=(
|
|
"/Library/LaunchAgents/${service}.plist"
|
|
"/Library/LaunchDaemons/${service}.plist"
|
|
)
|
|
|
|
# if not using sudo, prepend the home directory to the paths
|
|
if [[ $should_sudo == "false" ]]; then
|
|
for i in "${!paths[@]}"; do
|
|
paths[i]="${HOME}${paths[i]}"
|
|
done
|
|
fi
|
|
|
|
for path in "${paths[@]}"; do
|
|
if [[ -e "$path" ]]; then
|
|
if [[ $should_sudo == "true" ]]; then
|
|
sudo rm -f -- "$path"
|
|
else
|
|
rm -f -- "$path"
|
|
fi
|
|
fi
|
|
done
|
|
done
|
|
}
|
|
|
|
trash() {
|
|
local logged_in_user="$1"
|
|
local target_file="$2"
|
|
local timestamp="$(date +%Y-%m-%d-%s)"
|
|
local rand="$(jot -r 1 0 99999)"
|
|
|
|
# replace ~ with /Users/$logged_in_user
|
|
if [[ "$target_file" == ~* ]]; then
|
|
target_file="/Users/$logged_in_user${target_file:1}"
|
|
fi
|
|
|
|
local trash="/Users/$logged_in_user/.Trash"
|
|
local file_name="$(basename "${target_file}")"
|
|
|
|
if [[ -e "$target_file" ]]; then
|
|
echo "removing $target_file."
|
|
mv -f "$target_file" "$trash/${file_name}_${timestamp}_${rand}"
|
|
else
|
|
echo "$target_file doesn't exist."
|
|
fi
|
|
}
|
|
|
|
remove_launchctl_service 'com.macpaw.CleanMyMac5.HealthMonitor'
|
|
remove_launchctl_service 'com.macpaw.CleanMyMac5.Menu'
|
|
quit_application 'com.macpaw.CleanMyMac5'
|
|
quit_application 'com.macpaw.CleanMyMac5.HealthMonitor'
|
|
quit_application 'com.macpaw.CleanMyMac5.Menu'
|
|
sudo rm -rf '/Library/PrivilegedHelperTools/com.macpaw.CleanMyMac5.Agent'
|
|
sudo rm -rf "$APPDIR/CleanMyMac_5.app"
|
|
trash $LOGGED_IN_USER '/Library/LaunchDaemons/com.macpaw.CleanMyMac5.Agent.plist'
|
|
trash $LOGGED_IN_USER '/Library/PrivilegedHelperTools/com.macpaw.CleanMyMac5.Agent'
|
|
trash $LOGGED_IN_USER '/Users/Shared/CleanMyMac_5'
|
|
trash $LOGGED_IN_USER '~/Library/Application Scripts/S8EX82NJP6.com.macpaw.CleanMyMac5'
|
|
trash $LOGGED_IN_USER '~/Library/Application Support/CleanMyMac_5'
|
|
trash $LOGGED_IN_USER '~/Library/Caches/com.macpaw.CleanMyMac5'
|
|
trash $LOGGED_IN_USER '~/Library/Group Containers/S8EX82NJP6.com.macpaw.CleanMyMac5'
|
|
trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.macpaw.CleanMyMac5'
|
|
trash $LOGGED_IN_USER '~/Library/HTTPStorages/com.macpaw.CleanMyMac5.binarycookies'
|
|
trash $LOGGED_IN_USER '~/Library/LaunchAgents/com.macpaw.CleanMyMac5.Updater.plist'
|
|
trash $LOGGED_IN_USER '~/Library/Logs/com.macpaw.CleanMyMac5'
|
|
trash $LOGGED_IN_USER '~/Library/Preferences/com.macpaw.CleanMyMac5.plist'
|
|
trash $LOGGED_IN_USER '~/Library/Saved Application State/com.macpaw.CleanMyMac5.savedState'
|