aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rwxr-xr-xplayground/build.sh6
-rw-r--r--requirements.pip.dev.txt2
-rw-r--r--src_doit/__init__.py22
-rw-r--r--src_py/hatter/main.py2
-rw-r--r--src_py/hatter/server.py6
-rw-r--r--src_py/hatter/ui.py80
-rw-r--r--src_scss/main.scss74
8 files changed, 158 insertions, 35 deletions
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'<li><a href="/repo/{repo}">{repo}</a></li>'
for repo in repos)
return (f'<div class="repos">\n'
+ f'<h2>Repositories</h2>\n'
f'<ul>\n'
f'{items}\n'
f'</ul>\n'
@@ -135,6 +162,7 @@ def _generate_commits(commits):
for commit in commits)
return (f'<div class="commits">\n'
+ f'<h2>Commits</h2>\n'
f'<table>\n'
f'<thead>\n'
f'{thead}\n'
@@ -165,6 +193,15 @@ def _generate_commit(commit):
f'</div>')
+def _generate_add(repo):
+ return (f'<div class="add">\n'
+ f'<form method="post" action="/repo/{repo}/add">\n'
+ f'<input type="text" name="hash">\n'
+ f'<input type="submit" value="Add commit">\n'
+ f'</form>\n'
+ f'</div>')
+
+
def _format_time(t):
return datetime.datetime.fromtimestamp(t).strftime("%Y-%m-%d %H:%M:%S")
@@ -173,6 +210,7 @@ _html_template = r"""<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{title}</title>
<link href="/main.css" rel="stylesheet">
</head>
@@ -181,17 +219,3 @@ _html_template = r"""<!DOCTYPE html>
</body>
</html>
"""
-
-_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;
+ }
+}