Add db migrations, update watch.sh for uv + idempotent runs
- Schema versioned with migrations table - watch.sh runs db migrations on every pull - watch.sh uses uv run/sync instead of pip - Fixed parser.py reference in watch.sh
This commit is contained in:
45
db.py
45
db.py
@@ -15,10 +15,10 @@ def get_db() -> sqlite3.Connection:
|
|||||||
return conn
|
return conn
|
||||||
|
|
||||||
|
|
||||||
def init_db():
|
SCHEMA_VERSION = 2
|
||||||
"""Create tables if they don't exist."""
|
|
||||||
conn = get_db()
|
MIGRATIONS = {
|
||||||
conn.executescript("""
|
1: """
|
||||||
CREATE TABLE IF NOT EXISTS repos (
|
CREATE TABLE IF NOT EXISTS repos (
|
||||||
name TEXT PRIMARY KEY,
|
name TEXT PRIMARY KEY,
|
||||||
url TEXT,
|
url TEXT,
|
||||||
@@ -34,7 +34,7 @@ def init_db():
|
|||||||
language TEXT,
|
language TEXT,
|
||||||
documentation TEXT,
|
documentation TEXT,
|
||||||
prev_documentation TEXT,
|
prev_documentation TEXT,
|
||||||
functions TEXT, -- JSON array
|
functions TEXT,
|
||||||
last_commit TEXT,
|
last_commit TEXT,
|
||||||
staleness TEXT DEFAULT 'fresh',
|
staleness TEXT DEFAULT 'fresh',
|
||||||
updated_at TEXT
|
updated_at TEXT
|
||||||
@@ -54,9 +54,42 @@ def init_db():
|
|||||||
CREATE INDEX IF NOT EXISTS idx_files_staleness ON files(staleness);
|
CREATE INDEX IF NOT EXISTS idx_files_staleness ON files(staleness);
|
||||||
CREATE INDEX IF NOT EXISTS idx_rels_staleness ON relationships(staleness);
|
CREATE INDEX IF NOT EXISTS idx_rels_staleness ON relationships(staleness);
|
||||||
CREATE INDEX IF NOT EXISTS idx_rels_to ON relationships(to_file);
|
CREATE INDEX IF NOT EXISTS idx_rels_to ON relationships(to_file);
|
||||||
""")
|
""",
|
||||||
|
2: """
|
||||||
|
CREATE TABLE IF NOT EXISTS schema_version (
|
||||||
|
version INTEGER PRIMARY KEY
|
||||||
|
);
|
||||||
|
""",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def init_db():
|
||||||
|
"""Create or migrate the database schema."""
|
||||||
|
conn = get_db()
|
||||||
|
|
||||||
|
# Check current version
|
||||||
|
try:
|
||||||
|
row = conn.execute("SELECT MAX(version) AS v FROM schema_version").fetchone()
|
||||||
|
current = row["v"] or 0
|
||||||
|
except sqlite3.OperationalError:
|
||||||
|
current = 0
|
||||||
|
|
||||||
|
if current >= SCHEMA_VERSION:
|
||||||
|
conn.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
# Run pending migrations
|
||||||
|
for v in range(current + 1, SCHEMA_VERSION + 1):
|
||||||
|
if v in MIGRATIONS:
|
||||||
|
print(f" [db] Running migration v{v}...")
|
||||||
|
conn.executescript(MIGRATIONS[v])
|
||||||
|
|
||||||
|
# Ensure schema_version table exists and record version
|
||||||
|
conn.execute("CREATE TABLE IF NOT EXISTS schema_version (version INTEGER PRIMARY KEY)")
|
||||||
|
conn.execute("INSERT OR REPLACE INTO schema_version (version) VALUES (?)", (SCHEMA_VERSION,))
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
print(f" [db] Schema at v{SCHEMA_VERSION}")
|
||||||
|
|
||||||
|
|
||||||
class GraphDB:
|
class GraphDB:
|
||||||
|
|||||||
18
watch.sh
18
watch.sh
@@ -33,7 +33,7 @@ start_mcp() {
|
|||||||
wait "$MCP_PID" 2>/dev/null || true
|
wait "$MCP_PID" 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
echo "[watch] Starting MCP server..."
|
echo "[watch] Starting MCP server..."
|
||||||
python mcp_server.py &
|
uv run python mcp_server.py &
|
||||||
MCP_PID=$!
|
MCP_PID=$!
|
||||||
echo "[watch] MCP server started (pid $MCP_PID)"
|
echo "[watch] MCP server started (pid $MCP_PID)"
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ echo ""
|
|||||||
|
|
||||||
# Initial setup
|
# Initial setup
|
||||||
LAST_HASH=$(get_local_hash)
|
LAST_HASH=$(get_local_hash)
|
||||||
LAST_REQS=$(md5sum requirements.txt 2>/dev/null || echo "none")
|
LAST_REQS=$(md5sum requirements.txt pyproject.toml 2>/dev/null || echo "none")
|
||||||
|
|
||||||
# Start MCP server
|
# Start MCP server
|
||||||
if [ -f "devintel.db" ]; then
|
if [ -f "devintel.db" ]; then
|
||||||
@@ -82,19 +82,23 @@ while true; do
|
|||||||
git pull --ff-only origin master
|
git pull --ff-only origin master
|
||||||
|
|
||||||
# Check if requirements changed
|
# Check if requirements changed
|
||||||
NEW_REQS=$(md5sum requirements.txt 2>/dev/null || echo "none")
|
NEW_REQS=$(md5sum requirements.txt pyproject.toml 2>/dev/null || echo "none")
|
||||||
if [ "$NEW_REQS" != "$LAST_REQS" ]; then
|
if [ "$NEW_REQS" != "$LAST_REQS" ]; then
|
||||||
echo "[watch] requirements.txt changed — reinstalling..."
|
echo "[watch] Dependencies changed — syncing..."
|
||||||
pip install -r requirements.txt
|
uv sync
|
||||||
LAST_REQS="$NEW_REQS"
|
LAST_REQS="$NEW_REQS"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Always run db migrations
|
||||||
|
echo "[watch] Running db migrations..."
|
||||||
|
uv run python -c "from db import init_db; init_db()"
|
||||||
|
|
||||||
# Check if ingestion code changed
|
# Check if ingestion code changed
|
||||||
CHANGED_FILES=$(git diff --name-only "$LOCAL_HASH" "$REMOTE_HASH")
|
CHANGED_FILES=$(git diff --name-only "$LOCAL_HASH" "$REMOTE_HASH")
|
||||||
NEEDS_REINGEST=false
|
NEEDS_REINGEST=false
|
||||||
for f in $CHANGED_FILES; do
|
for f in $CHANGED_FILES; do
|
||||||
case "$f" in
|
case "$f" in
|
||||||
parser.py|docgen.py|ingest.py|db.py)
|
go_parser.py|docgen.py|ingest.py|db.py)
|
||||||
NEEDS_REINGEST=true
|
NEEDS_REINGEST=true
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -102,7 +106,7 @@ while true; do
|
|||||||
|
|
||||||
if [ "$NEEDS_REINGEST" = true ] && [ -f "devintel.db" ]; then
|
if [ "$NEEDS_REINGEST" = true ] && [ -f "devintel.db" ]; then
|
||||||
echo "[watch] Ingestion code changed. Re-running ingestion..."
|
echo "[watch] Ingestion code changed. Re-running ingestion..."
|
||||||
python ingest.py
|
uv run python ingest.py
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Always restart MCP server on any code change
|
# Always restart MCP server on any code change
|
||||||
|
|||||||
Reference in New Issue
Block a user