diff --git a/scripts/diagnose.sh b/scripts/diagnose.sh index 0bf300f..e5c1178 100755 --- a/scripts/diagnose.sh +++ b/scripts/diagnose.sh @@ -22,7 +22,6 @@ set -euo pipefail REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" LOG_FILE="$REPO_DIR/yaris-obd.log" SERVICE="yaris-obd.service" -DB_FILE="$REPO_DIR/$(ls "$REPO_DIR"/*.db 2>/dev/null | head -1 | xargs basename 2>/dev/null || true)" FIX=false ISSUES=0 WARNINGS=0 @@ -55,6 +54,25 @@ fix_action() { fi } +# sql_q — run a single SQL statement via Python's sqlite3 (the +# `sqlite3` CLI is not installed on the Pi). Prints the first column of the +# first result row, or nothing on error. +sql_q() { + local db="$1" sql="$2" + local py="$REPO_DIR/venv/bin/python" + [ -x "$py" ] || py="python3" + "$py" - "$db" "$sql" 2>/dev/null <<'PYEOF' +import sqlite3, sys +try: + conn = sqlite3.connect(sys.argv[1]) + row = conn.execute(sys.argv[2]).fetchone() + if row is not None: + print(row[0]) +except Exception: + pass +PYEOF +} + # ── argument parsing ────────────────────────────────────────────────────────── for arg in "$@"; do case "$arg" in @@ -227,21 +245,27 @@ else du -sh "$REPO_DIR"/*/ 2>/dev/null | sort -rh | head -5 | sed 's/^/ /' fi -# SQLite DB -DB_PATH=$(find "$REPO_DIR" -maxdepth 1 -name "*.db" 2>/dev/null | head -1) +# SQLite DB — lives under db/sql/_.db (see modules/app_sql.py), +# NOT in the repo root. Pick the most recently modified DB (the active account); +# there may also be stale test-user DBs in the same dir. Tolerate a legacy +# root-level path just in case. +DB_PATH=$(find "$REPO_DIR/db" -maxdepth 2 -name "*.db" -printf "%T@ %p\n" 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2-) +[ -n "$DB_PATH" ] || DB_PATH=$(find "$REPO_DIR" -maxdepth 1 -name "*.db" 2>/dev/null | head -1) if [ -n "$DB_PATH" ]; then DB_SIZE=$(du -sh "$DB_PATH" | cut -f1) - pass "Database found: $(basename "$DB_PATH") ($DB_SIZE)" + REL_DB="${DB_PATH#$REPO_DIR/}" + pass "Database found: $REL_DB ($DB_SIZE)" # Integrity check - INTEGRITY=$(sqlite3 "$DB_PATH" "PRAGMA integrity_check;" 2>/dev/null || echo "error") + INTEGRITY=$(sql_q "$DB_PATH" "PRAGMA integrity_check;") + INTEGRITY="${INTEGRITY:-error}" if [ "$INTEGRITY" = "ok" ]; then pass "Database integrity: OK" # Row counts - TRACKING_ROWS=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM tracking;" 2>/dev/null || echo "?") - UNSENT_ROWS=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM tracking WHERE sent=0;" 2>/dev/null || echo "?") - TRIP_ROWS=$(sqlite3 "$DB_PATH" "SELECT COUNT(*) FROM trips;" 2>/dev/null || echo "?") - info " tracking rows: $TRACKING_ROWS (unsent: $UNSENT_ROWS)" - info " trip summaries: $TRIP_ROWS" + TRACKING_ROWS=$(sql_q "$DB_PATH" "SELECT COUNT(*) FROM tracking;") + UNSENT_ROWS=$(sql_q "$DB_PATH" "SELECT COUNT(*) FROM tracking WHERE UPLOADED=0;") + TRIP_ROWS=$(sql_q "$DB_PATH" "SELECT COUNT(*) FROM trips;") + info " tracking rows: ${TRACKING_ROWS:-?} (unsent: ${UNSENT_ROWS:-?})" + info " trip summaries: ${TRIP_ROWS:-?}" if [ "${UNSENT_ROWS:-0}" -gt 5000 ]; then warn "Large upload backlog: $UNSENT_ROWS unsent tracking rows" fi @@ -250,10 +274,10 @@ if [ -n "$DB_PATH" ]; then info " !! Do NOT delete the database without backing it up first !!" info " Backup: cp '$DB_PATH' '${DB_PATH}.bak.$(date +%Y%m%d_%H%M%S)'" fix_action "backup and attempt WAL checkpoint" \ - "cp '$DB_PATH' '${DB_PATH}.bak.$(date +%Y%m%d_%H%M%S)' && sqlite3 '$DB_PATH' 'PRAGMA wal_checkpoint(FULL);'" + "cp '$DB_PATH' '${DB_PATH}.bak.$(date +%Y%m%d_%H%M%S)' && sql_q '$DB_PATH' 'PRAGMA wal_checkpoint(FULL);' >/dev/null" fi else - warn "No .db file found in $REPO_DIR — DB not yet created (normal on first run)" + warn "No .db file found under $REPO_DIR/db/sql/ — DB not yet created (normal on first run)" fi # Log file size