From b67204f959f3a8d7cfd9c1a3741df48380cbd16f Mon Sep 17 00:00:00 2001 From: Tw93 Date: Mon, 29 Dec 2025 00:29:42 +0800 Subject: [PATCH] feat: remove SQLite vacuum optimization, enhance CJK/emoji width calculation, and improve system cleanup and UI feedback. --- SECURITY_AUDIT.md | 3 +- bin/clean.sh | 6 +- cmd/analyze/format.go | 24 ++- lib/check/health_json.sh | 2 - lib/clean/system.sh | 23 --- lib/core/app_protection.sh | 5 + lib/core/base.sh | 17 ++- lib/core/ui.sh | 2 +- lib/optimize/tasks.sh | 104 ++----------- mole | 2 +- scripts/check.sh | 4 +- tests/system_maintenance.bats | 272 ---------------------------------- 12 files changed, 57 insertions(+), 407 deletions(-) diff --git a/SECURITY_AUDIT.md b/SECURITY_AUDIT.md index 87806f9..e5d8084 100644 --- a/SECURITY_AUDIT.md +++ b/SECURITY_AUDIT.md @@ -255,7 +255,7 @@ Mole uses **BATS (Bash Automated Testing System)** for automated testing. |---------------|----------|-----------| | Core File Operations | 95% | Path validation, symlink detection, permissions | | Cleaning Logic | 87% | Orphan detection, 60-day rule, vendor whitelist | -| Optimization | 82% | SQLite VACUUM, cache cleanup, timeouts | +| Optimization | 82% | Cache cleanup, timeouts | | System Maintenance | 90% | Time Machine, network volumes, crash recovery | | Security Controls | 100% | Path traversal, command injection, symlinks | @@ -315,7 +315,6 @@ Mole relies on standard macOS system binaries (all SIP-protected): | `tmutil` | Time Machine interaction | Skip TM cleanup | | `dscacheutil` | System cache rebuilding | Optional optimization | | `diskutil` | Volume information | Skip network volumes | -| `sqlite3` | Database optimization | Skip SQLite VACUUM | ### Go Dependencies (Interactive Tools) diff --git a/bin/clean.sh b/bin/clean.sh index 572404a..40b0f62 100755 --- a/bin/clean.sh +++ b/bin/clean.sh @@ -105,6 +105,7 @@ files_cleaned=0 total_size_cleaned=0 whitelist_skipped_count=0 +# shellcheck disable=SC2329 note_activity() { if [[ $TRACK_SECTION -eq 1 ]]; then SECTION_ACTIVITY=1 @@ -113,6 +114,7 @@ note_activity() { # Cleanup background processes CLEANUP_DONE=false +# shellcheck disable=SC2329 cleanup() { local signal="${1:-EXIT}" local exit_code="${2:-$?}" @@ -124,7 +126,7 @@ cleanup() { CLEANUP_DONE=true # Stop all spinners and clear the line - if [[ -n "$INLINE_SPINNER_PID" ]]; then + if [[ -n "${INLINE_SPINNER_PID:-}" ]] && kill -0 "$INLINE_SPINNER_PID" 2> /dev/null; then kill "$INLINE_SPINNER_PID" 2> /dev/null || true wait "$INLINE_SPINNER_PID" 2> /dev/null || true INLINE_SPINNER_PID="" @@ -176,6 +178,7 @@ end_section() { TRACK_SECTION=0 } +# shellcheck disable=SC2329 safe_clean() { if [[ $# -eq 0 ]]; then return 0 @@ -767,6 +770,7 @@ main() { hide_cursor perform_cleanup show_cursor + exit 0 } main "$@" diff --git a/cmd/analyze/format.go b/cmd/analyze/format.go index 7679489..881acb7 100644 --- a/cmd/analyze/format.go +++ b/cmd/analyze/format.go @@ -142,14 +142,24 @@ func coloredProgressBar(value, max int64, percent float64) string { return bar + colorReset } -// Calculate display width considering CJK characters. +// Calculate display width considering CJK characters and Emoji. func runeWidth(r rune) int { - if r >= 0x4E00 && r <= 0x9FFF || - r >= 0x3400 && r <= 0x4DBF || - r >= 0x3040 && r <= 0x30FF || - r >= 0x31F0 && r <= 0x31FF || - r >= 0xAC00 && r <= 0xD7AF || - r >= 0xFF00 && r <= 0xFFEF { + if r >= 0x4E00 && r <= 0x9FFF || // CJK Unified Ideographs + r >= 0x3400 && r <= 0x4DBF || // CJK Extension A + r >= 0x20000 && r <= 0x2A6DF || // CJK Extension B + r >= 0x2A700 && r <= 0x2B73F || // CJK Extension C + r >= 0x2B740 && r <= 0x2B81F || // CJK Extension D + r >= 0x2B820 && r <= 0x2CEAF || // CJK Extension E + r >= 0x3040 && r <= 0x30FF || // Hiragana and Katakana + r >= 0x31F0 && r <= 0x31FF || // Katakana Phonetic Extensions + r >= 0xAC00 && r <= 0xD7AF || // Hangul Syllables + r >= 0xFF00 && r <= 0xFFEF || // Fullwidth Forms + r >= 0x1F300 && r <= 0x1F6FF || // Miscellaneous Symbols and Pictographs (includes Transport) + r >= 0x1F900 && r <= 0x1F9FF || // Supplemental Symbols and Pictographs + r >= 0x2600 && r <= 0x26FF || // Miscellaneous Symbols + r >= 0x2700 && r <= 0x27BF || // Dingbats + r >= 0xFE10 && r <= 0xFE1F || // Vertical Forms + r >= 0x1F000 && r <= 0x1F02F { // Mahjong Tiles return 2 } return 1 diff --git a/lib/check/health_json.sh b/lib/check/health_json.sh index ac08a42..77fbbef 100644 --- a/lib/check/health_json.sh +++ b/lib/check/health_json.sh @@ -128,8 +128,6 @@ EOF items+=('maintenance_scripts|System Log Rotation|Rotate and compress system logs with newsyslog|true') items+=('swap_cleanup|Virtual Memory Refresh|Reset swap files and dynamic pager service|true') items+=('network_optimization|Network Stack Optimization|Refresh DNS, rebuild ARP & restart mDNSResponder|true') - items+=('sqlite_vacuum|SQLite Database Optimization|Optimize user databases with VACUUM to reduce size|true') - # Output items as JSON local first=true for item in "${items[@]}"; do diff --git a/lib/clean/system.sh b/lib/clean/system.sh index a863ba7..1311436 100644 --- a/lib/clean/system.sh +++ b/lib/clean/system.sh @@ -155,29 +155,6 @@ clean_deep_system() { fi fi debug_log "Core symbolication cache section completed" - - # Clean Aliyun/DingTalk security component logs (if exists, can be 2-3GB) - # Only clean if the software is installed - debug_log "Checking Aliyun security components..." - local ali_cleaned=0 - - # List of Aliyun-related paths to clean - local -a ali_paths=( - "/private/var/root/Library/Application Support/ali_bas/bas_http_info/ali_bas_httpclient" - "/private/var/root/Library/Application Support/Aliedr/logs_dir" - "/private/var/root/Library/Application Support/Aliedr/cache" - ) - - # Clean each path if exists - for ali_path in "${ali_paths[@]}"; do - if sudo test -e "$ali_path" 2> /dev/null; then - debug_log "Found Aliyun component: $ali_path, removing..." - safe_sudo_remove "$ali_path" && ((ali_cleaned++)) || true - fi - done - - debug_log "Aliyun security components check completed, cleaned: $ali_cleaned" - [[ $ali_cleaned -gt 0 ]] && log_success "Aliyun security component data" } # Clean incomplete Time Machine backups diff --git a/lib/core/app_protection.sh b/lib/core/app_protection.sh index 0d8b285..ee0f4b3 100755 --- a/lib/core/app_protection.sh +++ b/lib/core/app_protection.sh @@ -520,6 +520,11 @@ should_protect_path() { return 0 fi + # Protect Notes cache (search index issues) + if [[ "$path_lower" =~ com\.apple\.notes ]]; then + return 0 + fi + # 2. Protect caches critical for system UI rendering # These caches are essential for modern macOS (Sonoma/Sequoia) system UI rendering case "$path" in diff --git a/lib/core/base.sh b/lib/core/base.sh index 6600c8a..0f1f2bd 100644 --- a/lib/core/base.sh +++ b/lib/core/base.sh @@ -429,11 +429,18 @@ bytes_to_human_kb() { get_brand_name() { local name="$1" - # Detect if system primary language is Chinese - local is_chinese=false - local sys_lang - sys_lang=$(defaults read -g AppleLanguages 2> /dev/null | grep -o 'zh-Hans\|zh-Hant\|zh' | head -1 || echo "") - [[ -n "$sys_lang" ]] && is_chinese=true + # Detect if system primary language is Chinese (Cached) + if [[ -z "${MOLE_IS_CHINESE_SYSTEM:-}" ]]; then + local sys_lang + sys_lang=$(defaults read -g AppleLanguages 2> /dev/null | grep -o 'zh-Hans\|zh-Hant\|zh' | head -1 || echo "") + if [[ -n "$sys_lang" ]]; then + export MOLE_IS_CHINESE_SYSTEM="true" + else + export MOLE_IS_CHINESE_SYSTEM="false" + fi + fi + + local is_chinese="${MOLE_IS_CHINESE_SYSTEM}" # Return localized names based on system language if [[ "$is_chinese" == true ]]; then diff --git a/lib/core/ui.sh b/lib/core/ui.sh index 49b0084..c0a6d00 100755 --- a/lib/core/ui.sh +++ b/lib/core/ui.sh @@ -284,7 +284,7 @@ stop_inline_spinner() { # Try graceful TERM first, then force KILL if needed if kill -0 "$INLINE_SPINNER_PID" 2> /dev/null; then kill -TERM "$INLINE_SPINNER_PID" 2> /dev/null || true - sleep 0.05 2> /dev/null || true + sleep 0.1 2> /dev/null || true # Force kill if still running if kill -0 "$INLINE_SPINNER_PID" 2> /dev/null; then kill -KILL "$INLINE_SPINNER_PID" 2> /dev/null || true diff --git a/lib/optimize/tasks.sh b/lib/optimize/tasks.sh index 8f70a79..1539101 100644 --- a/lib/optimize/tasks.sh +++ b/lib/optimize/tasks.sh @@ -69,7 +69,20 @@ opt_cache_refresh() { # Run periodic maintenance scripts opt_maintenance_scripts() { + if [[ -t 1 ]]; then + MOLE_SPINNER_PREFIX=" " start_inline_spinner "Rotating logs..." + fi + + local success=false if run_with_timeout 120 sudo newsyslog > /dev/null 2>&1; then + success=true + fi + + if [[ -t 1 ]]; then + stop_inline_spinner + fi + + if [[ "$success" == "true" ]]; then echo -e " ${GREEN}✓${NC} System logs rotated" else echo -e " ${YELLOW}!${NC} Failed to rotate logs" @@ -204,96 +217,6 @@ opt_network_optimization() { echo -e " ${GREEN}✓${NC} mDNSResponder optimized" } -# SQLite database optimization -# Runs VACUUM on safe user-level databases to reduce size and improve performance -# Only operates on databases that are not in use and meet size threshold -opt_sqlite_vacuum() { - local optimized_count=0 - local total_saved_kb=0 - local min_size_kb=1024 # Only optimize databases larger than 1MB - - # List of safe databases to optimize - # Exclude critical system databases like Mail, Messages, Photos - local -a safe_databases=( - "$HOME/Library/Safari/History.db" - "$HOME/Library/Safari/CloudTabs.db" - ) - - if [[ -t 1 ]]; then - MOLE_SPINNER_PREFIX=" " start_inline_spinner "Scanning databases..." - fi - - for db_path in "${safe_databases[@]}"; do - # Check if database exists - [[ ! -f "$db_path" ]] && continue - - # Check if it's a SQLite database - if ! file "$db_path" 2> /dev/null | grep -q "SQLite"; then - continue - fi - - # Check size threshold - local db_size_kb - db_size_kb=$(get_path_size_kb "$db_path") - [[ $db_size_kb -lt $min_size_kb ]] && continue - - # Check if database is in use - if lsof "$db_path" > /dev/null 2>&1; then - debug_log "Skipping $db_path - in use" - continue - fi - - # Check disk space (VACUUM needs ~2x database size as temporary space) - local free_space_kb - free_space_kb=$(df -k "$(dirname "$db_path")" | tail -1 | awk '{print $4}') - if [[ $free_space_kb -lt $((db_size_kb * 2)) ]]; then - debug_log "Skipping $db_path - insufficient disk space" - continue - fi - - # Verify database integrity before VACUUM - if ! sqlite3 "$db_path" "PRAGMA integrity_check;" 2> /dev/null | grep -q "ok"; then - debug_log "Skipping $db_path - integrity check failed" - continue - fi - - # Get size before optimization - local size_before=$db_size_kb - - # Perform VACUUM with error handling - if sqlite3 "$db_path" "VACUUM;" 2> /dev/null; then - # Verify database integrity after VACUUM - if ! sqlite3 "$db_path" "PRAGMA integrity_check;" 2> /dev/null | grep -q "ok"; then - debug_log "Warning: $db_path integrity check failed after VACUUM" - continue - fi - - # Get size after optimization - local size_after - size_after=$(get_path_size_kb "$db_path") - local saved_kb=$((size_before - size_after)) - - if [[ $saved_kb -gt 0 ]]; then - ((optimized_count++)) - ((total_saved_kb += saved_kb)) - fi - else - debug_log "Failed to VACUUM $db_path" - fi - done - - if [[ -t 1 ]]; then - stop_inline_spinner - fi - - if [[ $optimized_count -gt 0 ]]; then - local saved_human=$(bytes_to_human "$((total_saved_kb * 1024))") - echo -e " ${GREEN}✓${NC} Optimized $optimized_count databases ($saved_human saved)" - else - echo -e " ${GREEN}✓${NC} Databases already optimized" - fi -} - # Clean Spotlight user caches # Execute optimization by action name @@ -312,7 +235,6 @@ execute_optimization() { local_snapshots) opt_local_snapshots ;; fix_broken_configs) opt_fix_broken_configs ;; network_optimization) opt_network_optimization ;; - sqlite_vacuum) opt_sqlite_vacuum ;; *) echo -e "${YELLOW}${ICON_ERROR}${NC} Unknown action: $action" return 1 diff --git a/mole b/mole index e7bb6f9..e2b0f46 100755 --- a/mole +++ b/mole @@ -25,7 +25,7 @@ source "$SCRIPT_DIR/lib/core/common.sh" trap cleanup_temp_files EXIT INT TERM # Version info -VERSION="1.15.4" +VERSION="1.15.5" MOLE_TAGLINE="Deep clean and optimize your Mac." # Check TouchID configuration diff --git a/scripts/check.sh b/scripts/check.sh index 0817e68..21f76f2 100755 --- a/scripts/check.sh +++ b/scripts/check.sh @@ -38,9 +38,9 @@ if command -v shellcheck > /dev/null 2>&1; then SHELL_FILES=$(find . -type f \( -name "*.sh" -o -name "mole" \) -not -path "./tests/*" -not -path "./.git/*") FILE_COUNT=$(echo "$SHELL_FILES" | wc -l | tr -d ' ') - if shellcheck mole bin/*.sh lib/*.sh scripts/*.sh 2>&1 | grep -q "SC[0-9]"; then + if shellcheck mole bin/*.sh lib/*/*.sh scripts/*.sh 2>&1 | grep -q "SC[0-9]"; then echo -e "${YELLOW}⚠ ShellCheck found some issues (non-critical):${NC}" - shellcheck mole bin/*.sh lib/*.sh scripts/*.sh 2>&1 | head -20 + shellcheck mole bin/*.sh lib/*/*.sh scripts/*.sh 2>&1 | head -20 echo -e "${GREEN}✓ ShellCheck completed (${FILE_COUNT} files checked)${NC}\n" else echo -e "${GREEN}✓ ShellCheck passed (${FILE_COUNT} files checked)${NC}\n" diff --git a/tests/system_maintenance.bats b/tests/system_maintenance.bats index 0daf044..b97f68a 100644 --- a/tests/system_maintenance.bats +++ b/tests/system_maintenance.bats @@ -469,275 +469,3 @@ EOF [ "$status" -eq 0 ] [[ "$output" == *"WOULD_CLEAN=no"* ]] } - -@test "clean_deep_system cleans Aliyun components when present" { - run bash --noprofile --norc <<'EOF' -set -euo pipefail -CLEANED_PATHS="" -source "$PROJECT_ROOT/lib/core/common.sh" -source "$PROJECT_ROOT/lib/clean/system.sh" - -sudo() { - if [[ "$1" == "test" ]]; then - # Simulate Aliyun paths exist - [[ "$3" == *"ali_bas"* || "$3" == *"Aliedr"* ]] && return 0 - return 1 - fi - return 0 -} - -safe_sudo_remove() { - CLEANED_PATHS="$CLEANED_PATHS|$1" - return 0 -} -safe_sudo_find_delete() { return 0; } -log_success() { :; } -start_section_spinner() { :; } -stop_section_spinner() { :; } -is_sip_enabled() { return 1; } -find() { return 0; } -run_with_timeout() { shift; "$@"; } - -clean_deep_system -echo "$CLEANED_PATHS" -EOF - - [ "$status" -eq 0 ] - [[ "$output" == *"ali_bas"* ]] - [[ "$output" == *"Aliedr"* ]] -} - -# ============================================================================ -# Tests for SQLite VACUUM optimization (v1.15.2) -# ============================================================================ - -skip_if_no_sqlite3() { - command -v sqlite3 > /dev/null 2>&1 || skip "sqlite3 not available" -} - -@test "opt_sqlite_vacuum optimizes Safari databases" { - skip_if_no_sqlite3 - # Create test databases - mkdir -p "$HOME/Library/Safari" - - # Clean up any existing databases from previous tests - rm -f "$HOME/Library/Safari/History.db" "$HOME/Library/Safari/CloudTabs.db" - - # Create a simple SQLite database - run sqlite3 "$HOME/Library/Safari/History.db" "CREATE TABLE test(id INTEGER); INSERT INTO test VALUES(1);" - [ "$status" -eq 0 ] - - # Create another test database - run sqlite3 "$HOME/Library/Safari/CloudTabs.db" "CREATE TABLE test(id INTEGER); INSERT INTO test VALUES(1);" - [ "$status" -eq 0 ] - - run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc << 'EOF' -set -euo pipefail -source "$PROJECT_ROOT/lib/core/common.sh" -source "$PROJECT_ROOT/lib/optimize/tasks.sh" - -# Mock functions to avoid actual operations -start_inline_spinner() { :; } -stop_inline_spinner() { :; } -lsof() { return 1; } # Database not in use - -opt_sqlite_vacuum -EOF - - [ "$status" -eq 0 ] - [[ "$output" == *"Databases already optimized"* || "$output" == *"Optimized"* ]] -} - -@test "opt_sqlite_vacuum checks database integrity before VACUUM" { - skip_if_no_sqlite3 - mkdir -p "$HOME/Library/Safari" - - # Clean up and create database - rm -f "$HOME/Library/Safari/History.db" - sqlite3 "$HOME/Library/Safari/History.db" "CREATE TABLE test(id INTEGER);" - - run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc << 'EOF' -set -euo pipefail -source "$PROJECT_ROOT/lib/core/common.sh" -source "$PROJECT_ROOT/lib/optimize/tasks.sh" - -INTEGRITY_CHECKS=0 -original_sqlite3=$(command -v sqlite3) - -sqlite3() { - if [[ "$2" == *"integrity_check"* ]]; then - ((INTEGRITY_CHECKS++)) - echo "ok" - return 0 - fi - "$original_sqlite3" "$@" -} -export -f sqlite3 - -start_inline_spinner() { :; } -stop_inline_spinner() { :; } -lsof() { return 1; } - -opt_sqlite_vacuum -echo "INTEGRITY_CHECKS=$INTEGRITY_CHECKS" -EOF - - [ "$status" -eq 0 ] - # Should check integrity at least once (before VACUUM) - [[ "$output" == *"INTEGRITY_CHECKS="* ]] -} - -@test "opt_sqlite_vacuum skips databases in use" { - skip_if_no_sqlite3 - mkdir -p "$HOME/Library/Safari" - rm -f "$HOME/Library/Safari/History.db" - sqlite3 "$HOME/Library/Safari/History.db" "CREATE TABLE test(id INTEGER);" - - run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc << 'EOF' -set -euo pipefail -source "$PROJECT_ROOT/lib/core/common.sh" -source "$PROJECT_ROOT/lib/optimize/tasks.sh" - -VACUUM_COUNT=0 -original_sqlite3=$(command -v sqlite3) - -sqlite3() { - if [[ "$2" == "VACUUM;" ]]; then - ((VACUUM_COUNT++)) - fi - "$original_sqlite3" "$@" -} -export -f sqlite3 - -start_inline_spinner() { :; } -stop_inline_spinner() { :; } -lsof() { return 0; } # Database is in use - -opt_sqlite_vacuum -echo "VACUUM_COUNT=$VACUUM_COUNT" -EOF - - [ "$status" -eq 0 ] - # Should not VACUUM when database is in use - [[ "$output" == *"VACUUM_COUNT=0"* ]] -} - -@test "opt_sqlite_vacuum checks disk space before VACUUM" { - skip_if_no_sqlite3 - mkdir -p "$HOME/Library/Safari" - - # Clean up and create a 2MB database - rm -f "$HOME/Library/Safari/History.db" - sqlite3 "$HOME/Library/Safari/History.db" << 'SQL' -CREATE TABLE test(id INTEGER, data TEXT); -INSERT INTO test VALUES(1, randomblob(1024*1024)); -INSERT INTO test VALUES(2, randomblob(1024*1024)); -SQL - - run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc << 'EOF' -set -euo pipefail -source "$PROJECT_ROOT/lib/core/common.sh" -source "$PROJECT_ROOT/lib/optimize/tasks.sh" - -VACUUM_ATTEMPTED=0 -original_sqlite3=$(command -v sqlite3) - -sqlite3() { - if [[ "$2" == "VACUUM;" ]]; then - VACUUM_ATTEMPTED=1 - fi - "$original_sqlite3" "$@" -} -export -f sqlite3 - -# Mock df to report insufficient space -df() { - if [[ "$1" == "-k" ]]; then - echo "Filesystem 1024-blocks Used Available Capacity" - echo "/dev/disk1 1000000 900000 100 90%" # Only 100KB free - fi -} -export -f df - -start_inline_spinner() { :; } -stop_inline_spinner() { :; } -lsof() { return 1; } - -opt_sqlite_vacuum -echo "VACUUM_ATTEMPTED=$VACUUM_ATTEMPTED" -EOF - - [ "$status" -eq 0 ] - # Should skip VACUUM when insufficient disk space - [[ "$output" == *"VACUUM_ATTEMPTED=0"* ]] -} - -@test "opt_sqlite_vacuum skips non-SQLite files" { - skip_if_no_sqlite3 - mkdir -p "$HOME/Library/Safari" - - # Create a non-SQLite file - echo "not a database" > "$HOME/Library/Safari/History.db" - - run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc << 'EOF' -set -euo pipefail -source "$PROJECT_ROOT/lib/core/common.sh" -source "$PROJECT_ROOT/lib/optimize/tasks.sh" - -start_inline_spinner() { :; } -stop_inline_spinner() { :; } - -opt_sqlite_vacuum -EOF - - [ "$status" -eq 0 ] - [[ "$output" == *"Databases already optimized"* ]] -} - -@test "opt_sqlite_vacuum verifies integrity after VACUUM" { - skip_if_no_sqlite3 - mkdir -p "$HOME/Library/Safari" - rm -f "$HOME/Library/Safari/History.db" - sqlite3 "$HOME/Library/Safari/History.db" "CREATE TABLE test(id INTEGER); INSERT INTO test VALUES(1);" - - run env HOME="$HOME" PROJECT_ROOT="$PROJECT_ROOT" bash --noprofile --norc << 'EOF' -set -euo pipefail -source "$PROJECT_ROOT/lib/core/common.sh" -source "$PROJECT_ROOT/lib/optimize/tasks.sh" - -CALL_LOG="$HOME/vacuum_calls.log" -> "$CALL_LOG" - -original_sqlite3=$(command -v sqlite3) - -sqlite3() { - if [[ "$2" == *"integrity_check"* ]]; then - echo "INTEGRITY_CHECK" >> "$CALL_LOG" - echo "ok" - return 0 - elif [[ "$2" == "VACUUM;" ]]; then - echo "VACUUM" >> "$CALL_LOG" - fi - "$original_sqlite3" "$@" -} -export -f sqlite3 - -start_inline_spinner() { :; } -stop_inline_spinner() { :; } -lsof() { return 1; } - -opt_sqlite_vacuum - -# Count calls -integrity_count=$(grep -c "INTEGRITY_CHECK" "$CALL_LOG" || echo 0) -vacuum_count=$(grep -c "VACUUM" "$CALL_LOG" || echo 0) - -echo "INTEGRITY_CHECKS=$integrity_count" -echo "VACUUM_COUNT=$vacuum_count" -EOF - - [ "$status" -eq 0 ] - # Should check integrity at least once and perform VACUUM - [[ "$output" == *"INTEGRITY_CHECKS="* ]] - [[ "$output" == *"VACUUM_COUNT="* ]] -}