mirror of
https://github.com/tw93/Mole.git
synced 2026-02-16 16:25:17 +00:00
feat: Add configurable project cleanup depth, refine interactive menu display, and sanitize uninstall app names.
This commit is contained in:
@@ -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"
|
||||||
|
|||||||
@@ -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
2
mole
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user