aboutsummaryrefslogtreecommitdiff
path: root/src_py/hatter/main.py
blob: f1046a52a953bc368c2d987feaf26b2edf0b5de8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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()