mirror of
https://github.com/tw93/Mole.git
synced 2026-02-04 21:29:42 +00:00
189 lines
4.9 KiB
Bash
Executable File
189 lines
4.9 KiB
Bash
Executable File
#!/bin/bash
|
|
# Mole - Common Functions Library
|
|
# Main entry point that loads all core modules
|
|
|
|
set -euo pipefail
|
|
|
|
# Prevent multiple sourcing
|
|
if [[ -n "${MOLE_COMMON_LOADED:-}" ]]; then
|
|
return 0
|
|
fi
|
|
readonly MOLE_COMMON_LOADED=1
|
|
|
|
_MOLE_CORE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
# Load core modules
|
|
source "$_MOLE_CORE_DIR/base.sh"
|
|
source "$_MOLE_CORE_DIR/log.sh"
|
|
|
|
source "$_MOLE_CORE_DIR/timeout.sh"
|
|
source "$_MOLE_CORE_DIR/file_ops.sh"
|
|
source "$_MOLE_CORE_DIR/ui.sh"
|
|
source "$_MOLE_CORE_DIR/app_protection.sh"
|
|
|
|
# Load sudo management if available
|
|
if [[ -f "$_MOLE_CORE_DIR/sudo.sh" ]]; then
|
|
source "$_MOLE_CORE_DIR/sudo.sh"
|
|
fi
|
|
|
|
# Update via Homebrew
|
|
update_via_homebrew() {
|
|
local current_version="$1"
|
|
local temp_update temp_upgrade
|
|
temp_update=$(mktemp_file "brew_update")
|
|
temp_upgrade=$(mktemp_file "brew_upgrade")
|
|
|
|
# Set up trap for interruption (Ctrl+C) with inline cleanup
|
|
trap 'stop_inline_spinner 2>/dev/null; rm -f "$temp_update" "$temp_upgrade" 2>/dev/null; echo ""; exit 130' INT TERM
|
|
|
|
# Update Homebrew
|
|
if [[ -t 1 ]]; then
|
|
start_inline_spinner "Updating Homebrew..."
|
|
else
|
|
echo "Updating Homebrew..."
|
|
fi
|
|
|
|
brew update > "$temp_update" 2>&1 &
|
|
local update_pid=$!
|
|
wait $update_pid 2> /dev/null || true # Continue even if brew update fails
|
|
|
|
if [[ -t 1 ]]; then
|
|
stop_inline_spinner
|
|
fi
|
|
|
|
# Upgrade Mole
|
|
if [[ -t 1 ]]; then
|
|
start_inline_spinner "Upgrading Mole..."
|
|
else
|
|
echo "Upgrading Mole..."
|
|
fi
|
|
|
|
brew upgrade mole > "$temp_upgrade" 2>&1 &
|
|
local upgrade_pid=$!
|
|
wait $upgrade_pid 2> /dev/null || true # Continue even if brew upgrade fails
|
|
|
|
local upgrade_output
|
|
upgrade_output=$(cat "$temp_upgrade")
|
|
|
|
if [[ -t 1 ]]; then
|
|
stop_inline_spinner
|
|
fi
|
|
|
|
# Clear trap
|
|
trap - INT TERM
|
|
|
|
# Cleanup temp files
|
|
rm -f "$temp_update" "$temp_upgrade"
|
|
|
|
if echo "$upgrade_output" | grep -q "already installed"; then
|
|
local installed_version
|
|
installed_version=$(brew list --versions mole 2> /dev/null | awk '{print $2}')
|
|
echo ""
|
|
echo -e "${GREEN}${ICON_SUCCESS}${NC} Already on latest version (${installed_version:-$current_version})"
|
|
echo ""
|
|
elif echo "$upgrade_output" | grep -q "Error:"; then
|
|
log_error "Homebrew upgrade failed"
|
|
echo "$upgrade_output" | grep "Error:" >&2
|
|
return 1
|
|
else
|
|
echo "$upgrade_output" | grep -Ev "^(==>|Updating Homebrew|Warning:)" || true
|
|
local new_version
|
|
new_version=$(brew list --versions mole 2> /dev/null | awk '{print $2}')
|
|
echo ""
|
|
echo -e "${GREEN}${ICON_SUCCESS}${NC} Updated to latest version (${new_version:-$current_version})"
|
|
echo ""
|
|
fi
|
|
|
|
# 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
|
|
}
|
|
|
|
# Remove applications from Dock
|
|
remove_apps_from_dock() {
|
|
if [[ $# -eq 0 ]]; then
|
|
return 0
|
|
fi
|
|
|
|
local plist="$HOME/Library/Preferences/com.apple.dock.plist"
|
|
[[ -f "$plist" ]] || return 0
|
|
|
|
if ! command -v python3 > /dev/null 2>&1; then
|
|
return 0
|
|
fi
|
|
|
|
# Prune dock entries using Python helper
|
|
python3 - "$@" << 'PY' 2> /dev/null || return 0
|
|
import os
|
|
import plistlib
|
|
import subprocess
|
|
import sys
|
|
import urllib.parse
|
|
|
|
plist_path = os.path.expanduser('~/Library/Preferences/com.apple.dock.plist')
|
|
if not os.path.exists(plist_path):
|
|
sys.exit(0)
|
|
|
|
def normalise(path):
|
|
if not path:
|
|
return ''
|
|
return os.path.normpath(os.path.realpath(path.rstrip('/')))
|
|
|
|
targets = {normalise(arg) for arg in sys.argv[1:] if arg}
|
|
targets = {t for t in targets if t}
|
|
if not targets:
|
|
sys.exit(0)
|
|
|
|
with open(plist_path, 'rb') as fh:
|
|
try:
|
|
data = plistlib.load(fh)
|
|
except Exception:
|
|
sys.exit(0)
|
|
|
|
apps = data.get('persistent-apps')
|
|
if not isinstance(apps, list):
|
|
sys.exit(0)
|
|
|
|
changed = False
|
|
filtered = []
|
|
for item in apps:
|
|
try:
|
|
url = item['tile-data']['file-data']['_CFURLString']
|
|
except (KeyError, TypeError):
|
|
filtered.append(item)
|
|
continue
|
|
|
|
if not isinstance(url, str):
|
|
filtered.append(item)
|
|
continue
|
|
|
|
parsed = urllib.parse.urlparse(url)
|
|
path = urllib.parse.unquote(parsed.path or '')
|
|
if not path:
|
|
filtered.append(item)
|
|
continue
|
|
|
|
candidate = normalise(path)
|
|
if any(candidate == t or candidate.startswith(t + os.sep) for t in targets):
|
|
changed = True
|
|
continue
|
|
|
|
filtered.append(item)
|
|
|
|
if not changed:
|
|
sys.exit(0)
|
|
|
|
data['persistent-apps'] = filtered
|
|
with open(plist_path, 'wb') as fh:
|
|
try:
|
|
plistlib.dump(data, fh, fmt=plistlib.FMT_BINARY)
|
|
except Exception:
|
|
plistlib.dump(data, fh)
|
|
|
|
# Restart Dock to apply changes
|
|
try:
|
|
subprocess.run(['killall', 'Dock'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=False)
|
|
except Exception:
|
|
pass
|
|
PY
|
|
}
|