mirror of
https://github.com/bitsycore/Allofit.git
synced 2026-10-05 12:27:26 +00:00
Security - Elevated copies: root only reads the original; the copy is written by the user (sudo -u tee), so root never chowns / chmods a user-controlled path. Staging folder forced to 0700. - Service logs moved from fixed /tmp names to /Library/Logs/Allofit (root-owned) and ~/Library/Logs/Allofit; Diagnostics reveals instead of opening the log. - Index files are owner-only (0600; the root daemon's belongs to the installing user), set on the temp file before an atomic rename. - Root install passes the plist inline (base64, plutil -lint) instead of a user-writable temp file; the binary comes from Bundle.main. - Cache loader caps and checks the declared payload size; each save uses its own temp file. - Release action pinned to a commit; non-system LC_RPATHs stripped. Correctness - Move to Trash removes the files from the index (the watcher ignores the app's own operations) and registers Undo (Put Back); trashed folders are matched with the original URLs; failures are shown. - The saved event id stays below pending subtree walks (GUI and service). - Roots / exclusions changes restart the watcher from the snapshot's id. - Case-only renames no longer leave a ghost entry. - Service mode is saved only after a successful install; a saved but missing service falls back to the in-process indexer. Performance - New folders are merged without the O(n) removal pass. - Size / date sorts use a compact key array (539 -> 47 ms for 630k). - Selection, preview and actions use the selected records directly. - Service saves at most every 15 s; reader reloads pause while hidden and are deferred instead of dropped; window close saves only when dirty. Usability - Results appear during the first index; empty-list explanations. - Down arrow moves to the results, Up on the first row back; history on Up / Option-Up / Option-Down. - Search syntax popover and Help menu; shortcuts shown in the context menu; confirmations for Clear Cache and Uninstall; privacy usage strings; Group Containers excluded by default; wording, VoiceOver labels, plural.
206 lines
6.0 KiB
Bash
Executable File
206 lines
6.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Removes every trace of Allofit from the system: launchd services, cache
|
|
# files, user preferences, build artifacts and log files. Useful for a
|
|
# clean reinstall test or to fully uninstall. Can be called from anywhere -
|
|
# paths are resolved relative to the script's own location.
|
|
#
|
|
# Usage:
|
|
# ./scripts/clean.sh # from project root
|
|
# scripts/clean.sh --keep-build # leave .build/ and outputs/ in place
|
|
# ./clean.sh --keep-prefs # from scripts/, keep user prefs
|
|
# ./clean.sh --dry-run # print what would happen, change nothing
|
|
set -uo pipefail
|
|
|
|
# ==================
|
|
# MARK: Constants
|
|
# ==================
|
|
|
|
kBundleId="com.bitsycore.allofit"
|
|
kServiceLabel="${kBundleId}.service"
|
|
kServicePlistName="${kServiceLabel}.plist"
|
|
kUserAgentPlist="$HOME/Library/LaunchAgents/${kServicePlistName}"
|
|
kSystemDaemonPlist="/Library/LaunchDaemons/${kServicePlistName}"
|
|
kUserCacheDir="$HOME/Library/Application Support/Allofit"
|
|
kSystemCacheDir="/Library/Application Support/Allofit"
|
|
kUserPrefsPlist="$HOME/Library/Preferences/${kBundleId}.plist"
|
|
# old /tmp log names (versions up to 1.0.9) and the current log folders
|
|
kServiceLogStdout="/tmp/allofit-service.log"
|
|
kServiceLogStderr="/tmp/allofit-service.err"
|
|
kUserLogDir="$HOME/Library/Logs/Allofit"
|
|
kSystemLogDir="/Library/Logs/Allofit"
|
|
|
|
# ==================
|
|
# MARK: Args
|
|
# ==================
|
|
|
|
# Resolve the project root from the script's own location (scripts/..),
|
|
# so this script works regardless of the caller's CWD.
|
|
vProjectRoot="$(cd "$(dirname "$0")/.." && pwd)"
|
|
vKeepBuild=0
|
|
vKeepPrefs=0
|
|
vDryRun=0
|
|
|
|
for vArg in "$@"; do
|
|
case "$vArg" in
|
|
--keep-build) vKeepBuild=1 ;;
|
|
--keep-prefs) vKeepPrefs=1 ;;
|
|
--dry-run|-n) vDryRun=1 ;;
|
|
-h|--help)
|
|
# print the comment block at the top of this file
|
|
sed -n '2,/^set /p' "$0" | sed -E 's/^#( |$)//;/^set /d'
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown argument: $vArg" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# ==================
|
|
# MARK: Helpers
|
|
# ==================
|
|
|
|
# runs a command, or just prints it under --dry-run
|
|
vRun() {
|
|
if [[ "$vDryRun" -eq 1 ]]; then
|
|
echo " [dry-run] $*"
|
|
else
|
|
"$@"
|
|
fi
|
|
}
|
|
|
|
# caches a sudo session once so later sudo calls don't re-prompt
|
|
vGotSudo=0
|
|
vNeedsSudo() {
|
|
if [[ "$vGotSudo" -eq 0 ]]; then
|
|
if [[ "$vDryRun" -eq 1 ]]; then
|
|
echo " [dry-run] sudo -v"
|
|
else
|
|
echo "==> Acquiring sudo (for /Library cleanup)"
|
|
sudo -v
|
|
fi
|
|
vGotSudo=1
|
|
fi
|
|
}
|
|
|
|
# stops a launchd job by plist path then deletes the plist
|
|
# inDomain inPlist [inSudo]
|
|
vRemoveLaunchd() {
|
|
local inDomain="$1"
|
|
local inPlist="$2"
|
|
local inSudo="${3:-}"
|
|
if [[ ! -f "$inPlist" ]]; then return 0; fi
|
|
if [[ -n "$inSudo" ]]; then vNeedsSudo; fi
|
|
vRun $inSudo launchctl bootout "$inDomain" "$inPlist" >/dev/null 2>&1 || true
|
|
vRun $inSudo launchctl unload -w "$inPlist" >/dev/null 2>&1 || true
|
|
vRun $inSudo rm -f "$inPlist"
|
|
}
|
|
|
|
# ==================
|
|
# MARK: launchd services
|
|
# ==================
|
|
|
|
echo "==> Stopping & removing user LaunchAgent (if present)"
|
|
vRemoveLaunchd "gui/$(id -u)" "$kUserAgentPlist"
|
|
|
|
if [[ -f "$kSystemDaemonPlist" ]]; then
|
|
echo "==> Stopping & removing system LaunchDaemon"
|
|
vRemoveLaunchd "system" "$kSystemDaemonPlist" "sudo"
|
|
fi
|
|
|
|
echo "==> Killing any leftover daemon processes"
|
|
# `pkill -f` matches against the full command line; the daemon binary is
|
|
# now installed as ".../Allofit service" (renamed copy), so the literal
|
|
# "Allofit --service" no longer appears - use a regex that handles both
|
|
# the legacy and the renamed binary by anchoring on "Allofit...--service"
|
|
vRun pkill -f "Allofit.*--service" >/dev/null 2>&1 || true
|
|
|
|
# ==================
|
|
# MARK: Cache files
|
|
# ==================
|
|
|
|
if [[ -d "$kUserCacheDir" ]]; then
|
|
echo "==> Removing user cache directory"
|
|
vRun rm -rf "$kUserCacheDir"
|
|
fi
|
|
|
|
if [[ -d "$kSystemCacheDir" ]]; then
|
|
echo "==> Removing system cache directory"
|
|
vNeedsSudo
|
|
vRun sudo rm -rf "$kSystemCacheDir"
|
|
fi
|
|
|
|
# ==================
|
|
# MARK: Preferences
|
|
# ==================
|
|
|
|
if [[ "$vKeepPrefs" -eq 0 ]]; then
|
|
echo "==> Removing user preferences"
|
|
# defaults handles cfprefsd's cached copy in addition to the on-disk plist
|
|
vRun defaults delete "$kBundleId" >/dev/null 2>&1 || true
|
|
# also clear the SwiftPM "swift run" domain, which may differ from the
|
|
# bundled .app's domain depending on how the binary was launched
|
|
vRun defaults delete "Allofit" >/dev/null 2>&1 || true
|
|
vRun rm -f "$kUserPrefsPlist"
|
|
# wipe ByHost variants if any
|
|
shopt -s nullglob
|
|
for vByHost in "$HOME/Library/Preferences/ByHost/${kBundleId}".*.plist; do
|
|
vRun rm -f "$vByHost"
|
|
done
|
|
shopt -u nullglob
|
|
fi
|
|
|
|
# ==================
|
|
# MARK: Logs
|
|
# ==================
|
|
|
|
if [[ -f "$kServiceLogStdout" || -f "$kServiceLogStderr" ]]; then
|
|
echo "==> Removing service log files"
|
|
# /tmp has the sticky bit, so only the file's owner can rm it. Logs
|
|
# left over from a previous *root* daemon run are owned by root - we
|
|
# need sudo to delete them. Plain rm for user-owned logs (user agent
|
|
# mode), sudo rm for root-owned ones.
|
|
for vLog in "$kServiceLogStdout" "$kServiceLogStderr"; do
|
|
if [[ -f "$vLog" ]]; then
|
|
if [[ -O "$vLog" ]]; then
|
|
vRun rm -f "$vLog"
|
|
else
|
|
vNeedsSudo
|
|
vRun sudo rm -f "$vLog"
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
if [[ -d "$kUserLogDir" ]]; then
|
|
echo "==> Removing user service logs"
|
|
vRun rm -rf "$kUserLogDir"
|
|
fi
|
|
if [[ -d "$kSystemLogDir" ]]; then
|
|
echo "==> Removing system service logs (needs sudo)"
|
|
vNeedsSudo
|
|
vRun sudo rm -rf "$kSystemLogDir"
|
|
fi
|
|
|
|
# ==================
|
|
# MARK: Build artifacts
|
|
# ==================
|
|
|
|
if [[ "$vKeepBuild" -eq 0 ]]; then
|
|
if [[ -d "${vProjectRoot}/.build" ]]; then
|
|
echo "==> Removing SwiftPM .build directory"
|
|
vRun rm -rf "${vProjectRoot}/.build"
|
|
fi
|
|
if [[ -d "${vProjectRoot}/outputs" ]]; then
|
|
echo "==> Removing outputs/ directory (built .app and .dmg)"
|
|
vRun rm -rf "${vProjectRoot}/outputs"
|
|
fi
|
|
fi
|
|
|
|
echo
|
|
echo "Clean complete."
|
|
echo
|
|
echo "Note: any Full Disk Access grant in System Settings → Privacy & Security"
|
|
echo "still points at the previous binary location. Remove it manually if you"
|
|
echo "intend to install Allofit at a different path."
|