From 81e0cbc034e594c73a38202afc0676b3522c6b46 Mon Sep 17 00:00:00 2001 From: "bozo.kopic" Date: Sun, 27 Mar 2022 04:28:55 +0200 Subject: WIP server --- .gitignore | 1 + playground/build.sh | 6 ++++ requirements.pip.dev.txt | 2 +- src_doit/__init__.py | 22 +++++++++++-- src_py/hatter/main.py | 2 +- src_py/hatter/server.py | 6 ++-- src_py/hatter/ui.py | 80 +++++++++++++++++++++++++++++++----------------- src_scss/main.scss | 74 ++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 158 insertions(+), 35 deletions(-) create mode 100755 playground/build.sh create mode 100644 src_scss/main.scss diff --git a/.gitignore b/.gitignore index 7d0bb47..a1479d9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.doit.* /build /src_py/hatter/json_schema_repo.json +/src_py/hatter/ui/main.css __pycache__ diff --git a/playground/build.sh b/playground/build.sh new file mode 100755 index 0000000..92f39f8 --- /dev/null +++ b/playground/build.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +. $(dirname -- "$0")/env.sh + +cd $ROOT_PATH +exec $PYTHON -m doit json_schema_repo scss diff --git a/requirements.pip.dev.txt b/requirements.pip.dev.txt index 9af3242..c68f1ae 100644 --- a/requirements.pip.dev.txt +++ b/requirements.pip.dev.txt @@ -3,6 +3,6 @@ build >= 0.7.0 doit >= 0.34.2 flake8 >= 4.0.1 -hat-doit ~= 0.8.1 +hat-doit ~= 0.8.2 setuptools >= 60.10.0 wheel >= 0.37.1 diff --git a/src_doit/__init__.py b/src_doit/__init__.py index 6773485..231061d 100644 --- a/src_doit/__init__.py +++ b/src_doit/__init__.py @@ -9,20 +9,27 @@ from hat.doit.py import (build_wheel, __all__ = ['task_clean_all', 'task_wheel', 'task_check', - 'task_json_schema_repo'] + 'task_json_schema_repo', + 'task_scss'] build_dir = Path('build') src_py_dir = Path('src_py') +src_scss_dir = Path('src_scss') schemas_json_dir = Path('schemas_json') +ui_dir = src_py_dir / 'hatter/ui' + json_schema_repo_path = src_py_dir / 'hatter/json_schema_repo.json' +main_scss_path = src_scss_dir / 'main.scss' +main_css_path = ui_dir / 'main.css' def task_clean_all(): """Clean all""" return {'actions': [(common.rm_rf, [build_dir, - json_schema_repo_path])]} + json_schema_repo_path, + main_css_path])]} def task_wheel(): @@ -40,7 +47,8 @@ def task_wheel(): console_scripts=['hatter = hatter.main:main']) return {'actions': [build], - 'task_dep': ['json_schema_repo']} + 'task_dep': ['json_schema_repo', + 'scss']} def task_check(): @@ -60,3 +68,11 @@ def task_json_schema_repo(): return {'actions': [generate], 'file_dep': src_paths, 'targets': [json_schema_repo_path]} + + +def task_scss(): + """Build SCSS""" + return {'actions': [(common.mkdir_p, [main_css_path.parent]), + (f'sass --no-source-map ' + f'{main_scss_path} {main_css_path}')], + 'targets': [main_css_path]} diff --git a/src_py/hatter/main.py b/src_py/hatter/main.py index 53b2032..c0ca225 100644 --- a/src_py/hatter/main.py +++ b/src_py/hatter/main.py @@ -135,7 +135,7 @@ async def async_server(host: str, server = await hatter.server.create(conf, backend) _bind_resource(async_group, server) - for repo in server.get_repos(): + for repo in server.repos: server.sync_repo(repo) ui = await hatter.ui.create(host, port, server) diff --git a/src_py/hatter/server.py b/src_py/hatter/server.py index 6d37244..5364f52 100644 --- a/src_py/hatter/server.py +++ b/src_py/hatter/server.py @@ -19,6 +19,7 @@ async def create(conf: json.Data, server._conf = conf server._backend = backend server._async_group = aio.Group() + server._repos = set(conf['repos'].keys()) server._lock = asyncio.Lock() server._run_queue = aio.Queue() server._sync_events = {} @@ -57,8 +58,9 @@ class Server(aio.Resource): def async_group(self): return self._async_group - def get_repos(self) -> typing.Iterable[str]: - return self._conf['repos'].keys() + @property + def repos(self) -> typing.Set[str]: + return self._repos async def get_commits(self, repo: typing.Optional[str], diff --git a/src_py/hatter/ui.py b/src_py/hatter/ui.py index 9368d63..cb827bd 100644 --- a/src_py/hatter/ui.py +++ b/src_py/hatter/ui.py @@ -23,15 +23,17 @@ async def create(host: str, get_routes = ( aiohttp.web.get(path, handler) for path, handler in ( ('/', ui._get_root_handler), - ('/main.css', ui._get_style_handler), ('/repo/{repo}', ui._get_repo_handler), ('/repo/{repo}/commit/{commit}', ui._get_commit_handler))) post_routes = ( aiohttp.web.post(path, handler) for path, handler in ( ('/repo/{repo}/webhook', ui._post_webhook_handler), + ('/repo/{repo}/add', ui._post_add_handler), ('/repo/{repo}/commit/{commit}/rerun', ui._post_rerun_handler), ('/repo/{repo}/commit/{commit}/remove', ui._post_remove_handler))) - app.add_routes([*get_routes, *post_routes]) + app.add_routes([*get_routes, + *post_routes, + aiohttp.web.static('/', static_dir)]) runner = aiohttp.web.AppRunner(app) await runner.setup() @@ -59,47 +61,71 @@ class UI(aio.Resource): return self._async_group async def _get_root_handler(self, request): - repos = self._server.get_repos() commits = await self._server.get_commits(None) - body = (f'{_generate_repos(repos)}\n' + + body = (f'{_generate_repos(self._server.repos)}\n' f'{_generate_commits(commits)}') return _create_html_response('hatter', body) - async def _get_style_handler(self, request): - return aiohttp.web.Response(content_type='text/css', - text=_main_css) - async def _get_repo_handler(self, request): - repo = request.match_info['repo'] + repo = _parse_repo(request, self._server.repos) + commits = await self._server.get_commits(repo) - body = _generate_commits(commits) + + body = (f'{_generate_commits(commits)}\n' + f'{_generate_add(repo)}') return _create_html_response(f'hatter - {repo}', body) async def _get_commit_handler(self, request): - repo = request.match_info['repo'] + repo = _parse_repo(request, self._server.repos) + commit_hash = request.match_info['commit'] commit = await self._server.get_commit(repo, commit_hash) + body = _generate_commit(commit) return _create_html_response(f'hatter - {repo}/{commit_hash}', body) async def _post_webhook_handler(self, request): - repo = request.match_info['repo'] + repo = _parse_repo(request, self._server.repos) + self._server.sync_repo(repo) + return aiohttp.web.Response() + async def _post_add_handler(self, request): + repo = _parse_repo(request, self._server.repos) + + body = await request.post() + commit_hash = body['hash'] + if not commit_hash: + raise aiohttp.web.HTTPBadRequest() + + raise aiohttp.web.HTTPFound(f'/repo/{repo}/commit/{commit_hash}') + async def _post_rerun_handler(self, request): - repo = request.match_info['repo'] + repo = _parse_repo(request, self._server.repos) + commit_hash = request.match_info['commit'] await self._server.rerun_commit(repo, commit_hash) + raise aiohttp.web.HTTPFound(f'/repo/{repo}/commit/{commit_hash}') async def _post_remove_handler(self, request): - repo = request.match_info['repo'] + repo = _parse_repo(request, self._server.repos) + commit_hash = request.match_info['commit'] await self._server.remove_commit(repo, commit_hash) + raise aiohttp.web.HTTPFound(f'/repo/{repo}') +def _parse_repo(request, repos): + repo = request.match_info['repo'] + if repo not in repos: + raise aiohttp.web.HTTPBadRequest() + return repo + + def _create_html_response(title, body): text = _html_template.format(title=title, body=body) @@ -111,6 +137,7 @@ def _generate_repos(repos): items = '\n'.join(f'
  • {repo}
  • ' for repo in repos) return (f'
    \n' + f'

    Repositories

    \n' f'\n' @@ -135,6 +162,7 @@ def _generate_commits(commits): for commit in commits) return (f'
    \n' + f'

    Commits

    \n' f'\n' f'\n' f'{thead}\n' @@ -165,6 +193,15 @@ def _generate_commit(commit): f'') +def _generate_add(repo): + return (f'
    \n' + f'
    \n' + f'\n' + f'\n' + f'\n' + f'
    ') + + def _format_time(t): return datetime.datetime.fromtimestamp(t).strftime("%Y-%m-%d %H:%M:%S") @@ -173,6 +210,7 @@ _html_template = r""" +{title} @@ -181,17 +219,3 @@ _html_template = r""" """ - -_main_css = r""" -.repos { - -} - -.commits { - -} - -.commit { - -} -""" diff --git a/src_scss/main.scss b/src_scss/main.scss new file mode 100644 index 0000000..d7d247a --- /dev/null +++ b/src_scss/main.scss @@ -0,0 +1,74 @@ + +$color-grey-50: rgb(250, 250, 250); +$color-grey-100: rgb(245, 245, 245); +$color-grey-200: rgb(238, 238, 238); +$color-grey-300: rgb(224, 224, 224); +$color-grey-400: rgb(189, 189, 189); +$color-grey-500: rgb(158, 158, 158); +$color-grey-600: rgb(117, 117, 117); +$color-grey-700: rgb(97, 97, 97); +$color-grey-800: rgb(66, 66, 66); +$color-grey-900: rgb(33, 33, 33); + + +html, body, button, input { + font-family: sans-serif; + font-size: 12pt; +} + +body { + margin: 1rem auto; + width: 920px; + + .commits { + & > table { + width: 100%; + border: 1px solid $color-grey-500; + border-spacing: 0; + + thead { + background-color: $color-grey-300; + } + + tbody { + td { + border-top: 1px solid $color-grey-500; + } + } + + th, td { + padding: 0.2rem; + } + + .col-change { + width: 12rem; + text-align: center; + } + + .col-status { + width: 7rem; + text-align: center; + } + } + } + + .commit { + display: grid; + grid-template-columns: auto 1fr; + grid-gap: 0.5rem; + + label { + font-weight: 600; + justify-self: right; + } + + form { + display: inline; + } + } + + .add { + margin: 1rem 0; + text-align: right; + } +} -- cgit v1.2.3-70-g09d2