From cc4ba3b063f14943579ffbfe416828590f70ae0a Mon Sep 17 00:00:00 2001 From: "bozo.kopic" Date: Tue, 22 Mar 2022 01:31:27 +0100 Subject: WIP major rewrite --- src_py/hatter/main.py | 189 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 115 insertions(+), 74 deletions(-) (limited to 'src_py/hatter/main.py') diff --git a/src_py/hatter/main.py b/src_py/hatter/main.py index 71245a2..f1046a5 100644 --- a/src_py/hatter/main.py +++ b/src_py/hatter/main.py @@ -1,74 +1,115 @@ -import sys -import asyncio -import argparse -import pdb -import yaml -import logging.config -import atexit -import pkg_resources -import pathlib - -import hatter.json_validator -from hatter import util -from hatter.backend import Backend -from hatter.server import create_web_server - - -def main(): - args = _create_parser().parse_args() - - with open(args.conf, encoding='utf-8') as conf_file: - conf = yaml.safe_load(conf_file) - hatter.json_validator.validate(conf, 'hatter://server.yaml#') - - if 'log' in conf: - logging.config.dictConfig(conf['log']) - - if args.web_path: - web_path = args.web_path - else: - atexit.register(pkg_resources.cleanup_resources) - web_path = pkg_resources.resource_filename('hatter', 'web') - - util.run_until_complete_without_interrupt(async_main(conf, web_path)) - - -async def async_main(conf, web_path): - backend = None - web_server = None - try: - backend = Backend(pathlib.Path(conf.get('db_path', 'hatter.db')), - conf['repositories']) - web_server = await create_web_server( - backend, conf.get('host', '0.0.0.0'), conf.get('port', 24000), - conf.get('webhook_path', '/webhook'), web_path) - await asyncio.Future() - except asyncio.CancelledError: - pass - except Exception as e: - pdb.set_trace() - raise - finally: - if web_server: - await web_server.async_close() - if backend: - await backend.async_close() - await asyncio.sleep(0.5) - - -def _create_parser(): - parser = argparse.ArgumentParser(prog='hatter') - parser.add_argument( - '--web-path', default=None, metavar='path', dest='web_path', - help="web ui directory path") - - named_arguments = parser.add_argument_group('required named arguments') - named_arguments.add_argument( - '-c', '--conf', required=True, metavar='path', dest='conf', - help='configuration path') - - return parser - - -if __name__ == '__main__': - sys.exit(main()) +from pathlib import Path +import asyncio +import contextlib +import logging.config +import sys +import tempfile +import typing +import subprocess + +import appdirs +import click + +from hat import aio +from hat import json + +from hatter import common + + +user_config_dir: Path = Path(appdirs.user_config_dir('hatter')) +user_data_dir: Path = Path(appdirs.user_data_dir('hatter')) + +default_conf_path: Path = user_config_dir / 'server.yaml' +default_db_path: Path = user_data_dir / 'hatter.db' + +ssh_key_path: typing.Optional[Path] = None + + +@click.group() +@click.option('--log-level', + default='INFO', + type=click.Choice(['CRITICAL', 'ERROR', 'WARNING', 'INFO', + 'DEBUG', 'NOTSET']), + help="log level") +@click.option('--ssh-key', default=None, metavar='PATH', type=Path, + help="private key used for ssh authentication") +def main(log_level: str, + ssh_key: typing.Optional[Path]): + global ssh_key_path + ssh_key_path = ssh_key + + logging.config.dictConfig({ + 'version': 1, + 'formatters': { + 'console': { + 'format': "[%(asctime)s %(levelname)s %(name)s] %(message)s"}}, + 'handlers': { + 'console': { + 'class': 'logging.StreamHandler', + 'formatter': 'console', + 'level': log_level}}, + 'root': { + 'level': log_level, + 'handlers': ['console']}, + 'disable_existing_loggers': False}) + + +@main.command() +@click.argument('url', required=True) +@click.argument('branch', required=False, default='master') +@click.argument('action', required=False, default='.hatter.yaml') +def execute(url: str, + branch: str, + action: str): + with tempfile.TemporaryDirectory() as repo_dir: + repo_dir = Path(repo_dir) + + subprocess.run(['git', 'clone', '-q', '--depth', '1', + '-b', branch, url, str(repo_dir)], + check=True) + + conf = json.decode_file(repo_dir / '.hatter.yaml') + common.json_schema_repo.validate('hatter://action.yaml#', conf) + + image = conf['image'] + command = conf['command'] + subprocess.run(['podman', 'run', '-i', '--rm', + '-v', f'{repo_dir}:/hatter', + image, '/bin/sh'], + input=f'set -e\ncd /hatter\n{command}\n', + encoding='utf-8', + check=True) + + +@main.command() +@click.option('--host', default='0.0.0.0', + help="listening host name (default 0.0.0.0)") +@click.option('--port', default=24000, type=int, + help="listening TCP port (default 24000)") +@click.option('--conf', default=default_conf_path, metavar='PATH', type=Path, + help="configuration defined by hatter://server.yaml# " + "(default $XDG_CONFIG_HOME/hatter/server.yaml)") +@click.option('--db', default=default_db_path, metavar='PATH', type=Path, + help="sqlite database path " + "(default $XDG_CONFIG_HOME/hatter/hatter.db") +def server(host: str, + port: int, + conf: Path, + db: Path): + conf = json.decode_file(conf) + common.json_schema_repo.validate('hatter://server.yaml#', conf) + + with contextlib.suppress(asyncio.CancelledError): + aio.run_asyncio(async_server(host, port, conf, db)) + + +async def async_server(host: str, + port: int, + conf: json.Data, + db_path: Path): + pass + + +if __name__ == '__main__': + sys.argv[0] = 'hatter' + main() -- cgit v1.2.3-70-g09d2