1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-16 10:36:12 +00:00

feat: Add configurable project cleanup depth, refine interactive menu display, and sanitize uninstall app names.

This commit is contained in:
Tw93
2025-12-22 18:53:48 +08:00
parent bf04f752d2
commit 9a942a2770
3 changed files with 54 additions and 13 deletions

View File

@@ -149,6 +149,17 @@ scan_applications() {
local bundle_name local bundle_name
bundle_name=$(plutil -extract CFBundleName raw "$app_path/Contents/Info.plist" 2> /dev/null) bundle_name=$(plutil -extract CFBundleName raw "$app_path/Contents/Info.plist" 2> /dev/null)
# Sanitize metadata values (prevent paths, pipes, and newlines)
if [[ "$md_display_name" == /* ]]; then md_display_name=""; fi
md_display_name="${md_display_name//|/-}"
md_display_name="${md_display_name//[$'\t\r\n']/}"
bundle_display_name="${bundle_display_name//|/-}"
bundle_display_name="${bundle_display_name//[$'\t\r\n']/}"
bundle_name="${bundle_name//|/-}"
bundle_name="${bundle_name//[$'\t\r\n']/}"
# Select best available name # Select best available name
if [[ -n "$md_display_name" && "$md_display_name" != "(null)" && "$md_display_name" != "$app_name" ]]; then if [[ -n "$md_display_name" && "$md_display_name" != "(null)" && "$md_display_name" != "$app_name" ]]; then
display_name="$md_display_name" display_name="$md_display_name"
@@ -159,6 +170,14 @@ scan_applications() {
fi fi
fi fi
# Final safety check: if display_name looks like a path, revert to app_name
if [[ "$display_name" == /* ]]; then
display_name="$app_name"
fi
# Ensure no pipes or newlines in final display name
display_name="${display_name//|/-}"
display_name="${display_name//[$'\t\r\n']/}"
# Calculate app size (in parallel for performance) # Calculate app size (in parallel for performance)
local app_size="N/A" local app_size="N/A"
local app_size_kb="0" local app_size_kb="0"

View File

@@ -26,6 +26,10 @@ readonly PURGE_TARGETS=(
# Minimum age in days before considering for cleanup # Minimum age in days before considering for cleanup
readonly MIN_AGE_DAYS=7 readonly MIN_AGE_DAYS=7
# Scan depth defaults (relative to search root)
readonly PURGE_MIN_DEPTH_DEFAULT=2
readonly PURGE_MAX_DEPTH_DEFAULT=8
# Search paths (only project directories) # Search paths (only project directories)
readonly PURGE_SEARCH_PATHS=( readonly PURGE_SEARCH_PATHS=(
"$HOME/www" "$HOME/www"
@@ -71,6 +75,18 @@ is_safe_project_artifact() {
scan_purge_targets() { scan_purge_targets() {
local search_path="$1" local search_path="$1"
local output_file="$2" local output_file="$2"
local min_depth="${MOLE_PURGE_MIN_DEPTH:-$PURGE_MIN_DEPTH_DEFAULT}"
local max_depth="${MOLE_PURGE_MAX_DEPTH:-$PURGE_MAX_DEPTH_DEFAULT}"
if [[ ! "$min_depth" =~ ^[0-9]+$ ]]; then
min_depth="$PURGE_MIN_DEPTH_DEFAULT"
fi
if [[ ! "$max_depth" =~ ^[0-9]+$ ]]; then
max_depth="$PURGE_MAX_DEPTH_DEFAULT"
fi
if [[ "$max_depth" -lt "$min_depth" ]]; then
max_depth="$min_depth"
fi
if [[ ! -d "$search_path" ]]; then if [[ ! -d "$search_path" ]]; then
return return
@@ -83,8 +99,8 @@ scan_purge_targets() {
"--hidden" "--hidden"
"--no-ignore" "--no-ignore"
"--type" "d" "--type" "d"
"--min-depth" "2" "--min-depth" "$min_depth"
"--max-depth" "5" "--max-depth" "$max_depth"
"--threads" "4" "--threads" "4"
"--exclude" ".git" "--exclude" ".git"
"--exclude" "Library" "--exclude" "Library"
@@ -152,7 +168,7 @@ scan_purge_targets() {
((i++)) ((i++))
done done
command find "$search_path" -mindepth 2 -maxdepth 5 -type d \ command find "$search_path" -mindepth "$min_depth" -maxdepth "$max_depth" -type d \
\( "${find_expr[@]}" \) 2> /dev/null | while IFS= read -r item; do \( "${find_expr[@]}" \) 2> /dev/null | while IFS= read -r item; do
if is_safe_project_artifact "$item" "$search_path"; then if is_safe_project_artifact "$item" "$search_path"; then
@@ -226,6 +242,7 @@ get_dir_size_kb() {
select_purge_categories() { select_purge_categories() {
local -a categories=("$@") local -a categories=("$@")
local total_items=${#categories[@]} local total_items=${#categories[@]}
local clear_line=$'\r\033[2K'
if [[ $total_items -eq 0 ]]; then if [[ $total_items -eq 0 ]]; then
return 1 return 1
@@ -265,7 +282,7 @@ select_purge_categories() {
} }
draw_menu() { draw_menu() {
printf "\033[H\033[2J" printf "\033[H"
# Calculate total size of selected items for header # Calculate total size of selected items for header
local selected_size=0 local selected_size=0
local selected_count=0 local selected_count=0
@@ -276,11 +293,12 @@ select_purge_categories() {
((selected_count++)) ((selected_count++))
fi fi
done done
local selected_gb=$(echo "scale=1; $selected_size/1024/1024" | bc) local selected_gb
selected_gb=$(echo "scale=1; $selected_size/1024/1024" | bc)
printf '\n' printf "%s\n" "$clear_line"
echo -e "${PURPLE_BOLD}Select Categories to Clean${NC} ${GRAY}- ${selected_gb}GB ($selected_count selected)${NC}" printf "%s${PURPLE_BOLD}Select Categories to Clean${NC} ${GRAY}- ${selected_gb}GB ($selected_count selected)${NC}\n" "$clear_line"
echo "" printf "%s\n" "$clear_line"
IFS=',' read -r -a recent_flags <<< "${PURGE_RECENT_CATEGORIES:-}" IFS=',' read -r -a recent_flags <<< "${PURGE_RECENT_CATEGORIES:-}"
for ((i = 0; i < total_items; i++)); do for ((i = 0; i < total_items; i++)); do
@@ -291,14 +309,14 @@ select_purge_categories() {
[[ ${recent_flags[i]:-false} == "true" ]] && recent_marker=" ${GRAY}| Recent${NC}" [[ ${recent_flags[i]:-false} == "true" ]] && recent_marker=" ${GRAY}| Recent${NC}"
if [[ $i -eq $cursor_pos ]]; then if [[ $i -eq $cursor_pos ]]; then
printf "\r\033[2K${CYAN}${ICON_ARROW} %s %s%s${NC}\n" "$checkbox" "${categories[i]}" "$recent_marker" printf "%s${CYAN}${ICON_ARROW} %s %s%s${NC}\n" "$clear_line" "$checkbox" "${categories[i]}" "$recent_marker"
else else
printf "\r\033[2K %s %s%s\n" "$checkbox" "${categories[i]}" "$recent_marker" printf "%s %s %s%s\n" "$clear_line" "$checkbox" "${categories[i]}" "$recent_marker"
fi fi
done done
echo "" printf "%s\n" "$clear_line"
echo -e "${GRAY}↑↓ | Space Select | Enter Confirm | A All | I Invert | Q Quit${NC}" printf "%s${GRAY}↑↓ | Space Select | Enter Confirm | A All | I Invert | Q Quit${NC}\n" "$clear_line"
} }
trap restore_terminal EXIT trap restore_terminal EXIT
@@ -308,6 +326,10 @@ select_purge_categories() {
stty -echo -icanon intr ^C 2> /dev/null || true stty -echo -icanon intr ^C 2> /dev/null || true
hide_cursor hide_cursor
if [[ -t 1 ]]; then
clear_screen
fi
# Main loop # Main loop
while true; do while true; do
draw_menu draw_menu

2
mole
View File

@@ -22,7 +22,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/lib/core/common.sh" source "$SCRIPT_DIR/lib/core/common.sh"
# Version info # Version info
VERSION="1.14.0" VERSION="1.14.1"
MOLE_TAGLINE="Deep clean and optimize your Mac." MOLE_TAGLINE="Deep clean and optimize your Mac."
# Check TouchID configuration # Check TouchID configuration