1
0
mirror of https://github.com/tw93/Mole.git synced 2026-03-22 20:50:06 +00:00

fix(purge): prevent hangs during size calculation

This commit is contained in:
tw93
2026-02-19 22:52:27 +08:00
parent 9de661b5df
commit 7c974bf351
2 changed files with 77 additions and 7 deletions

View File

@@ -510,8 +510,42 @@ is_recently_modified() {
# Get directory size in KB.
get_dir_size_kb() {
local path="$1"
if [[ -d "$path" ]]; then
du -skP "$path" 2> /dev/null | awk '{print $1}' || echo "0"
if [[ ! -d "$path" ]]; then
echo "0"
return
fi
local timeout_seconds="${MO_PURGE_SIZE_TIMEOUT_SEC:-15}"
if [[ ! "$timeout_seconds" =~ ^[0-9]+([.][0-9]+)?$ ]]; then
timeout_seconds=15
fi
local du_output=""
local du_exit=0
local du_tmp
du_tmp=$(mktemp)
if run_with_timeout "$timeout_seconds" du -skP "$path" > "$du_tmp" 2> /dev/null; then
du_output=$(cat "$du_tmp")
else
du_exit=$?
fi
rm -f "$du_tmp"
if [[ $du_exit -eq 124 ]]; then
debug_log "Size calculation timed out (${timeout_seconds}s): $path"
echo "TIMEOUT"
return
fi
if [[ $du_exit -ne 0 ]]; then
echo "0"
return
fi
local size_kb
size_kb=$(printf '%s\n' "$du_output" | awk 'NR==1 {print $1; exit}')
if [[ "$size_kb" =~ ^[0-9]+$ ]]; then
echo "$size_kb"
else
echo "0"
fi
@@ -855,6 +889,7 @@ clean_project_artifacts() {
local -a menu_options=()
local -a item_paths=()
local -a item_sizes=()
local -a item_size_unknown_flags=()
local -a item_recent_flags=()
# Helper to get project name from path
# For ~/www/pake/src-tauri/target -> returns "pake"
@@ -1054,14 +1089,26 @@ clean_project_artifacts() {
for item in "${safe_to_clean[@]}"; do
local project_path=$(get_project_path "$item")
local artifact_type=$(get_artifact_display_name "$item")
local size_kb=$(get_dir_size_kb "$item")
local size_raw
size_raw=$(get_dir_size_kb "$item")
local size_kb=0
local size_human=""
local size_unknown=false
# Skip empty directories (0 bytes)
if [[ $size_kb -eq 0 ]]; then
if [[ "$size_raw" == "TIMEOUT" ]]; then
size_unknown=true
size_human="unknown"
elif [[ "$size_raw" =~ ^[0-9]+$ ]]; then
size_kb="$size_raw"
# Skip empty directories (0 bytes)
if [[ $size_kb -eq 0 ]]; then
continue
fi
size_human=$(bytes_to_human "$((size_kb * 1024))")
else
continue
fi
local size_human=$(bytes_to_human "$((size_kb * 1024))")
# Check if recent
local is_recent=false
for recent_item in "${recently_modified[@]+"${recently_modified[@]}"}"; do
@@ -1073,6 +1120,7 @@ clean_project_artifacts() {
menu_options+=("$(format_purge_display "$project_path" "$artifact_type" "$size_human")")
item_paths+=("$item")
item_sizes+=("$size_kb")
item_size_unknown_flags+=("$size_unknown")
item_recent_flags+=("$is_recent")
done
@@ -1097,12 +1145,14 @@ clean_project_artifacts() {
local -a sorted_menu_options=()
local -a sorted_item_paths=()
local -a sorted_item_sizes=()
local -a sorted_item_size_unknown_flags=()
local -a sorted_item_recent_flags=()
for idx in "${sorted_indices[@]}"; do
sorted_menu_options+=("${menu_options[idx]}")
sorted_item_paths+=("${item_paths[idx]}")
sorted_item_sizes+=("${item_sizes[idx]}")
sorted_item_size_unknown_flags+=("${item_size_unknown_flags[idx]}")
sorted_item_recent_flags+=("${item_recent_flags[idx]}")
done
@@ -1110,6 +1160,7 @@ clean_project_artifacts() {
menu_options=("${sorted_menu_options[@]}")
item_paths=("${sorted_item_paths[@]}")
item_sizes=("${sorted_item_sizes[@]}")
item_size_unknown_flags=("${sorted_item_size_unknown_flags[@]}")
item_recent_flags=("${sorted_item_recent_flags[@]}")
fi
if [[ -t 1 ]]; then
@@ -1157,7 +1208,13 @@ clean_project_artifacts() {
local artifact_type=$(basename "$item_path")
local project_path=$(get_project_path "$item_path")
local size_kb="${item_sizes[idx]}"
local size_human=$(bytes_to_human "$((size_kb * 1024))")
local size_unknown="${item_size_unknown_flags[idx]:-false}"
local size_human
if [[ "$size_unknown" == "true" ]]; then
size_human="unknown"
else
size_human=$(bytes_to_human "$((size_kb * 1024))")
fi
# Safety checks
if [[ -z "$item_path" || "$item_path" == "/" || "$item_path" == "$HOME" || "$item_path" != "$HOME/"* ]]; then
continue

View File

@@ -492,6 +492,19 @@ EOF
[[ "$result" == "0" ]]
}
@test "get_dir_size_kb: returns TIMEOUT when size calculation hangs" {
mkdir -p "$HOME/www/stuck-project/node_modules"
result=$(bash -c "
source '$PROJECT_ROOT/lib/core/common.sh'
source '$PROJECT_ROOT/lib/clean/project.sh'
run_with_timeout() { return 124; }
get_dir_size_kb '$HOME/www/stuck-project/node_modules'
")
[[ "$result" == "TIMEOUT" ]]
}
@test "clean_project_artifacts: handles empty directory gracefully" {
run bash -c "
export HOME='$HOME'