diff --git a/Dockerfile b/Dockerfile index 0bc987e..2d899c5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,7 +22,7 @@ RUN uv sync --locked --no-dev --no-editable --no-cache ENV PYTHONUNBUFFERED=1 ENV VIRTUAL_ENV=/app/.venv -ENV PATH=/app/.vnev/bin:$PATH +ENV PATH=/app/.venv/bin:$PATH ENV TESSDATA_PREFIX=/usr/share/tesseract-ocr/5/tessdata ENTRYPOINT ["/app/.venv/bin/nextcloud-mcp-server", "run", "--host", "0.0.0.0"] diff --git a/alembic.ini b/alembic.ini index e030b90..1a2971e 100644 --- a/alembic.ini +++ b/alembic.ini @@ -2,7 +2,7 @@ [alembic] # Path to migration scripts -script_location = alembic +script_location = nextcloud_mcp_server/alembic # Template used to generate migration file names # Default: %%(rev)s_%%(slug)s @@ -26,7 +26,7 @@ timezone = utc # Version location specification # Supports single or multiple directories -version_locations = alembic/versions +version_locations = nextcloud_mcp_server/alembic/versions # Path separator for version locations (required to suppress deprecation warning) # Use os (for cross-platform compatibility) diff --git a/nextcloud_mcp_server/alembic/__init__.py b/nextcloud_mcp_server/alembic/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/alembic/env.py b/nextcloud_mcp_server/alembic/env.py similarity index 94% rename from alembic/env.py rename to nextcloud_mcp_server/alembic/env.py index 4a3fadb..3026174 100644 --- a/alembic/env.py +++ b/nextcloud_mcp_server/alembic/env.py @@ -23,6 +23,11 @@ logger = logging.getLogger("alembic.env") # access to the values within the .ini file in use. config = context.config +# Update script location to point to package location +# This allows alembic to find migrations when installed in site-packages +script_location = Path(__file__).parent +config.set_main_option("script_location", str(script_location)) + # We don't use SQLAlchemy models, so target_metadata is None # Migrations will be written manually using op.execute() for raw SQL target_metadata = None diff --git a/alembic/versions/20251217_2200_001_initial_schema.py b/nextcloud_mcp_server/alembic/versions/20251217_2200_001_initial_schema.py similarity index 100% rename from alembic/versions/20251217_2200_001_initial_schema.py rename to nextcloud_mcp_server/alembic/versions/20251217_2200_001_initial_schema.py diff --git a/nextcloud_mcp_server/alembic/versions/__init__.py b/nextcloud_mcp_server/alembic/versions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nextcloud_mcp_server/migrations.py b/nextcloud_mcp_server/migrations.py index bbff578..e595ec2 100644 --- a/nextcloud_mcp_server/migrations.py +++ b/nextcloud_mcp_server/migrations.py @@ -19,33 +19,39 @@ def get_alembic_config(database_path: str | Path | None = None) -> Config: """ Get Alembic configuration for programmatic use. + Works in both development and installed (Docker) modes by using + package location instead of alembic.ini file. + Args: database_path: Path to SQLite database file. If None, uses default - from alembic.ini (/app/data/tokens.db) + (/app/data/tokens.db for Docker) Returns: Alembic Config object configured for the specified database """ - # Get path to alembic.ini (in project root) - project_root = Path(__file__).parent.parent - alembic_ini_path = project_root / "alembic.ini" + from nextcloud_mcp_server import alembic as alembic_package - if not alembic_ini_path.exists(): - raise FileNotFoundError( - f"alembic.ini not found at {alembic_ini_path}. " - "Ensure Alembic is properly initialized." - ) + # Use package location (works in both editable and installed modes) + if alembic_package.__file__ is None: + raise RuntimeError("alembic package __file__ is None") + script_location = Path(alembic_package.__file__).parent - # Create Alembic config - config = Config(str(alembic_ini_path)) + # Create config programmatically (no alembic.ini needed at runtime) + config = Config() + config.set_main_option("script_location", str(script_location)) + config.set_main_option("path_separator", "os") # Suppress deprecation warning - # Override database URL if provided + # Set database URL if database_path: db_path = Path(database_path).resolve() - # Use sqlite+aiosqlite:// for async support - url = f"sqlite+aiosqlite:///{db_path}" - config.set_main_option("sqlalchemy.url", url) - logger.debug(f"Alembic configured with database: {db_path}") + else: + db_path = Path("/app/data/tokens.db") # Default for Docker + + url = f"sqlite+aiosqlite:///{db_path}" + config.set_main_option("sqlalchemy.url", url) + + logger.debug(f"Alembic script location: {script_location}") + logger.debug(f"Database: {db_path}") return config