1:cb057921cd8c
Anton Shestakov <engored@ya.ru>, Sat, 02 May 2015 01:52:26 +0800
viewer webapp

next change 5:d8052e876798

viewer.py

Permissions: -rwxr-xr-x

Other formats: Feeds:
#!/usr/bin/env python
import colorsys
import json
import logging
import re
import sqlite3
import subprocess
from tornado.ioloop import IOLoop
from tornado.options import define, options
from tornado.web import Application, RequestHandler, URLSpec
from settings import DBPATH, HG, TEMPLATES, TESTHGREPO
from bench import MARKS
define('listen', metavar='IP', default='127.0.0.1')
define('port', metavar='PORT', default=8065, type=int)
define('xheaders', metavar='True|False', default=False, type=bool)
define('debug', metavar='True|False', default=False, type=bool)
def getinfo(revset):
output = subprocess.check_output([HG, 'log', '-R', TESTHGREPO, '-T', 'json', '-r', revset])
return json.loads(output)
class BaseHandler(RequestHandler):
def prepare(self):
self.conn = sqlite3.connect(DBPATH)
super(BaseHandler, self).prepare()
def on_finish(self):
self.conn.close()
class IndexHandler(BaseHandler):
def get(self):
self.redirect('results.html')
class ResultsHandler(BaseHandler):
def get(self, ext):
if ext == 'tsv':
self.results_tsv()
elif ext == 'asc':
self.results_asc()
elif ext == 'html':
self.results_html()
def getdata(self):
rev = self.get_argument('rev', 'tip')
revcount = 120
results = {}
limits = {
mark: self.conn.execute(
'SELECT MIN(time), MAX(time) FROM results WHERE mark = ? AND cache = ?',
(mark, False)).fetchone()
for mark in MARKS
}
changesets = getinfo('first(%s:0, %d)' % (rev, revcount))
for cset in changesets:
node = cset['node']
resultsq = self.conn.execute(
'SELECT mark, time FROM results WHERE node = ? AND cache = ?',
(node, False))
for mark, time in resultsq:
color = green_to_red(limits[mark], time) if time is not None else None
results.setdefault(node, {})[mark] = (time, color)
return changesets, results
def results_tsv(self):
self.set_header('Content-Type', 'text/plain; charset=UTF-8')
changesets, results = self.getdata()
for cset in changesets:
self.write('%(rev)s\t%(node)s\t' % cset)
self.write('\t'.join(
str(results.get(cset['node'], {}).get(mark, ('',))[0])
for mark in MARKS
))
self.write('\n')
self.finish()
def results_asc(self):
self.set_header('Content-Type', 'text/plain; charset=UTF-8')
rev = self.get_argument('rev', 'tip')
revcount = 120
regex = re.compile(r'^[-\\|/+ ]+([0-9a-f]{40})$')
template = '{rev}:{node|short} {tags} {date|isodate} {author|user} {desc|firstline|strip}\n {node}\n\n'
revset = 'first(%s:0, %d)' % (rev, revcount)
cmd = [HG, 'log', '-R', TESTHGREPO, '-G', '-T', template, '-r', revset]
graph = subprocess.Popen(cmd, stdout=subprocess.PIPE)
while graph.poll() is None:
line = graph.stdout.readline()
matches = regex.findall(line)
for match in matches:
msg = []
rows = self.conn.execute('SELECT mark, time FROM results WHERE node = ?', (match,))
for row in rows:
msg.append('{}: {:.2g}s'.format(*row))
line = line.replace(match, ' '.join(msg))
self.write(line)
self.finish()
def results_html(self):
changesets, results = self.getdata()
self.render('results.html', changesets=changesets, marks=MARKS, results=results)
def green_to_red((low, high), value):
hue = (value - low) / (high - low) if high != low else 0.5
r, g, b = colorsys.hsv_to_rgb((1 - hue) * 0.3, 1, 1)
return (int(r * 255), int(g * 255), int(b * 255))
class Viewer(Application):
def __init__(self):
handlers = [
URLSpec(r'/', IndexHandler),
URLSpec(r'/results\.(html|tsv|asc)', ResultsHandler),
]
settings = dict(
template_path=TEMPLATES,
debug=options.debug
)
super(Viewer, self).__init__(handlers, **settings)
def listen(self, port, address='', **kwargs):
logging.info('{} is serving on {}:{}'.format(self.__class__.__name__, address, port))
super(Viewer, self).listen(port, address, **kwargs)
def main():
options.parse_command_line()
application = Viewer()
application.listen(options.port, address=options.listen, xheaders=options.xheaders)
IOLoop.instance().start()
if __name__ == '__main__':
main()