mirror of
https://github.com/tw93/Mole.git
synced 2026-02-15 16:55:06 +00:00
chore: auto format code
This commit is contained in:
@@ -13,7 +13,7 @@ _MOLE_CORE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||||||
[[ -z "${MOLE_BASE_LOADED:-}" ]] && source "$_MOLE_CORE_DIR/base.sh"
|
[[ -z "${MOLE_BASE_LOADED:-}" ]] && source "$_MOLE_CORE_DIR/base.sh"
|
||||||
|
|
||||||
# Declare WHITELIST_PATTERNS if not already set (used by is_path_whitelisted)
|
# Declare WHITELIST_PATTERNS if not already set (used by is_path_whitelisted)
|
||||||
if ! declare -p WHITELIST_PATTERNS &>/dev/null; then
|
if ! declare -p WHITELIST_PATTERNS &> /dev/null; then
|
||||||
declare -a WHITELIST_PATTERNS=()
|
declare -a WHITELIST_PATTERNS=()
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -737,13 +737,13 @@ find_app_files() {
|
|||||||
[[ -f ~/Library/Preferences/"$bundle_id".plist ]] && files_to_clean+=("$HOME/Library/Preferences/$bundle_id.plist")
|
[[ -f ~/Library/Preferences/"$bundle_id".plist ]] && files_to_clean+=("$HOME/Library/Preferences/$bundle_id.plist")
|
||||||
[[ -d ~/Library/Preferences/ByHost ]] && while IFS= read -r -d '' pref; do
|
[[ -d ~/Library/Preferences/ByHost ]] && while IFS= read -r -d '' pref; do
|
||||||
files_to_clean+=("$pref")
|
files_to_clean+=("$pref")
|
||||||
done < <(command find ~/Library/Preferences/ByHost -maxdepth 1 \( -name "$bundle_id*.plist" \) -print0 2>/dev/null)
|
done < <(command find ~/Library/Preferences/ByHost -maxdepth 1 \( -name "$bundle_id*.plist" \) -print0 2> /dev/null)
|
||||||
|
|
||||||
# Group Containers (special handling)
|
# Group Containers (special handling)
|
||||||
if [[ -d ~/Library/Group\ Containers ]]; then
|
if [[ -d ~/Library/Group\ Containers ]]; then
|
||||||
while IFS= read -r -d '' container; do
|
while IFS= read -r -d '' container; do
|
||||||
files_to_clean+=("$container")
|
files_to_clean+=("$container")
|
||||||
done < <(command find ~/Library/Group\ Containers -maxdepth 1 \( -name "*$bundle_id*" \) -print0 2>/dev/null)
|
done < <(command find ~/Library/Group\ Containers -maxdepth 1 \( -name "*$bundle_id*" \) -print0 2> /dev/null)
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -758,7 +758,7 @@ find_app_files() {
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
files_to_clean+=("$plist")
|
files_to_clean+=("$plist")
|
||||||
done < <(command find ~/Library/LaunchAgents -maxdepth 1 -name "*$app_name*.plist" -print0 2>/dev/null)
|
done < <(command find ~/Library/LaunchAgents -maxdepth 1 -name "*$app_name*.plist" -print0 2> /dev/null)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Handle specialized toolchains and development environments
|
# Handle specialized toolchains and development environments
|
||||||
@@ -774,7 +774,7 @@ find_app_files() {
|
|||||||
for d in ~/AndroidStudioProjects ~/Library/Android ~/.android; do
|
for d in ~/AndroidStudioProjects ~/Library/Android ~/.android; do
|
||||||
[[ -d "$d" ]] && files_to_clean+=("$d")
|
[[ -d "$d" ]] && files_to_clean+=("$d")
|
||||||
done
|
done
|
||||||
[[ -d ~/Library/Application\ Support/Google ]] && while IFS= read -r -d '' d; do files_to_clean+=("$d"); done < <(command find ~/Library/Application\ Support/Google -maxdepth 1 -name "AndroidStudio*" -print0 2>/dev/null)
|
[[ -d ~/Library/Application\ Support/Google ]] && while IFS= read -r -d '' d; do files_to_clean+=("$d"); done < <(command find ~/Library/Application\ Support/Google -maxdepth 1 -name "AndroidStudio*" -print0 2> /dev/null)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 3. Xcode (Apple)
|
# 3. Xcode (Apple)
|
||||||
@@ -786,7 +786,7 @@ find_app_files() {
|
|||||||
# 4. JetBrains (IDE settings)
|
# 4. JetBrains (IDE settings)
|
||||||
if [[ "$bundle_id" =~ jetbrains ]] || [[ "$app_name" =~ IntelliJ|PyCharm|WebStorm|GoLand|RubyMine|PhpStorm|CLion|DataGrip|Rider ]]; then
|
if [[ "$bundle_id" =~ jetbrains ]] || [[ "$app_name" =~ IntelliJ|PyCharm|WebStorm|GoLand|RubyMine|PhpStorm|CLion|DataGrip|Rider ]]; then
|
||||||
for base in ~/Library/Application\ Support/JetBrains ~/Library/Caches/JetBrains ~/Library/Logs/JetBrains; do
|
for base in ~/Library/Application\ Support/JetBrains ~/Library/Caches/JetBrains ~/Library/Logs/JetBrains; do
|
||||||
[[ -d "$base" ]] && while IFS= read -r -d '' d; do files_to_clean+=("$d"); done < <(command find "$base" -maxdepth 1 -name "${app_name}*" -print0 2>/dev/null)
|
[[ -d "$base" ]] && while IFS= read -r -d '' d; do files_to_clean+=("$d"); done < <(command find "$base" -maxdepth 1 -name "${app_name}*" -print0 2> /dev/null)
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -868,7 +868,7 @@ find_app_system_files() {
|
|||||||
for base in /Library/LaunchAgents /Library/LaunchDaemons; do
|
for base in /Library/LaunchAgents /Library/LaunchDaemons; do
|
||||||
[[ -d "$base" ]] && while IFS= read -r -d '' plist; do
|
[[ -d "$base" ]] && while IFS= read -r -d '' plist; do
|
||||||
system_files+=("$plist")
|
system_files+=("$plist")
|
||||||
done < <(command find "$base" -maxdepth 1 \( -name "*$app_name*.plist" \) -print0 2>/dev/null)
|
done < <(command find "$base" -maxdepth 1 \( -name "*$app_name*.plist" \) -print0 2> /dev/null)
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -877,11 +877,11 @@ find_app_system_files() {
|
|||||||
if [[ -n "$bundle_id" && "$bundle_id" != "unknown" && ${#bundle_id} -gt 3 ]]; then
|
if [[ -n "$bundle_id" && "$bundle_id" != "unknown" && ${#bundle_id} -gt 3 ]]; then
|
||||||
[[ -d /Library/PrivilegedHelperTools ]] && while IFS= read -r -d '' helper; do
|
[[ -d /Library/PrivilegedHelperTools ]] && while IFS= read -r -d '' helper; do
|
||||||
system_files+=("$helper")
|
system_files+=("$helper")
|
||||||
done < <(command find /Library/PrivilegedHelperTools -maxdepth 1 \( -name "$bundle_id*" \) -print0 2>/dev/null)
|
done < <(command find /Library/PrivilegedHelperTools -maxdepth 1 \( -name "$bundle_id*" \) -print0 2> /dev/null)
|
||||||
|
|
||||||
[[ -d /private/var/db/receipts ]] && while IFS= read -r -d '' receipt; do
|
[[ -d /private/var/db/receipts ]] && while IFS= read -r -d '' receipt; do
|
||||||
system_files+=("$receipt")
|
system_files+=("$receipt")
|
||||||
done < <(command find /private/var/db/receipts -maxdepth 1 \( -name "*$bundle_id*" \) -print0 2>/dev/null)
|
done < <(command find /private/var/db/receipts -maxdepth 1 \( -name "*$bundle_id*" \) -print0 2> /dev/null)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local receipt_files=""
|
local receipt_files=""
|
||||||
@@ -926,7 +926,7 @@ find_app_receipt_files() {
|
|||||||
if [[ -d /private/var/db/receipts ]]; then
|
if [[ -d /private/var/db/receipts ]]; then
|
||||||
while IFS= read -r -d '' bom; do
|
while IFS= read -r -d '' bom; do
|
||||||
bom_files+=("$bom")
|
bom_files+=("$bom")
|
||||||
done < <(find /private/var/db/receipts -maxdepth 1 -name "${bundle_id}*.bom" -print0 2>/dev/null)
|
done < <(find /private/var/db/receipts -maxdepth 1 -name "${bundle_id}*.bom" -print0 2> /dev/null)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Process bom files if any found
|
# Process bom files if any found
|
||||||
@@ -938,7 +938,7 @@ find_app_receipt_files() {
|
|||||||
# lsbom -f: file paths only
|
# lsbom -f: file paths only
|
||||||
# -s: suppress output (convert to text)
|
# -s: suppress output (convert to text)
|
||||||
local bom_content
|
local bom_content
|
||||||
bom_content=$(lsbom -f -s "$bom_file" 2>/dev/null)
|
bom_content=$(lsbom -f -s "$bom_file" 2> /dev/null)
|
||||||
|
|
||||||
while IFS= read -r file_path; do
|
while IFS= read -r file_path; do
|
||||||
# Standardize path (remove leading dot)
|
# Standardize path (remove leading dot)
|
||||||
@@ -988,7 +988,7 @@ find_app_receipt_files() {
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if declare -f should_protect_path >/dev/null 2>&1; then
|
if declare -f should_protect_path > /dev/null 2>&1; then
|
||||||
if should_protect_path "$clean_path"; then
|
if should_protect_path "$clean_path"; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
@@ -997,7 +997,7 @@ find_app_receipt_files() {
|
|||||||
receipt_files+=("$clean_path")
|
receipt_files+=("$clean_path")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
done <<<"$bom_content"
|
done <<< "$bom_content"
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
if [[ ${#receipt_files[@]} -gt 0 ]]; then
|
if [[ ${#receipt_files[@]} -gt 0 ]]; then
|
||||||
@@ -1014,34 +1014,34 @@ force_kill_app() {
|
|||||||
# Get the executable name from bundle if app_path is provided
|
# Get the executable name from bundle if app_path is provided
|
||||||
local exec_name=""
|
local exec_name=""
|
||||||
if [[ -n "$app_path" && -e "$app_path/Contents/Info.plist" ]]; then
|
if [[ -n "$app_path" && -e "$app_path/Contents/Info.plist" ]]; then
|
||||||
exec_name=$(defaults read "$app_path/Contents/Info.plist" CFBundleExecutable 2>/dev/null || echo "")
|
exec_name=$(defaults read "$app_path/Contents/Info.plist" CFBundleExecutable 2> /dev/null || echo "")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Use executable name for precise matching, fallback to app name
|
# Use executable name for precise matching, fallback to app name
|
||||||
local match_pattern="${exec_name:-$app_name}"
|
local match_pattern="${exec_name:-$app_name}"
|
||||||
|
|
||||||
# Check if process is running using exact match only
|
# Check if process is running using exact match only
|
||||||
if ! pgrep -x "$match_pattern" >/dev/null 2>&1; then
|
if ! pgrep -x "$match_pattern" > /dev/null 2>&1; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Try graceful termination first
|
# Try graceful termination first
|
||||||
pkill -x "$match_pattern" 2>/dev/null || true
|
pkill -x "$match_pattern" 2> /dev/null || true
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
# Check again after graceful kill
|
# Check again after graceful kill
|
||||||
if ! pgrep -x "$match_pattern" >/dev/null 2>&1; then
|
if ! pgrep -x "$match_pattern" > /dev/null 2>&1; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Force kill if still running
|
# Force kill if still running
|
||||||
pkill -9 -x "$match_pattern" 2>/dev/null || true
|
pkill -9 -x "$match_pattern" 2> /dev/null || true
|
||||||
sleep 2
|
sleep 2
|
||||||
|
|
||||||
# If still running and sudo is available, try with sudo
|
# If still running and sudo is available, try with sudo
|
||||||
if pgrep -x "$match_pattern" >/dev/null 2>&1; then
|
if pgrep -x "$match_pattern" > /dev/null 2>&1; then
|
||||||
if sudo -n true 2>/dev/null; then
|
if sudo -n true 2> /dev/null; then
|
||||||
sudo pkill -9 -x "$match_pattern" 2>/dev/null || true
|
sudo pkill -9 -x "$match_pattern" 2> /dev/null || true
|
||||||
sleep 2
|
sleep 2
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -1049,7 +1049,7 @@ force_kill_app() {
|
|||||||
# Final check with longer timeout for stubborn processes
|
# Final check with longer timeout for stubborn processes
|
||||||
local retries=3
|
local retries=3
|
||||||
while [[ $retries -gt 0 ]]; do
|
while [[ $retries -gt 0 ]]; do
|
||||||
if ! pgrep -x "$match_pattern" >/dev/null 2>&1; then
|
if ! pgrep -x "$match_pattern" > /dev/null 2>&1; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
sleep 1
|
sleep 1
|
||||||
@@ -1057,7 +1057,7 @@ force_kill_app() {
|
|||||||
done
|
done
|
||||||
|
|
||||||
# Still running after all attempts
|
# Still running after all attempts
|
||||||
pgrep -x "$match_pattern" >/dev/null 2>&1 && return 1 || return 0
|
pgrep -x "$match_pattern" > /dev/null 2>&1 && return 1 || return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# Note: calculate_total_size() is defined in lib/core/file_ops.sh
|
# Note: calculate_total_size() is defined in lib/core/file_ops.sh
|
||||||
|
|||||||
@@ -43,9 +43,9 @@ update_via_homebrew() {
|
|||||||
echo "Updating Homebrew..."
|
echo "Updating Homebrew..."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
brew update >"$temp_update" 2>&1 &
|
brew update > "$temp_update" 2>&1 &
|
||||||
local update_pid=$!
|
local update_pid=$!
|
||||||
wait $update_pid 2>/dev/null || true # Continue even if brew update fails
|
wait $update_pid 2> /dev/null || true # Continue even if brew update fails
|
||||||
|
|
||||||
if [[ -t 1 ]]; then
|
if [[ -t 1 ]]; then
|
||||||
stop_inline_spinner
|
stop_inline_spinner
|
||||||
@@ -58,9 +58,9 @@ update_via_homebrew() {
|
|||||||
echo "Upgrading Mole..."
|
echo "Upgrading Mole..."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
brew upgrade mole >"$temp_upgrade" 2>&1 &
|
brew upgrade mole > "$temp_upgrade" 2>&1 &
|
||||||
local upgrade_pid=$!
|
local upgrade_pid=$!
|
||||||
wait $upgrade_pid 2>/dev/null || true # Continue even if brew upgrade fails
|
wait $upgrade_pid 2> /dev/null || true # Continue even if brew upgrade fails
|
||||||
|
|
||||||
local upgrade_output
|
local upgrade_output
|
||||||
upgrade_output=$(cat "$temp_upgrade")
|
upgrade_output=$(cat "$temp_upgrade")
|
||||||
@@ -78,7 +78,7 @@ update_via_homebrew() {
|
|||||||
|
|
||||||
if echo "$upgrade_output" | grep -q "already installed"; then
|
if echo "$upgrade_output" | grep -q "already installed"; then
|
||||||
local installed_version
|
local installed_version
|
||||||
installed_version=$(brew list --versions mole 2>/dev/null | awk '{print $2}')
|
installed_version=$(brew list --versions mole 2> /dev/null | awk '{print $2}')
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${GREEN}${ICON_SUCCESS}${NC} Already on latest version (${installed_version:-$current_version})"
|
echo -e "${GREEN}${ICON_SUCCESS}${NC} Already on latest version (${installed_version:-$current_version})"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -89,14 +89,14 @@ update_via_homebrew() {
|
|||||||
else
|
else
|
||||||
echo "$upgrade_output" | grep -Ev "^(==>|Updating Homebrew|Warning:)" || true
|
echo "$upgrade_output" | grep -Ev "^(==>|Updating Homebrew|Warning:)" || true
|
||||||
local new_version
|
local new_version
|
||||||
new_version=$(brew list --versions mole 2>/dev/null | awk '{print $2}')
|
new_version=$(brew list --versions mole 2> /dev/null | awk '{print $2}')
|
||||||
echo ""
|
echo ""
|
||||||
echo -e "${GREEN}${ICON_SUCCESS}${NC} Updated to latest version (${new_version:-$current_version})"
|
echo -e "${GREEN}${ICON_SUCCESS}${NC} Updated to latest version (${new_version:-$current_version})"
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Clear update cache (suppress errors if cache doesn't exist or is locked)
|
# Clear update cache (suppress errors if cache doesn't exist or is locked)
|
||||||
rm -f "$HOME/.cache/mole/version_check" "$HOME/.cache/mole/update_message" 2>/dev/null || true
|
rm -f "$HOME/.cache/mole/version_check" "$HOME/.cache/mole/update_message" 2> /dev/null || true
|
||||||
}
|
}
|
||||||
|
|
||||||
# Remove applications from Dock
|
# Remove applications from Dock
|
||||||
@@ -133,7 +133,7 @@ remove_apps_from_dock() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -e "$app_path" ]]; then
|
if [[ -e "$app_path" ]]; then
|
||||||
if full_path=$(cd "$(dirname "$app_path")" 2>/dev/null && pwd); then
|
if full_path=$(cd "$(dirname "$app_path")" 2> /dev/null && pwd); then
|
||||||
full_path="$full_path/$(basename "$app_path")"
|
full_path="$full_path/$(basename "$app_path")"
|
||||||
else
|
else
|
||||||
continue
|
continue
|
||||||
@@ -154,11 +154,11 @@ remove_apps_from_dock() {
|
|||||||
local i=0
|
local i=0
|
||||||
while true; do
|
while true; do
|
||||||
local label
|
local label
|
||||||
label=$(/usr/libexec/PlistBuddy -c "Print :persistent-apps:$i:tile-data:file-label" "$plist" 2>/dev/null || echo "")
|
label=$(/usr/libexec/PlistBuddy -c "Print :persistent-apps:$i:tile-data:file-label" "$plist" 2> /dev/null || echo "")
|
||||||
[[ -z "$label" ]] && break
|
[[ -z "$label" ]] && break
|
||||||
|
|
||||||
local url
|
local url
|
||||||
url=$(/usr/libexec/PlistBuddy -c "Print :persistent-apps:$i:tile-data:file-data:_CFURLString" "$plist" 2>/dev/null || echo "")
|
url=$(/usr/libexec/PlistBuddy -c "Print :persistent-apps:$i:tile-data:file-data:_CFURLString" "$plist" 2> /dev/null || echo "")
|
||||||
[[ -z "$url" ]] && {
|
[[ -z "$url" ]] && {
|
||||||
((i++))
|
((i++))
|
||||||
continue
|
continue
|
||||||
@@ -166,7 +166,7 @@ remove_apps_from_dock() {
|
|||||||
|
|
||||||
# Match by URL-encoded path to handle spaces in app names
|
# Match by URL-encoded path to handle spaces in app names
|
||||||
if [[ -n "$encoded_path" && "$url" == *"$encoded_path"* ]]; then
|
if [[ -n "$encoded_path" && "$url" == *"$encoded_path"* ]]; then
|
||||||
if /usr/libexec/PlistBuddy -c "Delete :persistent-apps:$i" "$plist" 2>/dev/null; then
|
if /usr/libexec/PlistBuddy -c "Delete :persistent-apps:$i" "$plist" 2> /dev/null; then
|
||||||
changed=true
|
changed=true
|
||||||
# After deletion, current index i now points to the next item
|
# After deletion, current index i now points to the next item
|
||||||
continue
|
continue
|
||||||
@@ -178,6 +178,6 @@ remove_apps_from_dock() {
|
|||||||
|
|
||||||
if [[ "$changed" == "true" ]]; then
|
if [[ "$changed" == "true" ]]; then
|
||||||
# Restart Dock to apply changes from the plist
|
# Restart Dock to apply changes from the plist
|
||||||
killall Dock 2>/dev/null || true
|
killall Dock 2> /dev/null || true
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ validate_path_for_deletion() {
|
|||||||
# Check symlink target if path is a symbolic link
|
# Check symlink target if path is a symbolic link
|
||||||
if [[ -L "$path" ]]; then
|
if [[ -L "$path" ]]; then
|
||||||
local link_target
|
local link_target
|
||||||
link_target=$(readlink "$path" 2>/dev/null) || {
|
link_target=$(readlink "$path" 2> /dev/null) || {
|
||||||
log_error "Cannot read symlink: $path"
|
log_error "Cannot read symlink: $path"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ validate_path_for_deletion() {
|
|||||||
if [[ "$link_target" != /* ]]; then
|
if [[ "$link_target" != /* ]]; then
|
||||||
local link_dir
|
local link_dir
|
||||||
link_dir=$(dirname "$path")
|
link_dir=$(dirname "$path")
|
||||||
resolved_target=$(cd "$link_dir" 2>/dev/null && cd "$(dirname "$link_target")" 2>/dev/null && pwd)/$(basename "$link_target") || resolved_target=""
|
resolved_target=$(cd "$link_dir" 2> /dev/null && cd "$(dirname "$link_target")" 2> /dev/null && pwd)/$(basename "$link_target") || resolved_target=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Validate resolved target against protected paths
|
# Validate resolved target against protected paths
|
||||||
@@ -128,7 +128,7 @@ validate_path_for_deletion() {
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
# Check if path is protected (keychains, system settings, etc)
|
# Check if path is protected (keychains, system settings, etc)
|
||||||
if declare -f should_protect_path >/dev/null 2>&1; then
|
if declare -f should_protect_path > /dev/null 2>&1; then
|
||||||
if should_protect_path "$path"; then
|
if should_protect_path "$path"; then
|
||||||
if [[ "${MO_DEBUG:-0}" == "1" ]]; then
|
if [[ "${MO_DEBUG:-0}" == "1" ]]; then
|
||||||
log_warning "Path validation: protected path skipped: $path"
|
log_warning "Path validation: protected path skipped: $path"
|
||||||
@@ -171,16 +171,16 @@ safe_remove() {
|
|||||||
|
|
||||||
if [[ -e "$path" ]]; then
|
if [[ -e "$path" ]]; then
|
||||||
local size_kb
|
local size_kb
|
||||||
size_kb=$(get_path_size_kb "$path" 2>/dev/null || echo "0")
|
size_kb=$(get_path_size_kb "$path" 2> /dev/null || echo "0")
|
||||||
if [[ "$size_kb" -gt 0 ]]; then
|
if [[ "$size_kb" -gt 0 ]]; then
|
||||||
file_size=$(bytes_to_human "$((size_kb * 1024))")
|
file_size=$(bytes_to_human "$((size_kb * 1024))")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -f "$path" || -d "$path" ]] && ! [[ -L "$path" ]]; then
|
if [[ -f "$path" || -d "$path" ]] && ! [[ -L "$path" ]]; then
|
||||||
local mod_time
|
local mod_time
|
||||||
mod_time=$(stat -f%m "$path" 2>/dev/null || echo "0")
|
mod_time=$(stat -f%m "$path" 2> /dev/null || echo "0")
|
||||||
local now
|
local now
|
||||||
now=$(date +%s 2>/dev/null || echo "0")
|
now=$(date +%s 2> /dev/null || echo "0")
|
||||||
if [[ "$mod_time" -gt 0 && "$now" -gt 0 ]]; then
|
if [[ "$mod_time" -gt 0 && "$now" -gt 0 ]]; then
|
||||||
file_age=$(((now - mod_time) / 86400))
|
file_age=$(((now - mod_time) / 86400))
|
||||||
fi
|
fi
|
||||||
@@ -248,18 +248,18 @@ safe_sudo_remove() {
|
|||||||
local file_size=""
|
local file_size=""
|
||||||
local file_age=""
|
local file_age=""
|
||||||
|
|
||||||
if sudo test -e "$path" 2>/dev/null; then
|
if sudo test -e "$path" 2> /dev/null; then
|
||||||
local size_kb
|
local size_kb
|
||||||
size_kb=$(sudo du -sk "$path" 2>/dev/null | awk '{print $1}' || echo "0")
|
size_kb=$(sudo du -sk "$path" 2> /dev/null | awk '{print $1}' || echo "0")
|
||||||
if [[ "$size_kb" -gt 0 ]]; then
|
if [[ "$size_kb" -gt 0 ]]; then
|
||||||
file_size=$(bytes_to_human "$((size_kb * 1024))")
|
file_size=$(bytes_to_human "$((size_kb * 1024))")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if sudo test -f "$path" 2>/dev/null || sudo test -d "$path" 2>/dev/null; then
|
if sudo test -f "$path" 2> /dev/null || sudo test -d "$path" 2> /dev/null; then
|
||||||
local mod_time
|
local mod_time
|
||||||
mod_time=$(sudo stat -f%m "$path" 2>/dev/null || echo "0")
|
mod_time=$(sudo stat -f%m "$path" 2> /dev/null || echo "0")
|
||||||
local now
|
local now
|
||||||
now=$(date +%s 2>/dev/null || echo "0")
|
now=$(date +%s 2> /dev/null || echo "0")
|
||||||
if [[ "$mod_time" -gt 0 && "$now" -gt 0 ]]; then
|
if [[ "$mod_time" -gt 0 && "$now" -gt 0 ]]; then
|
||||||
file_age=$(((now - mod_time) / 86400))
|
file_age=$(((now - mod_time) / 86400))
|
||||||
fi
|
fi
|
||||||
@@ -276,7 +276,7 @@ safe_sudo_remove() {
|
|||||||
debug_log "Removing (sudo): $path"
|
debug_log "Removing (sudo): $path"
|
||||||
|
|
||||||
# Perform the deletion
|
# Perform the deletion
|
||||||
if sudo rm -rf "$path" 2>/dev/null; then # SAFE: safe_sudo_remove implementation
|
if sudo rm -rf "$path" 2> /dev/null; then # SAFE: safe_sudo_remove implementation
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
log_error "Failed to remove (sudo): $path"
|
log_error "Failed to remove (sudo): $path"
|
||||||
@@ -325,7 +325,7 @@ safe_find_delete() {
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
safe_remove "$match" true || true
|
safe_remove "$match" true || true
|
||||||
done < <(command find "$base_dir" "${find_args[@]}" -print0 2>/dev/null || true)
|
done < <(command find "$base_dir" "${find_args[@]}" -print0 2> /dev/null || true)
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -338,12 +338,12 @@ safe_sudo_find_delete() {
|
|||||||
local type_filter="${4:-f}"
|
local type_filter="${4:-f}"
|
||||||
|
|
||||||
# Validate base directory (use sudo for permission-restricted dirs)
|
# Validate base directory (use sudo for permission-restricted dirs)
|
||||||
if ! sudo test -d "$base_dir" 2>/dev/null; then
|
if ! sudo test -d "$base_dir" 2> /dev/null; then
|
||||||
debug_log "Directory does not exist (skipping): $base_dir"
|
debug_log "Directory does not exist (skipping): $base_dir"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if sudo test -L "$base_dir" 2>/dev/null; then
|
if sudo test -L "$base_dir" 2> /dev/null; then
|
||||||
log_error "Refusing to search symlinked directory: $base_dir"
|
log_error "Refusing to search symlinked directory: $base_dir"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@@ -367,7 +367,7 @@ safe_sudo_find_delete() {
|
|||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
safe_sudo_remove "$match" || true
|
safe_sudo_remove "$match" || true
|
||||||
done < <(sudo find "$base_dir" "${find_args[@]}" -print0 2>/dev/null || true)
|
done < <(sudo find "$base_dir" "${find_args[@]}" -print0 2> /dev/null || true)
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -387,7 +387,7 @@ get_path_size_kb() {
|
|||||||
# Use || echo 0 to ensure failure in du (e.g. permission error) doesn't exit script under set -e
|
# Use || echo 0 to ensure failure in du (e.g. permission error) doesn't exit script under set -e
|
||||||
# Pipefail would normally cause the pipeline to fail if du fails, but || handle catches it.
|
# Pipefail would normally cause the pipeline to fail if du fails, but || handle catches it.
|
||||||
local size
|
local size
|
||||||
size=$(command du -sk "$path" 2>/dev/null | awk 'NR==1 {print $1; exit}' || true)
|
size=$(command du -sk "$path" 2> /dev/null | awk 'NR==1 {print $1; exit}' || true)
|
||||||
|
|
||||||
# Ensure size is a valid number (fix for non-numeric du output)
|
# Ensure size is a valid number (fix for non-numeric du output)
|
||||||
if [[ "$size" =~ ^[0-9]+$ ]]; then
|
if [[ "$size" =~ ^[0-9]+$ ]]; then
|
||||||
@@ -408,7 +408,7 @@ calculate_total_size() {
|
|||||||
size_kb=$(get_path_size_kb "$file")
|
size_kb=$(get_path_size_kb "$file")
|
||||||
((total_kb += size_kb))
|
((total_kb += size_kb))
|
||||||
fi
|
fi
|
||||||
done <<<"$files"
|
done <<< "$files"
|
||||||
|
|
||||||
echo "$total_kb"
|
echo "$total_kb"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ has_sensitive_data() {
|
|||||||
return 0 # Found sensitive data
|
return 0 # Found sensitive data
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done <<<"$files"
|
done <<< "$files"
|
||||||
|
|
||||||
return 1 # Not found
|
return 1 # Not found
|
||||||
}
|
}
|
||||||
@@ -44,8 +44,8 @@ decode_file_list() {
|
|||||||
local decoded
|
local decoded
|
||||||
|
|
||||||
# macOS uses -D, GNU uses -d. Always return 0 for set -e safety.
|
# macOS uses -D, GNU uses -d. Always return 0 for set -e safety.
|
||||||
if ! decoded=$(printf '%s' "$encoded" | base64 -D 2>/dev/null); then
|
if ! decoded=$(printf '%s' "$encoded" | base64 -D 2> /dev/null); then
|
||||||
if ! decoded=$(printf '%s' "$encoded" | base64 -d 2>/dev/null); then
|
if ! decoded=$(printf '%s' "$encoded" | base64 -d 2> /dev/null); then
|
||||||
log_error "Failed to decode file list for $app_name" >&2
|
log_error "Failed to decode file list for $app_name" >&2
|
||||||
echo ""
|
echo ""
|
||||||
return 0 # Return success with empty string
|
return 0 # Return success with empty string
|
||||||
@@ -64,7 +64,7 @@ decode_file_list() {
|
|||||||
echo ""
|
echo ""
|
||||||
return 0 # Return success with empty string
|
return 0 # Return success with empty string
|
||||||
fi
|
fi
|
||||||
done <<<"$decoded"
|
done <<< "$decoded"
|
||||||
|
|
||||||
echo "$decoded"
|
echo "$decoded"
|
||||||
return 0
|
return 0
|
||||||
@@ -80,20 +80,20 @@ stop_launch_services() {
|
|||||||
|
|
||||||
if [[ -d ~/Library/LaunchAgents ]]; then
|
if [[ -d ~/Library/LaunchAgents ]]; then
|
||||||
while IFS= read -r -d '' plist; do
|
while IFS= read -r -d '' plist; do
|
||||||
launchctl unload "$plist" 2>/dev/null || true
|
launchctl unload "$plist" 2> /dev/null || true
|
||||||
done < <(find ~/Library/LaunchAgents -maxdepth 1 -name "${bundle_id}*.plist" -print0 2>/dev/null)
|
done < <(find ~/Library/LaunchAgents -maxdepth 1 -name "${bundle_id}*.plist" -print0 2> /dev/null)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$has_system_files" == "true" ]]; then
|
if [[ "$has_system_files" == "true" ]]; then
|
||||||
if [[ -d /Library/LaunchAgents ]]; then
|
if [[ -d /Library/LaunchAgents ]]; then
|
||||||
while IFS= read -r -d '' plist; do
|
while IFS= read -r -d '' plist; do
|
||||||
sudo launchctl unload "$plist" 2>/dev/null || true
|
sudo launchctl unload "$plist" 2> /dev/null || true
|
||||||
done < <(find /Library/LaunchAgents -maxdepth 1 -name "${bundle_id}*.plist" -print0 2>/dev/null)
|
done < <(find /Library/LaunchAgents -maxdepth 1 -name "${bundle_id}*.plist" -print0 2> /dev/null)
|
||||||
fi
|
fi
|
||||||
if [[ -d /Library/LaunchDaemons ]]; then
|
if [[ -d /Library/LaunchDaemons ]]; then
|
||||||
while IFS= read -r -d '' plist; do
|
while IFS= read -r -d '' plist; do
|
||||||
sudo launchctl unload "$plist" 2>/dev/null || true
|
sudo launchctl unload "$plist" 2> /dev/null || true
|
||||||
done < <(find /Library/LaunchDaemons -maxdepth 1 -name "${bundle_id}*.plist" -print0 2>/dev/null)
|
done < <(find /Library/LaunchDaemons -maxdepth 1 -name "${bundle_id}*.plist" -print0 2> /dev/null)
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@@ -115,7 +115,7 @@ remove_login_item() {
|
|||||||
local escaped_name="${clean_name//\\/\\\\}"
|
local escaped_name="${clean_name//\\/\\\\}"
|
||||||
escaped_name="${escaped_name//\"/\\\"}"
|
escaped_name="${escaped_name//\"/\\\"}"
|
||||||
|
|
||||||
osascript <<-EOF >/dev/null 2>&1 || true
|
osascript <<- EOF > /dev/null 2>&1 || true
|
||||||
tell application "System Events"
|
tell application "System Events"
|
||||||
try
|
try
|
||||||
set itemCount to count of login items
|
set itemCount to count of login items
|
||||||
@@ -149,9 +149,9 @@ remove_file_list() {
|
|||||||
|
|
||||||
if [[ -L "$file" ]]; then
|
if [[ -L "$file" ]]; then
|
||||||
if [[ "$use_sudo" == "true" ]]; then
|
if [[ "$use_sudo" == "true" ]]; then
|
||||||
sudo rm "$file" 2>/dev/null && ((++count)) || true
|
sudo rm "$file" 2> /dev/null && ((++count)) || true
|
||||||
else
|
else
|
||||||
rm "$file" 2>/dev/null && ((++count)) || true
|
rm "$file" 2> /dev/null && ((++count)) || true
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if [[ "$use_sudo" == "true" ]]; then
|
if [[ "$use_sudo" == "true" ]]; then
|
||||||
@@ -160,7 +160,7 @@ remove_file_list() {
|
|||||||
safe_remove "$file" true && ((++count)) || true
|
safe_remove "$file" true && ((++count)) || true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done <<<"$file_list"
|
done <<< "$file_list"
|
||||||
|
|
||||||
echo "$count"
|
echo "$count"
|
||||||
}
|
}
|
||||||
@@ -184,15 +184,15 @@ batch_uninstall_applications() {
|
|||||||
if [[ -t 1 ]]; then start_inline_spinner "Scanning files..."; fi
|
if [[ -t 1 ]]; then start_inline_spinner "Scanning files..."; fi
|
||||||
for selected_app in "${selected_apps[@]}"; do
|
for selected_app in "${selected_apps[@]}"; do
|
||||||
[[ -z "$selected_app" ]] && continue
|
[[ -z "$selected_app" ]] && continue
|
||||||
IFS='|' read -r _ app_path app_name bundle_id _ _ <<<"$selected_app"
|
IFS='|' read -r _ app_path app_name bundle_id _ _ <<< "$selected_app"
|
||||||
|
|
||||||
# Check running app by bundle executable if available.
|
# Check running app by bundle executable if available.
|
||||||
local exec_name=""
|
local exec_name=""
|
||||||
if [[ -e "$app_path/Contents/Info.plist" ]]; then
|
if [[ -e "$app_path/Contents/Info.plist" ]]; then
|
||||||
exec_name=$(defaults read "$app_path/Contents/Info.plist" CFBundleExecutable 2>/dev/null || echo "")
|
exec_name=$(defaults read "$app_path/Contents/Info.plist" CFBundleExecutable 2> /dev/null || echo "")
|
||||||
fi
|
fi
|
||||||
local check_pattern="${exec_name:-$app_name}"
|
local check_pattern="${exec_name:-$app_name}"
|
||||||
if pgrep -x "$check_pattern" >/dev/null 2>&1; then
|
if pgrep -x "$check_pattern" > /dev/null 2>&1; then
|
||||||
running_apps+=("$app_name")
|
running_apps+=("$app_name")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -259,7 +259,7 @@ batch_uninstall_applications() {
|
|||||||
# Warn if user data is detected.
|
# Warn if user data is detected.
|
||||||
local has_user_data=false
|
local has_user_data=false
|
||||||
for detail in "${app_details[@]}"; do
|
for detail in "${app_details[@]}"; do
|
||||||
IFS='|' read -r _ _ _ _ _ _ has_sensitive_data <<<"$detail"
|
IFS='|' read -r _ _ _ _ _ _ has_sensitive_data <<< "$detail"
|
||||||
if [[ "$has_sensitive_data" == "true" ]]; then
|
if [[ "$has_sensitive_data" == "true" ]]; then
|
||||||
has_user_data=true
|
has_user_data=true
|
||||||
break
|
break
|
||||||
@@ -272,7 +272,7 @@ batch_uninstall_applications() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
for detail in "${app_details[@]}"; do
|
for detail in "${app_details[@]}"; do
|
||||||
IFS='|' read -r app_name app_path bundle_id total_kb encoded_files encoded_system_files has_sensitive_data needs_sudo_flag is_brew_cask cask_name <<<"$detail"
|
IFS='|' read -r app_name app_path bundle_id total_kb encoded_files encoded_system_files has_sensitive_data needs_sudo_flag is_brew_cask cask_name <<< "$detail"
|
||||||
local app_size_display=$(bytes_to_human "$((total_kb * 1024))")
|
local app_size_display=$(bytes_to_human "$((total_kb * 1024))")
|
||||||
|
|
||||||
local brew_tag=""
|
local brew_tag=""
|
||||||
@@ -295,7 +295,7 @@ batch_uninstall_applications() {
|
|||||||
fi
|
fi
|
||||||
((file_count++))
|
((file_count++))
|
||||||
fi
|
fi
|
||||||
done <<<"$related_files"
|
done <<< "$related_files"
|
||||||
|
|
||||||
# Show system files (limit to 5).
|
# Show system files (limit to 5).
|
||||||
local sys_file_count=0
|
local sys_file_count=0
|
||||||
@@ -306,7 +306,7 @@ batch_uninstall_applications() {
|
|||||||
fi
|
fi
|
||||||
((sys_file_count++))
|
((sys_file_count++))
|
||||||
fi
|
fi
|
||||||
done <<<"$system_files"
|
done <<< "$system_files"
|
||||||
|
|
||||||
local total_hidden=$((file_count > max_files ? file_count - max_files : 0))
|
local total_hidden=$((file_count > max_files ? file_count - max_files : 0))
|
||||||
((total_hidden += sys_file_count > max_files ? sys_file_count - max_files : 0))
|
((total_hidden += sys_file_count > max_files ? sys_file_count - max_files : 0))
|
||||||
@@ -349,7 +349,7 @@ batch_uninstall_applications() {
|
|||||||
|
|
||||||
# Request sudo if needed.
|
# Request sudo if needed.
|
||||||
if [[ ${#sudo_apps[@]} -gt 0 ]]; then
|
if [[ ${#sudo_apps[@]} -gt 0 ]]; then
|
||||||
if ! sudo -n true 2>/dev/null; then
|
if ! sudo -n true 2> /dev/null; then
|
||||||
if ! request_sudo_access "Admin required for system apps: ${sudo_apps[*]}"; then
|
if ! request_sudo_access "Admin required for system apps: ${sudo_apps[*]}"; then
|
||||||
echo ""
|
echo ""
|
||||||
log_error "Admin access denied"
|
log_error "Admin access denied"
|
||||||
@@ -359,12 +359,12 @@ batch_uninstall_applications() {
|
|||||||
# Keep sudo alive during uninstall.
|
# Keep sudo alive during uninstall.
|
||||||
parent_pid=$$
|
parent_pid=$$
|
||||||
(while true; do
|
(while true; do
|
||||||
if ! kill -0 "$parent_pid" 2>/dev/null; then
|
if ! kill -0 "$parent_pid" 2> /dev/null; then
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
sudo -n true
|
sudo -n true
|
||||||
sleep 60
|
sleep 60
|
||||||
done 2>/dev/null) &
|
done 2> /dev/null) &
|
||||||
sudo_keepalive_pid=$!
|
sudo_keepalive_pid=$!
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -376,7 +376,7 @@ batch_uninstall_applications() {
|
|||||||
local current_index=0
|
local current_index=0
|
||||||
for detail in "${app_details[@]}"; do
|
for detail in "${app_details[@]}"; do
|
||||||
((current_index++))
|
((current_index++))
|
||||||
IFS='|' read -r app_name app_path bundle_id total_kb encoded_files encoded_system_files has_sensitive_data needs_sudo is_brew_cask cask_name <<<"$detail"
|
IFS='|' read -r app_name app_path bundle_id total_kb encoded_files encoded_system_files has_sensitive_data needs_sudo is_brew_cask cask_name <<< "$detail"
|
||||||
local related_files=$(decode_file_list "$encoded_files" "$app_name")
|
local related_files=$(decode_file_list "$encoded_files" "$app_name")
|
||||||
local system_files=$(decode_file_list "$encoded_system_files" "$app_name")
|
local system_files=$(decode_file_list "$encoded_system_files" "$app_name")
|
||||||
local reason=""
|
local reason=""
|
||||||
@@ -439,24 +439,24 @@ batch_uninstall_applications() {
|
|||||||
|
|
||||||
# Remove related files if app removal succeeded.
|
# Remove related files if app removal succeeded.
|
||||||
if [[ -z "$reason" ]]; then
|
if [[ -z "$reason" ]]; then
|
||||||
remove_file_list "$related_files" "false" >/dev/null
|
remove_file_list "$related_files" "false" > /dev/null
|
||||||
|
|
||||||
# If brew successfully uninstalled the cask, avoid deleting
|
# If brew successfully uninstalled the cask, avoid deleting
|
||||||
# system-level files Mole discovered. Brew manages its own
|
# system-level files Mole discovered. Brew manages its own
|
||||||
# receipts/symlinks and we don't want to fight it.
|
# receipts/symlinks and we don't want to fight it.
|
||||||
if [[ "$used_brew_successfully" != "true" ]]; then
|
if [[ "$used_brew_successfully" != "true" ]]; then
|
||||||
remove_file_list "$system_files" "true" >/dev/null
|
remove_file_list "$system_files" "true" > /dev/null
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Clean up macOS defaults (preference domains).
|
# Clean up macOS defaults (preference domains).
|
||||||
if [[ -n "$bundle_id" && "$bundle_id" != "unknown" ]]; then
|
if [[ -n "$bundle_id" && "$bundle_id" != "unknown" ]]; then
|
||||||
if defaults read "$bundle_id" &>/dev/null; then
|
if defaults read "$bundle_id" &> /dev/null; then
|
||||||
defaults delete "$bundle_id" 2>/dev/null || true
|
defaults delete "$bundle_id" 2> /dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ByHost preferences (machine-specific).
|
# ByHost preferences (machine-specific).
|
||||||
if [[ -d ~/Library/Preferences/ByHost ]]; then
|
if [[ -d ~/Library/Preferences/ByHost ]]; then
|
||||||
find ~/Library/Preferences/ByHost -maxdepth 1 -name "${bundle_id}.*.plist" -delete 2>/dev/null || true
|
find ~/Library/Preferences/ByHost -maxdepth 1 -name "${bundle_id}.*.plist" -delete 2> /dev/null || true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -586,7 +586,7 @@ batch_uninstall_applications() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
local autoremove_output removed_count
|
local autoremove_output removed_count
|
||||||
autoremove_output=$(HOMEBREW_NO_ENV_HINTS=1 brew autoremove 2>/dev/null) || true
|
autoremove_output=$(HOMEBREW_NO_ENV_HINTS=1 brew autoremove 2> /dev/null) || true
|
||||||
removed_count=$(printf '%s\n' "$autoremove_output" | grep -c "^Uninstalling" || true)
|
removed_count=$(printf '%s\n' "$autoremove_output" | grep -c "^Uninstalling" || true)
|
||||||
removed_count=${removed_count:-0}
|
removed_count=${removed_count:-0}
|
||||||
|
|
||||||
@@ -604,7 +604,7 @@ batch_uninstall_applications() {
|
|||||||
if [[ $success_count -gt 0 ]]; then
|
if [[ $success_count -gt 0 ]]; then
|
||||||
local -a removed_paths=()
|
local -a removed_paths=()
|
||||||
for detail in "${app_details[@]}"; do
|
for detail in "${app_details[@]}"; do
|
||||||
IFS='|' read -r app_name app_path _ _ _ _ <<<"$detail"
|
IFS='|' read -r app_name app_path _ _ _ _ <<< "$detail"
|
||||||
for success_name in "${success_items[@]}"; do
|
for success_name in "${success_items[@]}"; do
|
||||||
if [[ "$success_name" == "$app_name" ]]; then
|
if [[ "$success_name" == "$app_name" ]]; then
|
||||||
removed_paths+=("$app_path")
|
removed_paths+=("$app_path")
|
||||||
@@ -613,21 +613,21 @@ batch_uninstall_applications() {
|
|||||||
done
|
done
|
||||||
done
|
done
|
||||||
if [[ ${#removed_paths[@]} -gt 0 ]]; then
|
if [[ ${#removed_paths[@]} -gt 0 ]]; then
|
||||||
remove_apps_from_dock "${removed_paths[@]}" 2>/dev/null || true
|
remove_apps_from_dock "${removed_paths[@]}" 2> /dev/null || true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Clean up sudo keepalive if it was started.
|
# Clean up sudo keepalive if it was started.
|
||||||
if [[ -n "${sudo_keepalive_pid:-}" ]]; then
|
if [[ -n "${sudo_keepalive_pid:-}" ]]; then
|
||||||
kill "$sudo_keepalive_pid" 2>/dev/null || true
|
kill "$sudo_keepalive_pid" 2> /dev/null || true
|
||||||
wait "$sudo_keepalive_pid" 2>/dev/null || true
|
wait "$sudo_keepalive_pid" 2> /dev/null || true
|
||||||
sudo_keepalive_pid=""
|
sudo_keepalive_pid=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Invalidate cache if any apps were successfully uninstalled.
|
# Invalidate cache if any apps were successfully uninstalled.
|
||||||
if [[ $success_count -gt 0 ]]; then
|
if [[ $success_count -gt 0 ]]; then
|
||||||
local cache_file="$HOME/.cache/mole/app_scan_cache"
|
local cache_file="$HOME/.cache/mole/app_scan_cache"
|
||||||
rm -f "$cache_file" 2>/dev/null || true
|
rm -f "$cache_file" 2> /dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
((total_size_cleaned += total_size_freed))
|
((total_size_cleaned += total_size_freed))
|
||||||
|
|||||||
@@ -18,13 +18,13 @@ resolve_path() {
|
|||||||
[[ -e "$p" ]] || return 1
|
[[ -e "$p" ]] || return 1
|
||||||
|
|
||||||
# macOS 12.3+ and Linux have realpath
|
# macOS 12.3+ and Linux have realpath
|
||||||
if realpath "$p" 2>/dev/null; then
|
if realpath "$p" 2> /dev/null; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Fallback: use cd -P to resolve directory, then append basename
|
# Fallback: use cd -P to resolve directory, then append basename
|
||||||
local dir base
|
local dir base
|
||||||
dir=$(cd -P "$(dirname "$p")" 2>/dev/null && pwd) || return 1
|
dir=$(cd -P "$(dirname "$p")" 2> /dev/null && pwd) || return 1
|
||||||
base=$(basename "$p")
|
base=$(basename "$p")
|
||||||
echo "$dir/$base"
|
echo "$dir/$base"
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ resolve_path() {
|
|||||||
# Check if Homebrew is installed and accessible
|
# Check if Homebrew is installed and accessible
|
||||||
# Returns: 0 if brew is available, 1 otherwise
|
# Returns: 0 if brew is available, 1 otherwise
|
||||||
is_homebrew_available() {
|
is_homebrew_available() {
|
||||||
command -v brew >/dev/null 2>&1
|
command -v brew > /dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Extract cask token from a Caskroom path
|
# Extract cask token from a Caskroom path
|
||||||
@@ -87,9 +87,9 @@ _detect_cask_via_caskroom_search() {
|
|||||||
[[ -d "$room" ]] || continue
|
[[ -d "$room" ]] || continue
|
||||||
while IFS= read -r match; do
|
while IFS= read -r match; do
|
||||||
[[ -n "$match" ]] || continue
|
[[ -n "$match" ]] || continue
|
||||||
token=$(_extract_cask_token_from_path "$match" 2>/dev/null) || continue
|
token=$(_extract_cask_token_from_path "$match" 2> /dev/null) || continue
|
||||||
[[ -n "$token" ]] && tokens+=("$token")
|
[[ -n "$token" ]] && tokens+=("$token")
|
||||||
done < <(find "$room" -maxdepth 3 -name "$app_bundle_name" 2>/dev/null)
|
done < <(find "$room" -maxdepth 3 -name "$app_bundle_name" 2> /dev/null)
|
||||||
done
|
done
|
||||||
|
|
||||||
# Need at least one token
|
# Need at least one token
|
||||||
@@ -101,7 +101,7 @@ _detect_cask_via_caskroom_search() {
|
|||||||
|
|
||||||
# Only succeed if exactly one unique token found and it's installed
|
# Only succeed if exactly one unique token found and it's installed
|
||||||
if ((${#uniq[@]} == 1)) && [[ -n "${uniq[0]}" ]]; then
|
if ((${#uniq[@]} == 1)) && [[ -n "${uniq[0]}" ]]; then
|
||||||
HOMEBREW_NO_ENV_HINTS=1 brew list --cask 2>/dev/null | grep -qxF "${uniq[0]}" || return 1
|
HOMEBREW_NO_ENV_HINTS=1 brew list --cask 2> /dev/null | grep -qxF "${uniq[0]}" || return 1
|
||||||
echo "${uniq[0]}"
|
echo "${uniq[0]}"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@@ -115,7 +115,7 @@ _detect_cask_via_symlink_check() {
|
|||||||
[[ -L "$app_path" ]] || return 1
|
[[ -L "$app_path" ]] || return 1
|
||||||
|
|
||||||
local target
|
local target
|
||||||
target=$(readlink "$app_path" 2>/dev/null) || return 1
|
target=$(readlink "$app_path" 2> /dev/null) || return 1
|
||||||
_extract_cask_token_from_path "$target"
|
_extract_cask_token_from_path "$target"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,10 +127,10 @@ _detect_cask_via_brew_list() {
|
|||||||
app_name_lower=$(echo "${app_bundle_name%.app}" | LC_ALL=C tr '[:upper:]' '[:lower:]')
|
app_name_lower=$(echo "${app_bundle_name%.app}" | LC_ALL=C tr '[:upper:]' '[:lower:]')
|
||||||
|
|
||||||
local cask_name
|
local cask_name
|
||||||
cask_name=$(HOMEBREW_NO_ENV_HINTS=1 brew list --cask 2>/dev/null | grep -Fix "$app_name_lower") || return 1
|
cask_name=$(HOMEBREW_NO_ENV_HINTS=1 brew list --cask 2> /dev/null | grep -Fix "$app_name_lower") || return 1
|
||||||
|
|
||||||
# Verify this cask actually owns this app path
|
# Verify this cask actually owns this app path
|
||||||
HOMEBREW_NO_ENV_HINTS=1 brew info --cask "$cask_name" 2>/dev/null | grep -qF "$app_path" || return 1
|
HOMEBREW_NO_ENV_HINTS=1 brew info --cask "$cask_name" 2> /dev/null | grep -qF "$app_path" || return 1
|
||||||
echo "$cask_name"
|
echo "$cask_name"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +175,7 @@ brew_uninstall_cask() {
|
|||||||
|
|
||||||
# Ensure we have sudo access if needed, to prevent brew from hanging on password prompt
|
# Ensure we have sudo access if needed, to prevent brew from hanging on password prompt
|
||||||
if [[ "${NONINTERACTIVE:-}" != "1" && -t 0 && -t 1 ]]; then
|
if [[ "${NONINTERACTIVE:-}" != "1" && -t 0 && -t 1 ]]; then
|
||||||
if ! sudo -n true 2>/dev/null; then
|
if ! sudo -n true 2> /dev/null; then
|
||||||
sudo -v
|
sudo -v
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -194,7 +194,7 @@ brew_uninstall_cask() {
|
|||||||
|
|
||||||
# Verify removal
|
# Verify removal
|
||||||
local cask_gone=true app_gone=true
|
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
|
HOMEBREW_NO_ENV_HINTS=1 brew list --cask 2> /dev/null | grep -qxF "$cask_name" && cask_gone=false
|
||||||
[[ -n "$app_path" && -e "$app_path" ]] && app_gone=false
|
[[ -n "$app_path" && -e "$app_path" ]] && app_gone=false
|
||||||
|
|
||||||
# Success: uninstall worked and both are gone, or already uninstalled
|
# Success: uninstall worked and both are gone, or already uninstalled
|
||||||
|
|||||||
Reference in New Issue
Block a user