mirror of
https://github.com/tw93/Mole.git
synced 2026-02-04 19:09:43 +00:00
293 lines
10 KiB
Bash
Executable File
293 lines
10 KiB
Bash
Executable File
#!/bin/bash
|
||
# Whitelist management functionality
|
||
# Shows actual files that would be deleted by dry-run
|
||
|
||
set -euo pipefail
|
||
|
||
# Get script directory and source dependencies
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
source "$SCRIPT_DIR/common.sh"
|
||
source "$SCRIPT_DIR/paginated_menu.sh"
|
||
|
||
# Config file path
|
||
WHITELIST_CONFIG="$HOME/.config/mole/whitelist"
|
||
|
||
# Default whitelist patterns (preselected on first run)
|
||
declare -a DEFAULT_WHITELIST_PATTERNS=(
|
||
"$HOME/Library/Caches/ms-playwright*"
|
||
"$HOME/.cache/huggingface*"
|
||
"$HOME/.m2/repository/*"
|
||
)
|
||
|
||
# Save whitelist patterns to config
|
||
save_whitelist_patterns() {
|
||
local -a patterns
|
||
patterns=("$@")
|
||
mkdir -p "$(dirname "$WHITELIST_CONFIG")"
|
||
|
||
cat > "$WHITELIST_CONFIG" << 'EOF'
|
||
# Mole Whitelist - Protected paths won't be deleted
|
||
# Default protections: Playwright browsers, HuggingFace models, Maven local repo (can be disabled)
|
||
# Add one pattern per line to keep items safe.
|
||
EOF
|
||
|
||
if [[ ${#patterns[@]} -gt 0 ]]; then
|
||
local -a unique_patterns=()
|
||
for pattern in "${patterns[@]}"; do
|
||
local duplicate="false"
|
||
if [[ ${#unique_patterns[@]} -gt 0 ]]; then
|
||
for existing in "${unique_patterns[@]}"; do
|
||
if patterns_equivalent "$pattern" "$existing"; then
|
||
duplicate="true"
|
||
break
|
||
fi
|
||
done
|
||
fi
|
||
[[ "$duplicate" == "true" ]] && continue
|
||
unique_patterns+=("$pattern")
|
||
done
|
||
|
||
if [[ ${#unique_patterns[@]} -gt 0 ]]; then
|
||
printf '\n' >> "$WHITELIST_CONFIG"
|
||
for pattern in "${unique_patterns[@]}"; do
|
||
echo "$pattern" >> "$WHITELIST_CONFIG"
|
||
done
|
||
fi
|
||
fi
|
||
}
|
||
|
||
# Get all cache items with their patterns
|
||
get_all_cache_items() {
|
||
# Format: "display_name|pattern|category"
|
||
cat << 'EOF'
|
||
Gradle build cache (Android Studio, Gradle projects)|$HOME/.gradle/caches/*|ide_cache
|
||
Gradle daemon processes cache|$HOME/.gradle/daemon/*|ide_cache
|
||
Xcode DerivedData (build outputs, indexes)|$HOME/Library/Developer/Xcode/DerivedData/*|ide_cache
|
||
Xcode internal cache files|$HOME/Library/Caches/com.apple.dt.Xcode/*|ide_cache
|
||
Xcode iOS device support symbols|$HOME/Library/Developer/Xcode/iOS DeviceSupport/*/Symbols/System/Library/Caches/*|ide_cache
|
||
Maven local repository (Java dependencies)|$HOME/.m2/repository/*|ide_cache
|
||
JetBrains IDEs cache (IntelliJ, PyCharm, WebStorm)|$HOME/Library/Caches/JetBrains/*|ide_cache
|
||
Android Studio cache and indexes|$HOME/Library/Caches/Google/AndroidStudio*/*|ide_cache
|
||
VS Code runtime cache|$HOME/Library/Application Support/Code/Cache/*|ide_cache
|
||
VS Code extension and update cache|$HOME/Library/Application Support/Code/CachedData/*|ide_cache
|
||
VS Code system cache (Cursor, VSCodium)|$HOME/Library/Caches/com.microsoft.VSCode/*|ide_cache
|
||
Cursor editor cache|$HOME/Library/Caches/com.todesktop.230313mzl4w4u92/*|ide_cache
|
||
Bazel build cache|$HOME/.cache/bazel/*|compiler_cache
|
||
Go build cache and module cache|$HOME/Library/Caches/go-build/*|compiler_cache
|
||
Rust Cargo registry cache|$HOME/.cargo/registry/cache/*|compiler_cache
|
||
Rustup toolchain downloads|$HOME/.rustup/downloads/*|compiler_cache
|
||
ccache compiler cache|$HOME/.ccache/*|compiler_cache
|
||
sccache distributed compiler cache|$HOME/.cache/sccache/*|compiler_cache
|
||
CocoaPods cache (iOS dependencies)|$HOME/Library/Caches/CocoaPods/*|package_manager
|
||
npm package cache|$HOME/.npm/_cacache/*|package_manager
|
||
pip Python package cache|$HOME/.cache/pip/*|package_manager
|
||
Homebrew downloaded packages|$HOME/Library/Caches/Homebrew/*|package_manager
|
||
Yarn package manager cache|$HOME/.cache/yarn/*|package_manager
|
||
pnpm package store|$HOME/.pnpm-store/*|package_manager
|
||
Composer PHP dependencies cache|$HOME/.composer/cache/*|package_manager
|
||
RubyGems cache|$HOME/.gem/cache/*|package_manager
|
||
Go module cache|$HOME/go/pkg/mod/cache/*|package_manager
|
||
PyTorch model cache|$HOME/.cache/torch/*|ai_ml_cache
|
||
TensorFlow model and dataset cache|$HOME/.cache/tensorflow/*|ai_ml_cache
|
||
HuggingFace models and datasets|$HOME/.cache/huggingface/*|ai_ml_cache
|
||
Playwright browser binaries|$HOME/Library/Caches/ms-playwright*|ai_ml_cache
|
||
Selenium WebDriver binaries|$HOME/.cache/selenium/*|ai_ml_cache
|
||
Ollama local AI models|$HOME/.ollama/models/*|ai_ml_cache
|
||
Safari web browser cache|$HOME/Library/Caches/com.apple.Safari/*|browser_cache
|
||
Chrome browser cache|$HOME/Library/Caches/Google/Chrome/*|browser_cache
|
||
Firefox browser cache|$HOME/Library/Caches/Firefox/*|browser_cache
|
||
Brave browser cache|$HOME/Library/Caches/BraveSoftware/Brave-Browser/*|browser_cache
|
||
Docker Desktop image cache|$HOME/Library/Containers/com.docker.docker/Data/*|container_cache
|
||
Podman container cache|$HOME/.local/share/containers/cache/*|container_cache
|
||
Font cache|$HOME/Library/Caches/com.apple.FontRegistry/*|system_cache
|
||
Spotlight metadata cache|$HOME/Library/Caches/com.apple.spotlight/*|system_cache
|
||
CloudKit cache|$HOME/Library/Caches/CloudKit/*|system_cache
|
||
EOF
|
||
}
|
||
|
||
patterns_equivalent() {
|
||
local first="${1/#~/$HOME}"
|
||
local second="${2/#~/$HOME}"
|
||
|
||
# Only exact string match, no glob expansion
|
||
[[ "$first" == "$second" ]] && return 0
|
||
return 1
|
||
}
|
||
|
||
|
||
load_whitelist() {
|
||
local -a patterns=()
|
||
|
||
if [[ -f "$WHITELIST_CONFIG" ]]; then
|
||
while IFS= read -r line; do
|
||
line="${line#${line%%[![:space:]]*}}"
|
||
line="${line%${line##*[![:space:]]}}"
|
||
[[ -z "$line" || "$line" =~ ^# ]] && continue
|
||
patterns+=("$line")
|
||
done < "$WHITELIST_CONFIG"
|
||
else
|
||
patterns=("${DEFAULT_WHITELIST_PATTERNS[@]}")
|
||
fi
|
||
|
||
if [[ ${#patterns[@]} -gt 0 ]]; then
|
||
local -a unique_patterns=()
|
||
for pattern in "${patterns[@]}"; do
|
||
local duplicate="false"
|
||
if [[ ${#unique_patterns[@]} -gt 0 ]]; then
|
||
for existing in "${unique_patterns[@]}"; do
|
||
if patterns_equivalent "$pattern" "$existing"; then
|
||
duplicate="true"
|
||
break
|
||
fi
|
||
done
|
||
fi
|
||
[[ "$duplicate" == "true" ]] && continue
|
||
unique_patterns+=("$pattern")
|
||
done
|
||
CURRENT_WHITELIST_PATTERNS=("${unique_patterns[@]}")
|
||
else
|
||
CURRENT_WHITELIST_PATTERNS=()
|
||
fi
|
||
}
|
||
|
||
is_whitelisted() {
|
||
local pattern="$1"
|
||
local check_pattern="${pattern/#\~/$HOME}"
|
||
|
||
if [[ ${#CURRENT_WHITELIST_PATTERNS[@]} -eq 0 ]]; then
|
||
return 1
|
||
fi
|
||
|
||
for existing in "${CURRENT_WHITELIST_PATTERNS[@]}"; do
|
||
local existing_expanded="${existing/#\~/$HOME}"
|
||
if [[ "$check_pattern" == "$existing_expanded" ]]; then
|
||
return 0
|
||
fi
|
||
if [[ "$check_pattern" == $existing_expanded ]]; then
|
||
return 0
|
||
fi
|
||
done
|
||
return 1
|
||
}
|
||
|
||
|
||
manage_whitelist() {
|
||
manage_whitelist_categories
|
||
}
|
||
|
||
manage_whitelist_categories() {
|
||
clear
|
||
echo ""
|
||
echo -e "${PURPLE}Whitelist Manager${NC}"
|
||
echo ""
|
||
echo ""
|
||
|
||
# Load currently enabled patterns from both sources
|
||
load_whitelist
|
||
|
||
# Build cache items list
|
||
local -a cache_items=()
|
||
local -a cache_patterns=()
|
||
local -a menu_options=()
|
||
local index=0
|
||
|
||
while IFS='|' read -r display_name pattern category; do
|
||
# Expand $HOME in pattern
|
||
pattern="${pattern/\$HOME/$HOME}"
|
||
|
||
cache_items+=("$display_name")
|
||
cache_patterns+=("$pattern")
|
||
menu_options+=("$display_name")
|
||
|
||
((index++))
|
||
done < <(get_all_cache_items)
|
||
|
||
# Prioritize already-selected items to appear first
|
||
local -a selected_cache_items=()
|
||
local -a selected_cache_patterns=()
|
||
local -a selected_menu_options=()
|
||
local -a remaining_cache_items=()
|
||
local -a remaining_cache_patterns=()
|
||
local -a remaining_menu_options=()
|
||
|
||
for ((i = 0; i < ${#cache_patterns[@]}; i++)); do
|
||
if is_whitelisted "${cache_patterns[i]}"; then
|
||
selected_cache_items+=("${cache_items[i]}")
|
||
selected_cache_patterns+=("${cache_patterns[i]}")
|
||
selected_menu_options+=("${menu_options[i]}")
|
||
else
|
||
remaining_cache_items+=("${cache_items[i]}")
|
||
remaining_cache_patterns+=("${cache_patterns[i]}")
|
||
remaining_menu_options+=("${menu_options[i]}")
|
||
fi
|
||
done
|
||
|
||
cache_items=()
|
||
cache_patterns=()
|
||
menu_options=()
|
||
if [[ ${#selected_cache_items[@]} -gt 0 ]]; then
|
||
cache_items=("${selected_cache_items[@]}")
|
||
cache_patterns=("${selected_cache_patterns[@]}")
|
||
menu_options=("${selected_menu_options[@]}")
|
||
fi
|
||
if [[ ${#remaining_cache_items[@]} -gt 0 ]]; then
|
||
cache_items+=("${remaining_cache_items[@]}")
|
||
cache_patterns+=("${remaining_cache_patterns[@]}")
|
||
menu_options+=("${remaining_menu_options[@]}")
|
||
fi
|
||
|
||
if [[ ${#selected_cache_patterns[@]} -gt 0 ]]; then
|
||
local -a preselected_indices=()
|
||
for ((i = 0; i < ${#selected_cache_patterns[@]}; i++)); do
|
||
preselected_indices+=("$i")
|
||
done
|
||
local IFS=','
|
||
MOLE_PRESELECTED_INDICES="${preselected_indices[*]}"
|
||
else
|
||
unset MOLE_PRESELECTED_INDICES
|
||
fi
|
||
|
||
MOLE_SELECTION_RESULT=""
|
||
paginated_multi_select "Whitelist Manager – Select caches to protect" "${menu_options[@]}"
|
||
unset MOLE_PRESELECTED_INDICES
|
||
local exit_code=$?
|
||
|
||
if [[ $exit_code -ne 0 ]]; then
|
||
echo ""
|
||
echo -e "${YELLOW}Cancelled${NC}"
|
||
return 1
|
||
fi
|
||
|
||
# Convert selected indices to patterns
|
||
local -a selected_patterns=()
|
||
if [[ -n "$MOLE_SELECTION_RESULT" ]]; then
|
||
local -a selected_indices
|
||
IFS=',' read -ra selected_indices <<< "$MOLE_SELECTION_RESULT"
|
||
for idx in "${selected_indices[@]}"; do
|
||
if [[ $idx -ge 0 && $idx -lt ${#cache_patterns[@]} ]]; then
|
||
local pattern="${cache_patterns[$idx]}"
|
||
# Convert back to portable format with ~
|
||
pattern="${pattern/#$HOME/~}"
|
||
selected_patterns+=("$pattern")
|
||
fi
|
||
done
|
||
fi
|
||
|
||
# Save to whitelist config (bash 3.2 + set -u safe)
|
||
if [[ ${#selected_patterns[@]} -gt 0 ]]; then
|
||
save_whitelist_patterns "${selected_patterns[@]}"
|
||
else
|
||
save_whitelist_patterns
|
||
fi
|
||
|
||
print_summary_block "success" \
|
||
"Protected ${#selected_patterns[@]} cache(s)" \
|
||
"Saved to ${WHITELIST_CONFIG}"
|
||
printf '\n'
|
||
}
|
||
|
||
|
||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||
manage_whitelist
|
||
fi
|