diff --git a/flaschengeist/cli/__init__.py b/flaschengeist/cli/__init__.py index 493dcfd..945a80b 100644 --- a/flaschengeist/cli/__init__.py +++ b/flaschengeist/cli/__init__.py @@ -1,10 +1,5 @@ -import pathlib -import subprocess import click -from os import environ -from flask import current_app -from flask.cli import FlaskGroup, run_command, with_appcontext -import pkg_resources +from flask.cli import FlaskGroup, with_appcontext from flaschengeist.app import create_app from flaschengeist.config import configure_logger @@ -63,98 +58,14 @@ def cli(): pass -@cli.command() -@with_appcontext -def install(): - """Install and initialize enabled plugins. +def main(*args, **kwargs): + from .plugin_cmd import plugin + from .export_cmd import export + from .docs_cmd import docs + from .run_cmd import run - Most plugins need to install custom tables into the database - running this command will lookup all enabled plugins and run - their database initalization routines. - """ - from flaschengeist.app import install_all - - install_all() - - -@cli.command() -@click.option("--output", "-o", help="Output file, default is stdout", type=click.Path()) -@click.option("--namespace", "-n", help="TS namespace for the interfaces", type=str, show_default=True) -@click.option("--plugin", "-p", help="Also export types for a plugin (even if disabled)", multiple=True, type=str) -@click.option("--no-core", help="Skip models / types from flaschengeist core", is_flag=True) -def export(namespace, output, no_core, plugin): - from flaschengeist import models - from flaschengeist import logger - from .InterfaceGenerator import InterfaceGenerator - - gen = InterfaceGenerator(namespace, output, logger) - if not no_core: - gen.run(models) - if plugin: - for entry_point in pkg_resources.iter_entry_points("flaschengeist.plugins"): - if len(plugin) == 0 or entry_point.name in plugin: - plg = entry_point.load() - if hasattr(plg, "models") and plg.models is not None: - gen.run(plg.models) - gen.write() - - -@cli.command() -@click.option("--host", help="set hostname to listen on", default="127.0.0.1", show_default=True) -@click.option("--port", help="set port to listen on", type=int, default=5000, show_default=True) -@click.option("--debug", help="run in debug mode", is_flag=True) -@with_appcontext -@click.pass_context -def run(ctx, host, port, debug): - """Run Flaschengeist using a development server.""" - - class PrefixMiddleware(object): - def __init__(self, app, prefix=""): - self.app = app - self.prefix = prefix - - def __call__(self, environ, start_response): - - if environ["PATH_INFO"].startswith(self.prefix): - environ["PATH_INFO"] = environ["PATH_INFO"][len(self.prefix) :] - environ["SCRIPT_NAME"] = self.prefix - return self.app(environ, start_response) - else: - start_response("404", [("Content-Type", "text/plain")]) - return ["This url does not belong to the app.".encode()] - - from flaschengeist.config import config - - # re configure logger, as we are no logger in CLI mode - configure_logger() - current_app.wsgi_app = PrefixMiddleware(current_app.wsgi_app, prefix=config["FLASCHENGEIST"].get("root", "")) - if debug: - environ["FLASK_DEBUG"] = "1" - environ["FLASK_ENV"] = "development" - - ctx.invoke(run_command, host=host, port=port, debugger=debug) - - -@cli.command() -@click.option( - "--output", - "-o", - help="Documentation output path", - default="./docs", - type=click.Path(file_okay=False, path_type=pathlib.Path), -) -def docs(output: pathlib.Path): - """Generate and export API documentation using pdoc3""" - output.mkdir(parents=True, exist_ok=True) - command = [ - "python", - "-m", - "pdoc", - "--skip-errors", - "--html", - "--output-dir", - str(output), - "flaschengeist", - ] - click.echo(f"Running command: {command}") - subprocess.check_call(command) + cli.add_command(plugin) + cli.add_command(export) + cli.add_command(docs) + cli.add_command(run) + cli(*args, **kwargs) diff --git a/flaschengeist/cli/docs_cmd.py b/flaschengeist/cli/docs_cmd.py new file mode 100644 index 0000000..54faf02 --- /dev/null +++ b/flaschengeist/cli/docs_cmd.py @@ -0,0 +1,38 @@ +import click +import pathlib +import subprocess + + +@click.command() +@click.option( + "--output", + "-o", + help="Documentation output path", + default="./docs", + type=click.Path(file_okay=False, path_type=pathlib.Path), +) +@click.pass_context +def docs(ctx: click.Context, output: pathlib.Path): + """Generate and export API documentation using pdoc""" + import pkg_resources + + try: + pkg_resources.get_distribution("pdoc>=8.0.1") + except pkg_resources.DistributionNotFound: + click.echo( + f"Error: pdoc was not found, maybe you need to install it. Try:\n" "\n" '$ pip install "pdoc>=8.0.1"\n' + ) + ctx.exit(1) + output.mkdir(parents=True, exist_ok=True) + command = [ + "python", + "-m", + "pdoc", + "--docformat", + "google", + "--output-directory", + str(output), + "flaschengeist", + ] + click.echo(f"Running command: {command}") + subprocess.check_call(command) diff --git a/flaschengeist/cli/export_cmd.py b/flaschengeist/cli/export_cmd.py new file mode 100644 index 0000000..6f93c70 --- /dev/null +++ b/flaschengeist/cli/export_cmd.py @@ -0,0 +1,21 @@ +import click + + +@click.command() +@click.option("--output", "-o", help="Output file, default is stdout", type=click.Path()) +@click.option("--namespace", "-n", help="TS namespace for the interfaces", type=str, show_default=True) +@click.option("--plugin", "-p", help="Also export types for a plugin (even if disabled)", multiple=True, type=str) +@click.option("--no-core", help="Skip models / types from flaschengeist core", is_flag=True) +def export(namespace, output, no_core, plugin): + from flaschengeist import logger, models + from flaschengeist.app import get_plugins + from .InterfaceGenerator import InterfaceGenerator + + gen = InterfaceGenerator(namespace, output, logger) + if not no_core: + gen.run(models) + if plugin: + for plugin_class in get_plugins(): + if (len(plugin) == 0 or plugin_class.id in plugin) and plugin_class.models is not None: + gen.run(plugin_class.models) + gen.write() diff --git a/flaschengeist/cli/run_cmd.py b/flaschengeist/cli/run_cmd.py new file mode 100644 index 0000000..5f0eec3 --- /dev/null +++ b/flaschengeist/cli/run_cmd.py @@ -0,0 +1,40 @@ +import click +from os import environ +from flask import current_app +from flask.cli import with_appcontext, run_command + + +class PrefixMiddleware(object): + def __init__(self, app, prefix=""): + self.app = app + self.prefix = prefix + + def __call__(self, environ, start_response): + + if environ["PATH_INFO"].startswith(self.prefix): + environ["PATH_INFO"] = environ["PATH_INFO"][len(self.prefix) :] + environ["SCRIPT_NAME"] = self.prefix + return self.app(environ, start_response) + else: + start_response("404", [("Content-Type", "text/plain")]) + return ["This url does not belong to the app.".encode()] + + +@click.command() +@click.option("--host", help="set hostname to listen on", default="127.0.0.1", show_default=True) +@click.option("--port", help="set port to listen on", type=int, default=5000, show_default=True) +@click.option("--debug", help="run in debug mode", is_flag=True) +@with_appcontext +@click.pass_context +def run(ctx, host, port, debug): + """Run Flaschengeist using a development server.""" + from flaschengeist.config import config, configure_logger + + # re configure logger, as we are no logger in CLI mode + configure_logger() + current_app.wsgi_app = PrefixMiddleware(current_app.wsgi_app, prefix=config["FLASCHENGEIST"].get("root", "")) + if debug: + environ["FLASK_DEBUG"] = "1" + environ["FLASK_ENV"] = "development" + + ctx.invoke(run_command, host=host, port=port, debugger=debug) diff --git a/setup.cfg b/setup.cfg index 6d533e9..31cb338 100644 --- a/setup.cfg +++ b/setup.cfg @@ -44,7 +44,7 @@ mysql = [options.entry_points] console_scripts = - flaschengeist = flaschengeist.cli:cli + flaschengeist = flaschengeist.cli:main flask.commands = ldap = flaschengeist.plugins.auth_ldap.cli:ldap users = flaschengeist.plugins.users.cli:users