Source code for wdae.wgpf

import argparse
import logging
import logging.config
import os
import pathlib
import sys
from typing import cast

import django
from django.conf import settings
from django.core.management import execute_from_command_line
from gpf_instance.gpf_instance import WGPFInstance

from dae import __version__  # type: ignore
from dae.utils.verbosity_configuration import VerbosityConfiguration

logger = logging.getLogger("wgpf")


def _add_gpf_instance_path(parser: argparse.ArgumentParser) -> None:
    parser.add_argument(
        "--gpf-instance", "--gpf", type=str,
        default=None,
        help="Path to GPF instance configuration file. If None, the tool "
        "will check the environment for a 'DAE_DB_DIR' environment variable "
        "and if the variable is set it will use it as a GPF instance dictory. "
        "If 'DAE_DB_DIR' environment variable is not set, then the current "
        "directory and all its parents will be searched for a GPF instance "
        "configuration file `gpf_instance.yaml`")


def _configure_init_subparser(subparsers: argparse._SubParsersAction) -> None:
    parser = subparsers.add_parser(
        "init",
        help="Initialize a GPF Development Web Server for a GPF instance")

    _add_gpf_instance_path(parser)

    parser.add_argument(
        "-f", "--force", default=False,
        action="store_true",
        help="ingore the state of the instance and re-init.")


def _add_host_port_group(parser: argparse.ArgumentParser) -> None:
    group = parser.add_argument_group(
        title="Specify GPF development server host and port")

    group.add_argument(
        "-H", "--host", type=str,
        default="0.0.0.0",
        help="The host IP address on which the GPF development server will "
        "listen for incoming connections.")

    group.add_argument(
        "-P", "--port", type=int,
        default=8000,
        help="The port on which the GPF development server will listen "
        "for incomming connections.")


def _configure_run_subparser(subparsers: argparse._SubParsersAction) -> None:
    parser = subparsers.add_parser(
        "run",
        help="Run a GPF Development Web Server for a GPF instance")
    _add_host_port_group(parser)
    _add_gpf_instance_path(parser)


def _init_flag(wgpf_instance: WGPFInstance) -> pathlib.Path:
    return pathlib.Path(wgpf_instance.dae_dir) / ".wgpf_init.flag"


def _check_is_initialized(wgpf_instance: WGPFInstance) -> bool:
    if not os.path.exists(wgpf_instance.dae_dir):
        return False
    if _init_flag(wgpf_instance).exists():
        return True
    return False


def _run_init_command(
        wgpf_instance: WGPFInstance, **kwargs: str | bool) -> None:
    force = cast(bool, kwargs.pop("force", False))
    if _check_is_initialized(wgpf_instance) and not force:
        logger.error(
            "GPF instance %s already initialized. If you need to re-init "
            "please use '--force' flag.", wgpf_instance.dae_dir)
        sys.exit(0)

    try:
        try:
            execute_from_command_line([
                "wgpf", "migrate",
                "--skip-checks",
            ])
        except SystemExit:
            if not force:
                raise

        try:
            execute_from_command_line([
                "wgpf", "createapplication",
                "public", "authorization-code",
                "--client-id", "gpfjs",
                "--name", "GPF development server",
                "--redirect-uris", "http://localhost:8000/datasets",
                "--skip-checks",
            ])
        except SystemExit:
            if not force:
                raise

    finally:
        _init_flag(wgpf_instance).touch()


def _run_run_command(
        wgpf_instance: WGPFInstance, **kwargs: bool | str) -> None:
    if not _check_is_initialized(wgpf_instance):
        logger.info(
            "GPF instance %s should be initialized first. "
            "Running `wgpf init`...",
            wgpf_instance.dae_dir)
        _run_init_command(wgpf_instance, **kwargs)

    host = kwargs.get("host")
    port = kwargs.get("port")

    try:
        execute_from_command_line([
            "wgpf", "runserver", f"{host}:{port}",
            "--skip-checks",
        ])

    finally:
        pass


[docs] def cli(argv: list[str] | None = None) -> None: """Provide CLI for development GPF web server management.""" if argv is None: argv = sys.argv[:] desc = "GPF Development Web Server Management Tool" parser = argparse.ArgumentParser(description=desc) parser.add_argument( "--version", action="store_true", default=False, help="Prints GPF version and exists.") VerbosityConfiguration.set_arguments(parser) commands_parser = parser.add_subparsers( dest="command", help="Command to execute") _configure_init_subparser(commands_parser) _configure_run_subparser(commands_parser) args = parser.parse_args(argv[1:]) if args.version: print(f"GPF version: {__version__}") sys.exit(0) command = args.command if command is None: logger.error("missing wgpf subcommand") parser.print_help() sys.exit(1) # pylint: disable=import-outside-toplevel from gpf_instance import gpf_instance wgpf_instance = gpf_instance.get_wgpf_instance(args.gpf_instance) logger.info("using GPF instance at %s", wgpf_instance.dae_dir) if command not in {"init", "run"}: logger.error("unknown subcommand %s used in `wgpf`", command) sys.exit(1) os.environ.setdefault("DJANGO_SETTINGS_MODULE", "wdae.gpfjs_settings") django.setup() settings.DISABLE_PERMISSIONS = True settings.STUDIES_EAGER_LOADING = True settings.DEFAULT_WDAE_DIR = os.path.join( wgpf_instance.dae_dir, "wdae") os.makedirs(settings.DEFAULT_WDAE_DIR, exist_ok=True) if args.verbose > 0: settings.LOGGING["handlers"]["console"]["level"] = logging.DEBUG logging.config.dictConfig(settings.LOGGING) logger.info("using wdae directory: %s", settings.DEFAULT_WDAE_DIR) if command == "init": _run_init_command(wgpf_instance, **vars(args)) elif command == "run": _run_run_command(wgpf_instance, **vars(args))