From 2d7932025f7d6a1f34aed660cb2ab32ad0311b13 Mon Sep 17 00:00:00 2001 From: Tw93 Date: Thu, 11 Dec 2025 19:24:23 +0800 Subject: [PATCH] Parallel scanning and testing --- lib/clean/caches.sh | 89 +++++++++++++++++--------------------------- lib/clean/user.sh | 3 +- mole | 5 ++- scripts/run-tests.sh | 43 +++++++++++---------- 4 files changed, 62 insertions(+), 78 deletions(-) diff --git a/lib/clean/caches.sh b/lib/clean/caches.sh index 966ad6c..d9dc45a 100644 --- a/lib/clean/caches.sh +++ b/lib/clean/caches.sh @@ -126,15 +126,18 @@ clean_service_worker_cache() { # Clean Next.js (.next/cache) and Python (__pycache__) build caches # Uses maxdepth 3, excludes Library/.Trash/node_modules, 10s timeout per scan clean_project_caches() { - # Clean Next.js caches if [[ -t 1 ]]; then MOLE_SPINNER_PREFIX=" " - start_inline_spinner "Searching Next.js caches..." + start_inline_spinner "Searching project caches..." fi - # Use timeout to prevent hanging on problematic directories local nextjs_tmp_file nextjs_tmp_file=$(create_temp_file) + local pycache_tmp_file + pycache_tmp_file=$(create_temp_file) + local find_timeout=10 + + # 1. Start Next.js search ( command find "$HOME" -P -mount -type d -name ".next" -maxdepth 3 \ -not -path "*/Library/*" \ @@ -143,42 +146,9 @@ clean_project_caches() { -not -path "*/.*" \ 2> /dev/null || true ) > "$nextjs_tmp_file" 2>&1 & - local find_pid=$! - local find_timeout=10 - local elapsed=0 + local next_pid=$! - # Wait for find to complete or timeout - while kill -0 $find_pid 2> /dev/null && [[ $elapsed -lt $find_timeout ]]; do - sleep 1 - ((elapsed++)) - done - - # Kill if still running after timeout - if kill -0 $find_pid 2> /dev/null; then - kill -TERM $find_pid 2> /dev/null || true - wait $find_pid 2> /dev/null || true - else - wait $find_pid 2> /dev/null || true - fi - - # Clean found Next.js caches - while IFS= read -r next_dir; do - [[ -d "$next_dir/cache" ]] && safe_clean "$next_dir/cache"/* "Next.js build cache" || true - done < "$nextjs_tmp_file" - - if [[ -t 1 ]]; then - stop_inline_spinner - fi - - # Clean Python bytecode caches - if [[ -t 1 ]]; then - MOLE_SPINNER_PREFIX=" " - start_inline_spinner "Searching Python caches..." - fi - - # Use timeout to prevent hanging on problematic directories - local pycache_tmp_file - pycache_tmp_file=$(create_temp_file) + # 2. Start Python search ( command find "$HOME" -P -mount -type d -name "__pycache__" -maxdepth 3 \ -not -path "*/Library/*" \ @@ -187,32 +157,41 @@ clean_project_caches() { -not -path "*/.*" \ 2> /dev/null || true ) > "$pycache_tmp_file" 2>&1 & - local find_pid=$! - local find_timeout=10 - local elapsed=0 + local py_pid=$! - # Wait for find to complete or timeout - while kill -0 $find_pid 2> /dev/null && [[ $elapsed -lt $find_timeout ]]; do + # 3. Wait for both with timeout + local elapsed=0 + while [[ $elapsed -lt $find_timeout ]]; do + if ! kill -0 $next_pid 2> /dev/null && ! kill -0 $py_pid 2> /dev/null; then + break + fi sleep 1 ((elapsed++)) done - # Kill if still running after timeout - if kill -0 $find_pid 2> /dev/null; then - kill -TERM $find_pid 2> /dev/null || true - wait $find_pid 2> /dev/null || true - else - wait $find_pid 2> /dev/null || true - fi - - # Clean found Python caches - while IFS= read -r pycache; do - [[ -d "$pycache" ]] && safe_clean "$pycache"/* "Python bytecode cache" || true - done < "$pycache_tmp_file" + # 4. Clean up any stuck processes + for pid in $next_pid $py_pid; do + if kill -0 "$pid" 2> /dev/null; then + kill -TERM "$pid" 2> /dev/null || true + wait "$pid" 2> /dev/null || true + else + wait "$pid" 2> /dev/null || true + fi + done if [[ -t 1 ]]; then stop_inline_spinner fi + + # 5. Process Next.js results + while IFS= read -r next_dir; do + [[ -d "$next_dir/cache" ]] && safe_clean "$next_dir/cache"/* "Next.js build cache" || true + done < "$nextjs_tmp_file" + + # 6. Process Python results + while IFS= read -r pycache; do + [[ -d "$pycache" ]] && safe_clean "$pycache"/* "Python bytecode cache" || true + done < "$pycache_tmp_file" } # Clean Spotlight user caches diff --git a/lib/clean/user.sh b/lib/clean/user.sh index f75a723..88da1af 100644 --- a/lib/clean/user.sh +++ b/lib/clean/user.sh @@ -10,7 +10,7 @@ clean_user_essentials() { safe_clean ~/.Trash/* "Trash" # Empty trash on mounted volumes - if [[ -d "/Volumes" ]]; then + if [[ -d "/Volumes" && "$DRY_RUN" != "true" ]]; then for volume in /Volumes/*; do [[ -d "$volume" && -d "$volume/.Trashes" && -w "$volume" ]] || continue @@ -23,7 +23,6 @@ clean_user_essentials() { # Verify volume is mounted and not a symlink mount | grep -q "on $volume " || continue [[ -L "$volume/.Trashes" ]] && continue - [[ "$DRY_RUN" == "true" ]] && continue # Safely iterate and remove each item while IFS= read -r -d '' item; do diff --git a/mole b/mole index d17f766..abf6510 100755 --- a/mole +++ b/mole @@ -22,7 +22,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" source "$SCRIPT_DIR/lib/core/common.sh" # Version info -VERSION="1.12.10" +VERSION="1.12.11" MOLE_TAGLINE="can dig deep to clean your Mac." # Check if Touch ID is already configured @@ -738,6 +738,9 @@ main() { "touchid") exec "$SCRIPT_DIR/bin/touchid.sh" "${args[@]:1}" ;; + "test") + exec "$SCRIPT_DIR/scripts/run-tests.sh" "${args[@]:1}" + ;; "update") update_mole exit 0 diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh index 1d2ab24..b37e225 100755 --- a/scripts/run-tests.sh +++ b/scripts/run-tests.sh @@ -13,9 +13,9 @@ GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' -echo "================================" +echo "===============================" echo " Mole Test Runner" -echo "================================" +echo "===============================" echo "" # Track failures @@ -26,13 +26,13 @@ echo "1. Running ShellCheck..." if command -v shellcheck > /dev/null 2>&1; then if shellcheck mole bin/*.sh 2> /dev/null && find lib -name "*.sh" -type f -exec shellcheck {} + 2> /dev/null; then - echo -e "${GREEN}✓ ShellCheck passed${NC}" + printf "${GREEN}✓ ShellCheck passed${NC}\n" else - echo -e "${RED}✗ ShellCheck failed${NC}" + printf "${RED}✗ ShellCheck failed${NC}\n" ((FAILED++)) fi else - echo -e "${YELLOW}⚠ ShellCheck not installed, skipping${NC}" + printf "${YELLOW}⚠ ShellCheck not installed, skipping${NC}\n" fi echo "" @@ -41,9 +41,9 @@ echo "2. Running syntax check..." if bash -n mole && bash -n bin/*.sh 2> /dev/null && find lib -name "*.sh" -type f -exec bash -n {} \; 2> /dev/null; then - echo -e "${GREEN}✓ Syntax check passed${NC}" + printf "${GREEN}✓ Syntax check passed${NC}\n" else - echo -e "${RED}✗ Syntax check failed${NC}" + printf "${RED}✗ Syntax check failed${NC}\n" ((FAILED++)) fi echo "" @@ -51,14 +51,16 @@ echo "" # 3. Unit Tests echo "3. Running unit tests..." if command -v bats > /dev/null 2>&1; then + # Note: bats might detect non-TTY and suppress color. + # Adding --tap prevents spinner issues in background. if bats tests/*.bats; then - echo -e "${GREEN}✓ Unit tests passed${NC}" + printf "${GREEN}✓ Unit tests passed${NC}\n" else - echo -e "${RED}✗ Unit tests failed${NC}" + printf "${RED}✗ Unit tests failed${NC}\n" ((FAILED++)) fi else - echo -e "${YELLOW}⚠ Bats not installed, skipping unit tests${NC}" + printf "${YELLOW}⚠ Bats not installed, skipping unit tests${NC}\n" echo " Install with: brew install bats-core" fi echo "" @@ -67,45 +69,46 @@ echo "" echo "4. Running Go tests..." if command -v go > /dev/null 2>&1; then if go build ./... && go vet ./cmd/... && go test ./cmd/...; then - echo -e "${GREEN}✓ Go tests passed${NC}" + printf "${GREEN}✓ Go tests passed${NC}\n" else - echo -e "${RED}✗ Go tests failed${NC}" + printf "${RED}✗ Go tests failed${NC}\n" ((FAILED++)) fi else - echo -e "${YELLOW}⚠ Go not installed, skipping Go tests${NC}" + printf "${YELLOW}⚠ Go not installed, skipping Go tests${NC}\n" fi echo "" # 5. Module Loading Test echo "5. Testing module loading..." if bash -c 'source lib/core/common.sh && echo "OK"' > /dev/null 2>&1; then - echo -e "${GREEN}✓ Module loading passed${NC}" + printf "${GREEN}✓ Module loading passed${NC}\n" else - echo -e "${RED}✗ Module loading failed${NC}" + printf "${RED}✗ Module loading failed${NC}\n" ((FAILED++)) fi echo "" # 6. Integration Tests echo "6. Running integration tests..." +export MOLE_MAX_PARALLEL_JOBS=30 if ./bin/clean.sh --dry-run > /dev/null 2>&1; then - echo -e "${GREEN}✓ Clean dry-run passed${NC}" + printf "${GREEN}✓ Clean dry-run passed${NC}\n" else - echo -e "${RED}✗ Clean dry-run failed${NC}" + printf "${RED}✗ Clean dry-run failed${NC}\n" ((FAILED++)) fi echo "" # Summary -echo "================================" +echo "===============================" if [[ $FAILED -eq 0 ]]; then - echo -e "${GREEN}All tests passed!${NC}" + printf "${GREEN}All tests passed!${NC}\n" echo "" echo "You can now commit your changes." exit 0 else - echo -e "${RED}$FAILED test(s) failed!${NC}" + printf "${RED}$FAILED test(s) failed!${NC}\n" echo "" echo "Please fix the failing tests before committing." exit 1