Files
3cloud-backend/core/manage.py
JamesBhattarai 7fea4a5bcc Chore: Move services into core
- Move app/, worker/, websocket_server/, migrations/, tests and the services to core/, which becomes a self-contained root
- .gitmodules path for the novnc submodule rewritten by git mv.
- Initial Step to split into core and cloud/community
2026-08-17 22:15:19 +05:45

153 lines
4.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
xCloudify management commands.
Provides Click-based helpers around Flask-Migrate so you can initialise,
autogenerate and apply migrations without dragging every model into the
production WSGI process.
Usage examples
--------------
$ python manage.py migrations:init
$ python manage.py migrations:generate -m "add bar column"
$ python manage.py migrations:apply
$ python3 bootstrap_db.py
# Starting from scratch
rm -rf migrations/
python manage.py migrations:init
python manage.py migrations:generate -m "First"
python manage.py migrations:apply
python3 bootstrap_db.py
"""
import logging
from pathlib import Path
import pkgutil
from importlib import import_module
import click
from flask.cli import with_appcontext
from flask_migrate import (init as alembic_init,
migrate as alembic_migrate,
upgrade as alembic_upgrade,
downgrade as alembic_downgrade,
current as alembic_current,
history as alembic_history,
stamp as alembic_stamp)
# Importing the Flask application *after* logging is configured
from app import app, db # pylint: disable=wrong-import-position
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# --------------------------------------------------------------------------- #
# Helper – import all model modules only when a migration command runs #
# --------------------------------------------------------------------------- #
def _import_models() -> None:
"""
Dynamically import every module in ``app.models`` so that
``db.metadata`` is fully populated for Alembic.
This is **not** executed by the production WSGI server – only by
the CLI commands below, keeping live workers lightweight.
"""
models_directory: Path = Path("app") / "models"
logger.info(f"Models dir: {models_directory}")
for module_info in pkgutil.iter_modules([str(models_directory)]):
import_module(f"app.models.{module_info.name}")
logger.info(f"Imported {module_info.name}")
logger.info("All model modules imported for migration command.")
# --------------------------------------------------------------------------- #
# CLI setup with Click #
# --------------------------------------------------------------------------- #
@click.group()
def command_line_interface():
"""Root group for xCloudify helper commands."""
pass
@command_line_interface.command("migrations:init")
@with_appcontext
def init_migrations() -> None:
"""
Create the *migrations* directory and stamp the current head.
Safe to call repeatedly – it no-ops if the directory exists.
"""
_import_models()
migrations_directory: Path = Path("migrations")
if migrations_directory.exists():
logger.info("Migrations directory already exists at %s", migrations_directory)
else:
logger.info("Creating migrations directory at %s", migrations_directory)
alembic_init()
alembic_stamp(revision="head")
logger.info("Directory initialised and stamped to current head.")
@command_line_interface.command("migrations:generate")
@click.option(
"--message", "-m",
default="schema update",
help="Message to attach to the migration revision."
)
@with_appcontext
def generate_migration(message: str) -> None:
"""
Autogenerate a migration script from model changes.
"""
_import_models()
logger.info("Generating migration: %s", message)
alembic_migrate(message=message)
logger.info("Migration script created.")
@command_line_interface.command("migrations:apply")
@with_appcontext
def apply_migrations() -> None:
"""
Apply all unapplied migrations.
"""
logger.info("Applying migrations to database …")
alembic_upgrade()
logger.info("Database schema is now up-to-date.")
@command_line_interface.command("migrations:current")
@with_appcontext
def current_migration() -> None:
"""
Show the current applied migration revision.
"""
alembic_current(verbose=True)
@command_line_interface.command("migrations:history")
@with_appcontext
def migration_history() -> None:
"""
Show the full migration history.
"""
alembic_history(verbose=True)
@command_line_interface.command("migrations:downgrade")
@click.option("--revision", "-r", required=True, help="Revision to downgrade to, e.g. -r -1 (one step back) or -r <revision-id>")
@with_appcontext
def downgrade_migration(revision: str) -> None:
"""
Downgrade to a previous migration revision.
"""
logger.info("Downgrading to revision: %s", revision)
alembic_downgrade(revision=revision)
logger.info("Downgrade complete.")
if __name__ == "__main__":
command_line_interface()