- shared/ = portable Android-origin sources vendored from deferred/desktop-server (app/build.gradle.kts srcDir repointed; PlaybackController.kt excluded as Android-only) - backend/ = bundled-lite engine (SQLite + inline queue); .venv symlinked from the old checkout, PYTHONPATH pins THIS backend's code over any editable install - repoRoot() resolves this project dir (env SHONAR_REPO still wins); desktop-dev.sh watches shared/ + backend/ - Verified: :app:compileKotlin + :app:test green (23 tests); engine boots on :8010, self-migrates, /healthz ok
33 lines
1.1 KiB
Python
33 lines
1.1 KiB
Python
"""Programmatic schema migrations for the bundled desktop engine.
|
|
|
|
Server deployments run ``alembic upgrade head`` in their deploy flow;
|
|
the desktop app owns its SQLite file end-to-end, so the API applies
|
|
migrations itself at startup (``SHONAR_AUTO_MIGRATE=1``).
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import logging
|
|
from pathlib import Path
|
|
|
|
from alembic import command
|
|
from alembic.config import Config
|
|
|
|
logger = logging.getLogger("shonar.migrate")
|
|
|
|
# backend/ dir: migrations/ + alembic.ini live here relative to this file.
|
|
_BACKEND_DIR = Path(__file__).resolve().parents[2]
|
|
|
|
|
|
async def upgrade_head(database_url: str) -> None:
|
|
"""Run 'alembic upgrade head' for `database_url` without blocking the loop."""
|
|
|
|
def _run() -> None:
|
|
cfg = Config(str(_BACKEND_DIR / "alembic.ini"))
|
|
cfg.set_main_option("script_location", str(_BACKEND_DIR / "migrations"))
|
|
cfg.set_main_option("sqlalchemy.url", database_url)
|
|
command.upgrade(cfg, "head")
|
|
|
|
await asyncio.to_thread(_run)
|
|
logger.info("database schema migrated to head")
|