aboutsummaryrefslogtreecommitdiff
path: root/src_py
diff options
context:
space:
mode:
Diffstat (limited to 'src_py')
-rw-r--r--src_py/hatter/backend.py18
-rw-r--r--src_py/hatter/main.py60
-rw-r--r--src_py/hatter/server.py21
-rw-r--r--src_py/hatter/ui.py76
4 files changed, 165 insertions, 10 deletions
diff --git a/src_py/hatter/backend.py b/src_py/hatter/backend.py
new file mode 100644
index 0000000..059c636
--- /dev/null
+++ b/src_py/hatter/backend.py
@@ -0,0 +1,18 @@
+from pathlib import Path
+
+from hat import aio
+
+
+async def create(db_path: Path
+ ) -> 'Backend':
+ backend = Backend()
+ backend._async_group = aio.Group()
+
+ return backend
+
+
+class Backend(aio.Resource):
+
+ @property
+ def async_group(self):
+ return self._async_group
diff --git a/src_py/hatter/main.py b/src_py/hatter/main.py
index f1046a5..1d094b5 100644
--- a/src_py/hatter/main.py
+++ b/src_py/hatter/main.py
@@ -2,18 +2,20 @@ from pathlib import Path
import asyncio
import contextlib
import logging.config
+import subprocess
import sys
import tempfile
import typing
-import subprocess
-
-import appdirs
-import click
from hat import aio
from hat import json
+import appdirs
+import click
from hatter import common
+import hatter.backend
+import hatter.server
+import hatter.ui
user_config_dir: Path = Path(appdirs.user_config_dir('hatter'))
@@ -56,19 +58,36 @@ def main(log_level: str,
@main.command()
@click.argument('url', required=True)
-@click.argument('branch', required=False, default='master')
+@click.argument('commit', required=False, default='master')
@click.argument('action', required=False, default='.hatter.yaml')
def execute(url: str,
- branch: str,
+ commit: str,
action: str):
+ with contextlib.suppress(Exception):
+ path = Path(url)
+ if path.exists():
+ url = str(path.resolve())
+
with tempfile.TemporaryDirectory() as repo_dir:
repo_dir = Path(repo_dir)
- subprocess.run(['git', 'clone', '-q', '--depth', '1',
- '-b', branch, url, str(repo_dir)],
+ subprocess.run(['git', 'init', '-q'],
+ cwd=str(repo_dir),
check=True)
- conf = json.decode_file(repo_dir / '.hatter.yaml')
+ subprocess.run(['git', 'remote', 'add', 'origin', url],
+ cwd=str(repo_dir),
+ check=True)
+
+ subprocess.run(['git', 'fetch', '-q', '--depth=1', 'origin', commit],
+ cwd=str(repo_dir),
+ check=True)
+
+ subprocess.run(['git', 'checkout', '-q', commit],
+ cwd=str(repo_dir),
+ check=True)
+
+ conf = json.decode_file(repo_dir / action)
common.json_schema_repo.validate('hatter://action.yaml#', conf)
image = conf['image']
@@ -107,7 +126,28 @@ async def async_server(host: str,
port: int,
conf: json.Data,
db_path: Path):
- pass
+ async_group = aio.Group()
+
+ try:
+ backend = await hatter.backend.create(db_path)
+ _bind_resource(async_group, backend)
+
+ server = await hatter.server.create(conf, backend)
+ _bind_resource(async_group, server)
+
+ ui = await hatter.ui.create(host, port, server)
+ _bind_resource(async_group, ui)
+
+ await async_group.wait_closing()
+
+ finally:
+ await aio.uncancellable(async_group.async_close())
+
+
+def _bind_resource(async_group, resource):
+ async_group.spawn(aio.call_on_cancel, resource.async_close)
+ async_group.spawn(aio.call_on_done, resource.wait_closing(),
+ async_group.close)
if __name__ == '__main__':
diff --git a/src_py/hatter/server.py b/src_py/hatter/server.py
new file mode 100644
index 0000000..f9ee29f
--- /dev/null
+++ b/src_py/hatter/server.py
@@ -0,0 +1,21 @@
+from hat import aio
+from hat import json
+
+import hatter.backend
+
+
+async def create(conf: json.Data,
+ backend: hatter.backend.Backend
+ ) -> 'Server':
+ server = Server()
+ server._backend = backend
+ server._async_group = aio.Group()
+
+ return server
+
+
+class Server(aio.Resource):
+
+ @property
+ def async_group(self):
+ return self._async_group
diff --git a/src_py/hatter/ui.py b/src_py/hatter/ui.py
new file mode 100644
index 0000000..525df6b
--- /dev/null
+++ b/src_py/hatter/ui.py
@@ -0,0 +1,76 @@
+from pathlib import Path
+
+from hat import aio
+import aiohttp.web
+
+from hatter import common
+import hatter.server
+
+
+static_dir: Path = common.package_path / 'ui'
+
+
+async def create(host: str,
+ port: int,
+ server: hatter.server.Server
+ ) -> 'UI':
+ ui = UI()
+ ui._server = server
+ ui._async_group = aio.Group()
+
+ app = aiohttp.web.Application()
+ app.add_routes([
+ aiohttp.web.get('/', ui._get_root_handler),
+ aiohttp.web.get('/repo/{repo}', server._get_repo_handler),
+ aiohttp.web.get('/repo/{repo}/commit/{commit}',
+ server._get_commit_handler),
+ aiohttp.web.post('/repo/{repo}/webhook',
+ server._post_webhook_handler),
+ aiohttp.web.post('/repo/{repo}/commit/{commit}/run',
+ server._post_run_handler),
+ aiohttp.web.post('/repo/{repo}/commit/{commit}/remove',
+ server._post_remove_handler),
+ aiohttp.web.static('/', static_dir)])
+
+ runner = aiohttp.web.AppRunner(app)
+ await runner.setup()
+ ui.async_group.spawn(aio.call_on_cancel, runner.cleanup)
+
+ try:
+ site = aiohttp.web.TCPSite(runner=runner,
+ host=host,
+ port=port,
+ shutdown_timeout=0.1,
+ reuse_address=True)
+ await site.start()
+
+ except BaseException:
+ await aio.uncancellable(ui.async_group.async_close())
+ raise
+
+ return ui
+
+
+class UI(aio.Resource):
+
+ @property
+ def async_group(self):
+ return self._async_group
+
+ async def _get_root_handler(self, request):
+ pass
+
+ async def _get_repo_handler(self, request):
+ pass
+
+ async def _get_commit_handler(self, request):
+ pass
+
+ async def _post_webhook_handler(self, request):
+ pass
+
+ async def _post_run_handler(self, request):
+ pass
+
+ async def _post_remove_handler(self, request):
+ pass