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

refactor: standardize epoch time retrieval with get_epoch_seconds and ensure locale-independent string transformations.

This commit is contained in:
Tw93
2026-01-03 18:07:47 +08:00
parent 4efe1411aa
commit 6dfd675417
15 changed files with 79 additions and 41 deletions

View File

@@ -369,7 +369,8 @@ safe_clean() {
fi fi
local idx=0 local idx=0
local last_progress_update=$(date +%s) local last_progress_update
last_progress_update=$(get_epoch_seconds)
for path in "${existing_paths[@]}"; do for path in "${existing_paths[@]}"; do
local size local size
size=$(get_cleanup_path_size_kb "$path") size=$(get_cleanup_path_size_kb "$path")
@@ -384,14 +385,15 @@ safe_clean() {
((idx++)) ((idx++))
if [[ $((idx % 20)) -eq 0 && "$show_spinner" == "true" && -t 1 ]]; then if [[ $((idx % 20)) -eq 0 && "$show_spinner" == "true" && -t 1 ]]; then
update_progress_if_needed "$idx" "${#existing_paths[@]}" last_progress_update 1 || true update_progress_if_needed "$idx" "${#existing_paths[@]}" last_progress_update 1 || true
last_progress_update=$(date +%s) last_progress_update=$(get_epoch_seconds)
fi fi
done done
else else
local -a pids=() local -a pids=()
local idx=0 local idx=0
local completed=0 local completed=0
local last_progress_update=$(date +%s) local last_progress_update
last_progress_update=$(get_epoch_seconds)
local total_paths=${#existing_paths[@]} local total_paths=${#existing_paths[@]}
if [[ ${#existing_paths[@]} -gt 0 ]]; then if [[ ${#existing_paths[@]} -gt 0 ]]; then

View File

@@ -38,8 +38,8 @@ scan_applications() {
ensure_user_dir "$cache_dir" ensure_user_dir "$cache_dir"
if [[ $force_rescan == false && -f "$cache_file" ]]; then if [[ $force_rescan == false && -f "$cache_file" ]]; then
local cache_age=$(($(date +%s) - $(get_file_mtime "$cache_file"))) local cache_age=$(($(get_epoch_seconds) - $(get_file_mtime "$cache_file")))
[[ $cache_age -eq $(date +%s) ]] && cache_age=86401 # Handle mtime read failure [[ $cache_age -eq $(get_epoch_seconds) ]] && cache_age=86401 # Handle mtime read failure
if [[ $cache_age -lt $cache_ttl ]]; then if [[ $cache_age -lt $cache_ttl ]]; then
if [[ -t 2 ]]; then if [[ -t 2 ]]; then
echo -e "${GREEN}Loading from cache...${NC}" >&2 echo -e "${GREEN}Loading from cache...${NC}" >&2
@@ -60,7 +60,7 @@ scan_applications() {
temp_file=$(create_temp_file) temp_file=$(create_temp_file)
local current_epoch local current_epoch
current_epoch=$(date "+%s") current_epoch=$(get_epoch_seconds)
# Pass 1: collect app paths and bundle IDs (no mdls). # Pass 1: collect app paths and bundle IDs (no mdls).
local -a app_data_tuples=() local -a app_data_tuples=()
@@ -377,8 +377,8 @@ main() {
local needs_scanning=true local needs_scanning=true
local cache_file="$HOME/.cache/mole/app_scan_cache" local cache_file="$HOME/.cache/mole/app_scan_cache"
if [[ $force_rescan == false && -f "$cache_file" ]]; then if [[ $force_rescan == false && -f "$cache_file" ]]; then
local cache_age=$(($(date +%s) - $(get_file_mtime "$cache_file"))) local cache_age=$(($(get_epoch_seconds) - $(get_file_mtime "$cache_file")))
[[ $cache_age -eq $(date +%s) ]] && cache_age=86401 [[ $cache_age -eq $(get_epoch_seconds) ]] && cache_age=86401
[[ $cache_age -lt 86400 ]] && needs_scanning=false [[ $cache_age -lt 86400 ]] && needs_scanning=false
fi fi

View File

@@ -79,8 +79,8 @@ scan_applications() {
# Check if cache exists and is fresh # Check if cache exists and is fresh
if [[ $force_rescan == false && -f "$cache_file" ]]; then if [[ $force_rescan == false && -f "$cache_file" ]]; then
local cache_age=$(($(date +%s) - $(get_file_mtime "$cache_file"))) local cache_age=$(($(get_epoch_seconds) - $(get_file_mtime "$cache_file")))
[[ $cache_age -eq $(date +%s) ]] && cache_age=86401 # Handle missing file [[ $cache_age -eq $(get_epoch_seconds) ]] && cache_age=86401 # Handle missing file
if [[ $cache_age -lt $cache_ttl ]]; then if [[ $cache_age -lt $cache_ttl ]]; then
# Cache hit - return immediately # Cache hit - return immediately
# Show brief flash of cache usage if in interactive mode # Show brief flash of cache usage if in interactive mode
@@ -107,7 +107,7 @@ scan_applications() {
# Pre-cache current epoch to avoid repeated calls # Pre-cache current epoch to avoid repeated calls
local current_epoch local current_epoch
current_epoch=$(date "+%s") current_epoch=$(get_epoch_seconds)
# First pass: quickly collect all valid app paths and bundle IDs (NO mdls calls) # First pass: quickly collect all valid app paths and bundle IDs (NO mdls calls)
local -a app_data_tuples=() local -a app_data_tuples=()
@@ -454,8 +454,8 @@ main() {
local needs_scanning=true local needs_scanning=true
local cache_file="$HOME/.cache/mole/app_scan_cache" local cache_file="$HOME/.cache/mole/app_scan_cache"
if [[ $force_rescan == false && -f "$cache_file" ]]; then if [[ $force_rescan == false && -f "$cache_file" ]]; then
local cache_age=$(($(date +%s) - $(get_file_mtime "$cache_file"))) local cache_age=$(($(get_epoch_seconds) - $(get_file_mtime "$cache_file")))
[[ $cache_age -eq $(date +%s) ]] && cache_age=86401 # Handle missing file [[ $cache_age -eq $(get_epoch_seconds) ]] && cache_age=86401 # Handle missing file
[[ $cache_age -lt 86400 ]] && needs_scanning=false [[ $cache_age -lt 86400 ]] && needs_scanning=false
fi fi

View File

@@ -200,7 +200,7 @@ is_cache_valid() {
return 1 return 1
fi fi
local cache_age=$(($(date +%s) - $(get_file_mtime "$cache_file"))) local cache_age=$(($(get_epoch_seconds) - $(get_file_mtime "$cache_file")))
[[ $cache_age -lt $ttl ]] [[ $cache_age -lt $ttl ]]
} }

View File

@@ -73,7 +73,8 @@ get_uptime_days() {
boot_time=$(echo "$boot_output" | awk -F 'sec = |, usec' '{print $2}' 2> /dev/null || echo "") boot_time=$(echo "$boot_output" | awk -F 'sec = |, usec' '{print $2}' 2> /dev/null || echo "")
if [[ -n "$boot_time" && "$boot_time" =~ ^[0-9]+$ ]]; then if [[ -n "$boot_time" && "$boot_time" =~ ^[0-9]+$ ]]; then
local now=$(date +%s 2> /dev/null || echo "0") local now
now=$(get_epoch_seconds)
local uptime_sec=$((now - boot_time)) local uptime_sec=$((now - boot_time))
uptime_days=$(LC_ALL=C awk "BEGIN {printf \"%.1f\", $uptime_sec / 86400}" 2> /dev/null || echo "0") uptime_days=$(LC_ALL=C awk "BEGIN {printf \"%.1f\", $uptime_sec / 86400}" 2> /dev/null || echo "0")
else else

View File

@@ -66,7 +66,8 @@ scan_installed_apps() {
local cache_age_seconds=300 # 5 minutes local cache_age_seconds=300 # 5 minutes
if [[ -f "$cache_file" ]]; then if [[ -f "$cache_file" ]]; then
local cache_mtime=$(get_file_mtime "$cache_file") local cache_mtime=$(get_file_mtime "$cache_file")
local current_time=$(date +%s) local current_time
current_time=$(get_epoch_seconds)
local age=$((current_time - cache_mtime)) local age=$((current_time - cache_mtime))
if [[ $age -lt $cache_age_seconds ]]; then if [[ $age -lt $cache_age_seconds ]]; then
debug_log "Using cached app list (age: ${age}s)" debug_log "Using cached app list (age: ${age}s)"
@@ -158,7 +159,8 @@ is_bundle_orphaned() {
esac esac
if [[ -e "$directory_path" ]]; then if [[ -e "$directory_path" ]]; then
local last_modified_epoch=$(get_file_mtime "$directory_path") local last_modified_epoch=$(get_file_mtime "$directory_path")
local current_epoch=$(date +%s) local current_epoch
current_epoch=$(get_epoch_seconds)
local days_since_modified=$(((current_epoch - last_modified_epoch) / 86400)) local days_since_modified=$(((current_epoch - last_modified_epoch) / 86400))
if [[ $days_since_modified -lt ${ORPHAN_AGE_THRESHOLD:-60} ]]; then if [[ $days_since_modified -lt ${ORPHAN_AGE_THRESHOLD:-60} ]]; then
return 1 return 1

View File

@@ -16,7 +16,7 @@ clean_homebrew() {
local last_cleanup local last_cleanup
last_cleanup=$(cat "$brew_cache_file" 2> /dev/null || echo "0") last_cleanup=$(cat "$brew_cache_file" 2> /dev/null || echo "0")
local current_time local current_time
current_time=$(date +%s) current_time=$(get_epoch_seconds)
local time_diff=$((current_time - last_cleanup)) local time_diff=$((current_time - last_cleanup))
local days_diff=$((time_diff / 86400)) local days_diff=$((time_diff / 86400))
if [[ $days_diff -lt $cache_valid_days ]]; then if [[ $days_diff -lt $cache_valid_days ]]; then
@@ -112,6 +112,6 @@ clean_homebrew() {
# Update cache timestamp when any work succeeded or was intentionally skipped. # Update cache timestamp when any work succeeded or was intentionally skipped.
if [[ "$skip_cleanup" == "true" ]] || [[ "$brew_success" == "true" ]] || [[ "$autoremove_success" == "true" ]]; then if [[ "$skip_cleanup" == "true" ]] || [[ "$brew_success" == "true" ]] || [[ "$autoremove_success" == "true" ]]; then
ensure_user_file "$brew_cache_file" ensure_user_file "$brew_cache_file"
date +%s > "$brew_cache_file" get_epoch_seconds > "$brew_cache_file"
fi fi
} }

View File

@@ -214,7 +214,7 @@ is_safe_project_artifact() {
fi fi
# Must not be a direct child of the search root. # Must not be a direct child of the search root.
local relative_path="${path#"$search_path"/}" local relative_path="${path#"$search_path"/}"
local depth=$(echo "$relative_path" | tr -cd '/' | wc -c) local depth=$(echo "$relative_path" | LC_ALL=C tr -cd '/' | wc -c)
if [[ $depth -lt 1 ]]; then if [[ $depth -lt 1 ]]; then
return 1 return 1
fi fi
@@ -398,7 +398,8 @@ is_recently_modified() {
fi fi
local mod_time local mod_time
mod_time=$(get_file_mtime "$path") mod_time=$(get_file_mtime "$path")
local current_time=$(date +%s) local current_time
current_time=$(get_epoch_seconds)
local age_seconds=$((current_time - mod_time)) local age_seconds=$((current_time - mod_time))
local age_in_days=$((age_seconds / 86400)) local age_in_days=$((age_seconds / 86400))
if [[ $age_in_days -lt $age_days ]]; then if [[ $age_in_days -lt $age_days ]]; then

View File

@@ -40,7 +40,7 @@ clean_deep_system() {
fi fi
if [[ -d "/macOS Install Data" ]]; then if [[ -d "/macOS Install Data" ]]; then
local mtime=$(get_file_mtime "/macOS Install Data") local mtime=$(get_file_mtime "/macOS Install Data")
local age_days=$((($(date +%s) - mtime) / 86400)) local age_days=$((($(get_epoch_seconds) - mtime) / 86400))
debug_log "Found macOS Install Data (age: ${age_days} days)" debug_log "Found macOS Install Data (age: ${age_days} days)"
if [[ $age_days -ge 30 ]]; then if [[ $age_days -ge 30 ]]; then
local size_kb=$(get_path_size_kb "/macOS Install Data") local size_kb=$(get_path_size_kb "/macOS Install Data")
@@ -58,17 +58,23 @@ clean_deep_system() {
start_section_spinner "Scanning system caches..." start_section_spinner "Scanning system caches..."
local code_sign_cleaned=0 local code_sign_cleaned=0
local found_count=0 local found_count=0
local last_update_time=$(date +%s) local last_update_time
last_update_time=$(get_epoch_seconds)
local update_interval=2 local update_interval=2
while IFS= read -r -d '' cache_dir; do while IFS= read -r -d '' cache_dir; do
if safe_remove "$cache_dir" true; then if safe_remove "$cache_dir" true; then
((code_sign_cleaned++)) ((code_sign_cleaned++))
fi fi
((found_count++)) ((found_count++))
local current_time=$(date +%s)
if [[ $((current_time - last_update_time)) -ge $update_interval ]]; then # Optimize: only check time every 50 files
start_section_spinner "Scanning system caches... ($found_count found)" if ((found_count % 50 == 0)); then
last_update_time=$current_time local current_time
current_time=$(get_epoch_seconds)
if [[ $((current_time - last_update_time)) -ge $update_interval ]]; then
start_section_spinner "Scanning system caches... ($found_count found)"
last_update_time=$current_time
fi
fi fi
done < <(run_with_timeout 5 command find /private/var/folders -type d -name "*.code_sign_clone" -path "*/X/*" -print0 2> /dev/null || true) done < <(run_with_timeout 5 command find /private/var/folders -type d -name "*.code_sign_clone" -path "*/X/*" -print0 2> /dev/null || true)
stop_section_spinner stop_section_spinner
@@ -155,7 +161,8 @@ clean_time_machine_failed_backups() {
[[ -d "$inprogress_file" ]] || continue [[ -d "$inprogress_file" ]] || continue
# Only delete old incomplete backups (safety window). # Only delete old incomplete backups (safety window).
local file_mtime=$(get_file_mtime "$inprogress_file") local file_mtime=$(get_file_mtime "$inprogress_file")
local current_time=$(date +%s) local current_time
current_time=$(get_epoch_seconds)
local hours_old=$(((current_time - file_mtime) / 3600)) local hours_old=$(((current_time - file_mtime) / 3600))
if [[ $hours_old -lt $MOLE_TM_BACKUP_SAFE_HOURS ]]; then if [[ $hours_old -lt $MOLE_TM_BACKUP_SAFE_HOURS ]]; then
continue continue
@@ -200,7 +207,8 @@ clean_time_machine_failed_backups() {
while IFS= read -r inprogress_file; do while IFS= read -r inprogress_file; do
[[ -d "$inprogress_file" ]] || continue [[ -d "$inprogress_file" ]] || continue
local file_mtime=$(get_file_mtime "$inprogress_file") local file_mtime=$(get_file_mtime "$inprogress_file")
local current_time=$(date +%s) local current_time
current_time=$(get_epoch_seconds)
local hours_old=$(((current_time - file_mtime) / 3600)) local hours_old=$(((current_time - file_mtime) / 3600))
if [[ $hours_old -lt $MOLE_TM_BACKUP_SAFE_HOURS ]]; then if [[ $hours_old -lt $MOLE_TM_BACKUP_SAFE_HOURS ]]; then
continue continue

View File

@@ -485,7 +485,7 @@ process_container_cache() {
if is_critical_system_component "$bundle_id"; then if is_critical_system_component "$bundle_id"; then
return 0 return 0
fi fi
if should_protect_data "$bundle_id" || should_protect_data "$(echo "$bundle_id" | tr '[:upper:]' '[:lower:]')"; then if should_protect_data "$bundle_id" || should_protect_data "$(echo "$bundle_id" | LC_ALL=C tr '[:upper:]' '[:lower:]')"; then
return 0 return 0
fi fi
local cache_dir="$container_dir/Data/Library/Caches" local cache_dir="$container_dir/Data/Library/Caches"
@@ -583,7 +583,7 @@ clean_application_support_logs() {
for app_dir in ~/Library/Application\ Support/*; do for app_dir in ~/Library/Application\ Support/*; do
[[ -d "$app_dir" ]] || continue [[ -d "$app_dir" ]] || continue
local app_name=$(basename "$app_dir") local app_name=$(basename "$app_dir")
local app_name_lower=$(echo "$app_name" | tr '[:upper:]' '[:lower:]') local app_name_lower=$(echo "$app_name" | LC_ALL=C tr '[:upper:]' '[:lower:]')
local is_protected=false local is_protected=false
if should_protect_data "$app_name"; then if should_protect_data "$app_name"; then
is_protected=true is_protected=true

View File

@@ -425,7 +425,7 @@ is_critical_system_component() {
[[ -z "$token" ]] && return 1 [[ -z "$token" ]] && return 1
local lower local lower
lower=$(echo "$token" | tr '[:upper:]' '[:lower:]') lower=$(echo "$token" | LC_ALL=C tr '[:upper:]' '[:lower:]')
case "$lower" in case "$lower" in
*backgroundtaskmanagement* | *loginitems* | *systempreferences* | *systemsettings* | *settings* | *preferences* | *controlcenter* | *biometrickit* | *sfl* | *tcc*) *backgroundtaskmanagement* | *loginitems* | *systempreferences* | *systemsettings* | *settings* | *preferences* | *controlcenter* | *biometrickit* | *sfl* | *tcc*)
@@ -489,7 +489,7 @@ should_protect_path() {
[[ -z "$path" ]] && return 1 [[ -z "$path" ]] && return 1
local path_lower local path_lower
path_lower=$(echo "$path" | tr '[:upper:]' '[:lower:]') path_lower=$(echo "$path" | LC_ALL=C tr '[:upper:]' '[:lower:]')
# 1. Keyword-based matching for system components # 1. Keyword-based matching for system components
# Protect System Settings, Preferences, Control Center, and related XPC services # Protect System Settings, Preferences, Control Center, and related XPC services

View File

@@ -108,8 +108,30 @@ get_file_mtime() {
return return
} }
local result local result
result=$($STAT_BSD -f%m "$file" 2> /dev/null) result=$($STAT_BSD -f%m "$file" 2> /dev/null || echo "")
echo "${result:-0}" if [[ "$result" =~ ^[0-9]+$ ]]; then
echo "$result"
else
echo "0"
fi
}
# Determine date command once
if [[ -x /bin/date ]]; then
_DATE_CMD="/bin/date"
else
_DATE_CMD="date"
fi
# Get current time in epoch seconds (defensive against locale/aliases)
get_epoch_seconds() {
local result
result=$($_DATE_CMD +%s 2> /dev/null || echo "")
if [[ "$result" =~ ^[0-9]+$ ]]; then
echo "$result"
else
echo "0"
fi
} }
# Get file owner username # Get file owner username
@@ -635,11 +657,13 @@ update_progress_if_needed() {
local interval="${4:-2}" # Default: update every 2 seconds local interval="${4:-2}" # Default: update every 2 seconds
# Get current time # Get current time
local current_time=$(date +%s) local current_time
current_time=$(get_epoch_seconds)
# Get last update time from variable # Get last update time from variable
local last_time local last_time
eval "last_time=\${$last_update_var:-0}" eval "last_time=\${$last_update_var:-0}"
[[ "$last_time" =~ ^[0-9]+$ ]] || last_time=0
# Check if enough time has elapsed # Check if enough time has elapsed
if [[ $((current_time - last_time)) -ge $interval ]]; then if [[ $((current_time - last_time)) -ge $interval ]]; then

View File

@@ -590,9 +590,9 @@ opt_spotlight_index_optimize() {
local slow_count=0 local slow_count=0
local test_start test_end test_duration local test_start test_end test_duration
for _ in 1 2; do for _ in 1 2; do
test_start=$(date +%s) test_start=$(get_epoch_seconds)
mdfind "kMDItemFSName == 'Applications'" > /dev/null 2>&1 || true mdfind "kMDItemFSName == 'Applications'" > /dev/null 2>&1 || true
test_end=$(date +%s) test_end=$(get_epoch_seconds)
test_duration=$((test_end - test_start)) test_duration=$((test_end - test_start))
if [[ $test_duration -gt 3 ]]; then if [[ $test_duration -gt 3 ]]; then
((slow_count++)) ((slow_count++))

4
mole
View File

@@ -179,7 +179,7 @@ show_version() {
local sip_status local sip_status
if command -v csrutil > /dev/null; then if command -v csrutil > /dev/null; then
sip_status=$(csrutil status 2> /dev/null | grep -o "enabled\|disabled" || echo "Unknown") sip_status=$(csrutil status 2> /dev/null | grep -o "enabled\|disabled" || echo "Unknown")
sip_status="$(tr '[:lower:]' '[:upper:]' <<< "${sip_status:0:1}")${sip_status:1}" sip_status="$(LC_ALL=C tr '[:lower:]' '[:upper:]' <<< "${sip_status:0:1}")${sip_status:1}"
else else
sip_status="Unknown" sip_status="Unknown"
fi fi
@@ -613,7 +613,7 @@ interactive_main_menu() {
local flag_file local flag_file
local cache_dir="$HOME/.cache/mole" local cache_dir="$HOME/.cache/mole"
ensure_user_dir "$cache_dir" ensure_user_dir "$cache_dir"
flag_file="$cache_dir/intro_$(echo "$tty_name" | tr -c '[:alnum:]_' '_')" flag_file="$cache_dir/intro_$(echo "$tty_name" | LC_ALL=C tr -c '[:alnum:]_' '_')"
if [[ ! -f "$flag_file" ]]; then if [[ ! -f "$flag_file" ]]; then
animate_mole_intro animate_mole_intro
ensure_user_file "$flag_file" ensure_user_file "$flag_file"

View File

@@ -302,7 +302,7 @@ create_alfred_workflow() {
for entry in "${workflows[@]}"; do for entry in "${workflows[@]}"; do
IFS="|" read -r bundle name keyword subtitle command <<< "$entry" IFS="|" read -r bundle name keyword subtitle command <<< "$entry"
local workflow_uid="user.workflow.$(uuid | tr '[:upper:]' '[:lower:]')" local workflow_uid="user.workflow.$(uuid | LC_ALL=C tr '[:upper:]' '[:lower:]')"
local input_uid local input_uid
local action_uid local action_uid
input_uid="$(uuid)" input_uid="$(uuid)"