mirror of
https://github.com/tw93/Mole.git
synced 2026-02-10 05:34:17 +00:00
Merge branch 'main' into dev
This commit is contained in:
@@ -422,8 +422,11 @@ get_macos_update_labels() {
|
||||
# ============================================================================
|
||||
|
||||
check_disk_space() {
|
||||
local free_gb=$(command df -H / | awk 'NR==2 {print $4}' | sed 's/G//')
|
||||
local free_num=$(echo "$free_gb" | tr -d 'G' | cut -d'.' -f1)
|
||||
# Use df -k to get KB values (always numeric), then calculate GB via math
|
||||
# This avoids unit suffix parsing issues (df -H can return MB or GB)
|
||||
local free_kb=$(command df -k / | awk 'NR==2 {print $4}')
|
||||
local free_gb=$(awk "BEGIN {printf \"%.1f\", $free_kb / 1048576}")
|
||||
local free_num=$(awk "BEGIN {printf \"%d\", $free_kb / 1048576}")
|
||||
|
||||
export DISK_FREE_GB=$free_num
|
||||
|
||||
|
||||
@@ -114,6 +114,11 @@ clean_media_players() {
|
||||
fi
|
||||
safe_clean ~/Library/Caches/com.apple.Music "Apple Music cache"
|
||||
safe_clean ~/Library/Caches/com.apple.podcasts "Apple Podcasts cache"
|
||||
# Apple Podcasts sandbox container: zombie sparse files and stale artwork cache (#387)
|
||||
safe_clean ~/Library/Containers/com.apple.podcasts/Data/tmp/StreamedMedia "Podcasts streamed media"
|
||||
safe_clean ~/Library/Containers/com.apple.podcasts/Data/tmp/*.heic "Podcasts artwork cache"
|
||||
safe_clean ~/Library/Containers/com.apple.podcasts/Data/tmp/*.img "Podcasts image cache"
|
||||
safe_clean ~/Library/Containers/com.apple.podcasts/Data/tmp/*CFNetworkDownload*.tmp "Podcasts download temp"
|
||||
safe_clean ~/Library/Caches/com.apple.TV/* "Apple TV cache"
|
||||
safe_clean ~/Library/Caches/tv.plex.player.desktop "Plex cache"
|
||||
safe_clean ~/Library/Caches/com.netease.163music "NetEase Music cache"
|
||||
|
||||
@@ -413,7 +413,7 @@ clean_orphaned_system_services() {
|
||||
fi
|
||||
orphaned_files+=("$plist")
|
||||
local size_kb
|
||||
size_kb=$(sudo du -sk "$plist" 2> /dev/null | awk '{print $1}' || echo "0")
|
||||
size_kb=$(sudo du -skP "$plist" 2> /dev/null | awk '{print $1}' || echo "0")
|
||||
((total_orphaned_kb += size_kb))
|
||||
((orphaned_count++))
|
||||
break
|
||||
@@ -444,7 +444,7 @@ clean_orphaned_system_services() {
|
||||
fi
|
||||
orphaned_files+=("$plist")
|
||||
local size_kb
|
||||
size_kb=$(sudo du -sk "$plist" 2> /dev/null | awk '{print $1}' || echo "0")
|
||||
size_kb=$(sudo du -skP "$plist" 2> /dev/null | awk '{print $1}' || echo "0")
|
||||
((total_orphaned_kb += size_kb))
|
||||
((orphaned_count++))
|
||||
break
|
||||
@@ -474,7 +474,7 @@ clean_orphaned_system_services() {
|
||||
fi
|
||||
orphaned_files+=("$helper")
|
||||
local size_kb
|
||||
size_kb=$(sudo du -sk "$helper" 2> /dev/null | awk '{print $1}' || echo "0")
|
||||
size_kb=$(sudo du -skP "$helper" 2> /dev/null | awk '{print $1}' || echo "0")
|
||||
((total_orphaned_kb += size_kb))
|
||||
((orphaned_count++))
|
||||
break
|
||||
|
||||
@@ -29,7 +29,7 @@ clean_homebrew() {
|
||||
local skip_cleanup=false
|
||||
local brew_cache_size=0
|
||||
if [[ -d ~/Library/Caches/Homebrew ]]; then
|
||||
brew_cache_size=$(run_with_timeout 3 du -sk ~/Library/Caches/Homebrew 2> /dev/null | awk '{print $1}')
|
||||
brew_cache_size=$(run_with_timeout 3 du -skP ~/Library/Caches/Homebrew 2> /dev/null | awk '{print $1}')
|
||||
local du_exit=$?
|
||||
if [[ $du_exit -eq 0 && -n "$brew_cache_size" && "$brew_cache_size" -lt 51200 ]]; then
|
||||
skip_cleanup=true
|
||||
|
||||
@@ -97,7 +97,7 @@ check_multiple_versions() {
|
||||
if [[ -n "$list_cmd" ]]; then
|
||||
hint=" · ${GRAY}${list_cmd}${NC}"
|
||||
fi
|
||||
echo -e " ${GRAY}${ICON_WARNING}${NC} ${tool_name}: ${count} found${hint}"
|
||||
echo -e " ${GREEN}${ICON_SUCCESS}${NC} ${tool_name}: ${count} found${hint}"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -489,7 +489,7 @@ is_recently_modified() {
|
||||
get_dir_size_kb() {
|
||||
local path="$1"
|
||||
if [[ -d "$path" ]]; then
|
||||
du -sk "$path" 2> /dev/null | awk '{print $1}' || echo "0"
|
||||
du -skP "$path" 2> /dev/null | awk '{print $1}' || echo "0"
|
||||
else
|
||||
echo "0"
|
||||
fi
|
||||
|
||||
@@ -14,7 +14,7 @@ clean_user_essentials() {
|
||||
[[ "$trash_count" =~ ^[0-9]+$ ]] || trash_count="0"
|
||||
|
||||
if [[ "$DRY_RUN" == "true" ]]; then
|
||||
[[ $trash_count -gt 0 ]] && echo -e " ${YELLOW}${ICON_DRY_RUN}${NC} Trash · would empty, $trash_count items" || echo -e " ${GRAY}${ICON_EMPTY}${NC} Trash · already empty"
|
||||
[[ $trash_count -gt 0 ]] && echo -e " ${YELLOW}${ICON_DRY_RUN}${NC} Trash · would empty, $trash_count items" || echo -e " ${GREEN}${ICON_SUCCESS}${NC} Trash · already empty"
|
||||
elif [[ $trash_count -gt 0 ]]; then
|
||||
if osascript -e 'tell application "Finder" to empty trash' > /dev/null 2>&1; then
|
||||
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Trash · emptied, $trash_count items"
|
||||
@@ -25,7 +25,7 @@ clean_user_essentials() {
|
||||
done < <(command find "$HOME/.Trash" -mindepth 1 -maxdepth 1 -print0 2> /dev/null || true)
|
||||
fi
|
||||
else
|
||||
echo -e " ${GRAY}${ICON_EMPTY}${NC} Trash · already empty"
|
||||
echo -e " ${GREEN}${ICON_SUCCESS}${NC} Trash · already empty"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -628,7 +628,7 @@ check_ios_device_backups() {
|
||||
if [[ -d "$backup_dir" ]]; then
|
||||
local backup_kb=$(get_path_size_kb "$backup_dir")
|
||||
if [[ -n "${backup_kb:-}" && "$backup_kb" -gt 102400 ]]; then
|
||||
local backup_human=$(command du -sh "$backup_dir" 2> /dev/null | awk '{print $1}')
|
||||
local backup_human=$(command du -shP "$backup_dir" 2> /dev/null | awk '{print $1}')
|
||||
if [[ -n "$backup_human" ]]; then
|
||||
note_activity
|
||||
echo -e " ${YELLOW}${ICON_WARNING}${NC} iOS backups: ${GREEN}${backup_human}${NC}${GRAY}, Path: $backup_dir${NC}"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,7 @@ readonly MOLE_BASE_LOADED=1
|
||||
# ============================================================================
|
||||
readonly ESC=$'\033'
|
||||
readonly GREEN="${ESC}[0;32m"
|
||||
readonly BLUE="${ESC}[0;34m"
|
||||
readonly BLUE="${ESC}[1;34m"
|
||||
readonly CYAN="${ESC}[0;36m"
|
||||
readonly YELLOW="${ESC}[0;33m"
|
||||
readonly PURPLE="${ESC}[0;35m"
|
||||
@@ -626,9 +626,12 @@ start_section_spinner() {
|
||||
# Stop spinner and clear the line
|
||||
# Usage: stop_section_spinner
|
||||
stop_section_spinner() {
|
||||
stop_inline_spinner 2> /dev/null || true
|
||||
if [[ -t 1 ]]; then
|
||||
echo -ne "\r\033[K" >&2 || true
|
||||
# Only clear line if spinner was actually running
|
||||
if [[ -n "${INLINE_SPINNER_PID:-}" ]]; then
|
||||
stop_inline_spinner 2> /dev/null || true
|
||||
if [[ -t 1 ]]; then
|
||||
echo -ne "\r\033[2K" >&2 || true
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -646,7 +649,7 @@ safe_clear_lines() {
|
||||
# Clear lines one by one (more reliable than multi-line sequences)
|
||||
local i
|
||||
for ((i = 0; i < lines; i++)); do
|
||||
printf "\033[1A\r\033[K" > "$tty_device" 2> /dev/null || return 1
|
||||
printf "\033[1A\r\033[2K" > "$tty_device" 2> /dev/null || return 1
|
||||
done
|
||||
|
||||
return 0
|
||||
@@ -660,7 +663,7 @@ safe_clear_line() {
|
||||
# Use centralized ANSI support check
|
||||
is_ansi_supported 2> /dev/null || return 1
|
||||
|
||||
printf "\r\033[K" > "$tty_device" 2> /dev/null || return 1
|
||||
printf "\r\033[2K" > "$tty_device" 2> /dev/null || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ safe_sudo_remove() {
|
||||
|
||||
if sudo test -e "$path" 2> /dev/null; then
|
||||
local size_kb
|
||||
size_kb=$(sudo du -sk "$path" 2> /dev/null | awk '{print $1}' || echo "0")
|
||||
size_kb=$(sudo du -skP "$path" 2> /dev/null | awk '{print $1}' || echo "0")
|
||||
if [[ "$size_kb" -gt 0 ]]; then
|
||||
file_size=$(bytes_to_human "$((size_kb * 1024))")
|
||||
fi
|
||||
@@ -297,7 +297,7 @@ safe_sudo_remove() {
|
||||
local size_human=""
|
||||
if oplog_enabled; then
|
||||
if sudo test -e "$path" 2> /dev/null; then
|
||||
size_kb=$(sudo du -sk "$path" 2> /dev/null | awk '{print $1}' || echo "0")
|
||||
size_kb=$(sudo du -skP "$path" 2> /dev/null | awk '{print $1}' || echo "0")
|
||||
if [[ "$size_kb" =~ ^[0-9]+$ ]] && [[ "$size_kb" -gt 0 ]]; then
|
||||
size_human=$(bytes_to_human "$((size_kb * 1024))" 2> /dev/null || echo "${size_kb}KB")
|
||||
fi
|
||||
@@ -418,7 +418,7 @@ get_path_size_kb() {
|
||||
# Use || echo 0 to ensure failure in du (e.g. permission error) doesn't exit script under set -e
|
||||
# Pipefail would normally cause the pipeline to fail if du fails, but || handle catches it.
|
||||
local size
|
||||
size=$(command du -sk "$path" 2> /dev/null | awk 'NR==1 {print $1; exit}' || true)
|
||||
size=$(command du -skP "$path" 2> /dev/null | awk 'NR==1 {print $1; exit}' || true)
|
||||
|
||||
# Ensure size is a valid number (fix for non-numeric du output)
|
||||
if [[ "$size" =~ ^[0-9]+$ ]]; then
|
||||
|
||||
@@ -44,17 +44,25 @@ rotate_log_once() {
|
||||
export MOLE_LOG_ROTATED=1
|
||||
|
||||
local max_size="$LOG_MAX_SIZE_DEFAULT"
|
||||
if [[ -f "$LOG_FILE" ]] && [[ $(get_file_size "$LOG_FILE") -gt "$max_size" ]]; then
|
||||
mv "$LOG_FILE" "${LOG_FILE}.old" 2> /dev/null || true
|
||||
ensure_user_file "$LOG_FILE"
|
||||
if [[ -f "$LOG_FILE" ]]; then
|
||||
local size
|
||||
size=$(get_file_size "$LOG_FILE")
|
||||
if [[ "$size" -gt "$max_size" ]]; then
|
||||
mv "$LOG_FILE" "${LOG_FILE}.old" 2> /dev/null || true
|
||||
ensure_user_file "$LOG_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Rotate operations log (5MB limit)
|
||||
if [[ "${MO_NO_OPLOG:-}" != "1" ]]; then
|
||||
local oplog_max_size="$OPLOG_MAX_SIZE_DEFAULT"
|
||||
if [[ -f "$OPERATIONS_LOG_FILE" ]] && [[ $(get_file_size "$OPERATIONS_LOG_FILE") -gt "$oplog_max_size" ]]; then
|
||||
mv "$OPERATIONS_LOG_FILE" "${OPERATIONS_LOG_FILE}.old" 2> /dev/null || true
|
||||
ensure_user_file "$OPERATIONS_LOG_FILE"
|
||||
if [[ -f "$OPERATIONS_LOG_FILE" ]]; then
|
||||
local size
|
||||
size=$(get_file_size "$OPERATIONS_LOG_FILE")
|
||||
if [[ "$size" -gt "$oplog_max_size" ]]; then
|
||||
mv "$OPERATIONS_LOG_FILE" "${OPERATIONS_LOG_FILE}.old" 2> /dev/null || true
|
||||
ensure_user_file "$OPERATIONS_LOG_FILE"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -63,10 +71,16 @@ rotate_log_once() {
|
||||
# Logging Functions
|
||||
# ============================================================================
|
||||
|
||||
# Get current timestamp (centralized for consistency)
|
||||
get_timestamp() {
|
||||
date '+%Y-%m-%d %H:%M:%S'
|
||||
}
|
||||
|
||||
# Log informational message
|
||||
log_info() {
|
||||
echo -e "${BLUE}$1${NC}"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
local timestamp
|
||||
timestamp=$(get_timestamp)
|
||||
echo "[$timestamp] INFO: $1" >> "$LOG_FILE" 2> /dev/null || true
|
||||
if [[ "${MO_DEBUG:-}" == "1" ]]; then
|
||||
echo "[$timestamp] INFO: $1" >> "$DEBUG_LOG_FILE" 2> /dev/null || true
|
||||
@@ -76,38 +90,43 @@ log_info() {
|
||||
# Log success message
|
||||
log_success() {
|
||||
echo -e " ${GREEN}${ICON_SUCCESS}${NC} $1"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
local timestamp
|
||||
timestamp=$(get_timestamp)
|
||||
echo "[$timestamp] SUCCESS: $1" >> "$LOG_FILE" 2> /dev/null || true
|
||||
if [[ "${MO_DEBUG:-}" == "1" ]]; then
|
||||
echo "[$timestamp] SUCCESS: $1" >> "$DEBUG_LOG_FILE" 2> /dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Log warning message
|
||||
# shellcheck disable=SC2329
|
||||
log_warning() {
|
||||
echo -e "${YELLOW}$1${NC}"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
local timestamp
|
||||
timestamp=$(get_timestamp)
|
||||
echo "[$timestamp] WARNING: $1" >> "$LOG_FILE" 2> /dev/null || true
|
||||
if [[ "${MO_DEBUG:-}" == "1" ]]; then
|
||||
echo "[$timestamp] WARNING: $1" >> "$DEBUG_LOG_FILE" 2> /dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Log error message
|
||||
# shellcheck disable=SC2329
|
||||
log_error() {
|
||||
echo -e "${YELLOW}${ICON_ERROR}${NC} $1" >&2
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
local timestamp
|
||||
timestamp=$(get_timestamp)
|
||||
echo "[$timestamp] ERROR: $1" >> "$LOG_FILE" 2> /dev/null || true
|
||||
if [[ "${MO_DEBUG:-}" == "1" ]]; then
|
||||
echo "[$timestamp] ERROR: $1" >> "$DEBUG_LOG_FILE" 2> /dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Debug logging (active when MO_DEBUG=1)
|
||||
# shellcheck disable=SC2329
|
||||
debug_log() {
|
||||
if [[ "${MO_DEBUG:-}" == "1" ]]; then
|
||||
echo -e "${GRAY}[DEBUG]${NC} $*" >&2
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] DEBUG: $*" >> "$DEBUG_LOG_FILE" 2> /dev/null || true
|
||||
local timestamp
|
||||
timestamp=$(get_timestamp)
|
||||
echo "[$timestamp] DEBUG: $*" >> "$DEBUG_LOG_FILE" 2> /dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -139,7 +158,7 @@ log_operation() {
|
||||
[[ -z "$path" ]] && return 0
|
||||
|
||||
local timestamp
|
||||
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
timestamp=$(get_timestamp)
|
||||
|
||||
local log_line="[$timestamp] [$command] $action $path"
|
||||
[[ -n "$detail" ]] && log_line+=" ($detail)"
|
||||
@@ -154,7 +173,7 @@ log_operation_session_start() {
|
||||
|
||||
local command="${1:-mole}"
|
||||
local timestamp
|
||||
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
timestamp=$(get_timestamp)
|
||||
|
||||
{
|
||||
echo ""
|
||||
@@ -162,8 +181,7 @@ log_operation_session_start() {
|
||||
} >> "$OPERATIONS_LOG_FILE" 2> /dev/null || true
|
||||
}
|
||||
|
||||
# Log session end with summary
|
||||
# Usage: log_operation_session_end <command> <items_count> <total_size>
|
||||
# shellcheck disable=SC2329
|
||||
log_operation_session_end() {
|
||||
oplog_enabled || return 0
|
||||
|
||||
@@ -171,7 +189,7 @@ log_operation_session_end() {
|
||||
local items="${2:-0}"
|
||||
local size="${3:-0}"
|
||||
local timestamp
|
||||
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
timestamp=$(get_timestamp)
|
||||
|
||||
local size_human=""
|
||||
if [[ "$size" =~ ^[0-9]+$ ]] && [[ "$size" -gt 0 ]]; then
|
||||
|
||||
@@ -301,6 +301,9 @@ start_inline_spinner() {
|
||||
[[ -z "$chars" ]] && chars="|/-\\"
|
||||
local i=0
|
||||
|
||||
# Clear line on first output to prevent text remnants from previous messages
|
||||
printf "\r\033[2K" >&2 || true
|
||||
|
||||
# Cooperative exit: check for stop file instead of relying on signals
|
||||
while [[ ! -f "$stop_file" ]]; do
|
||||
local c="${chars:$((i % ${#chars})):1}"
|
||||
|
||||
Reference in New Issue
Block a user