Anton Shestakov <av6@dwimlabs.net>, Thu, 04 Aug 2016 14:16:22 +0800
bench: an awful typo that invalidates the whole stcp mark
viewer.py
Permissions: -rwxr-xr-x
from collections import OrderedDict from subprocess import check_output, Popen, PIPE from urllib import quote_plus from tornado.escape import xhtml_escape from tornado.ioloop import IOLoop from tornado.options import define, options from tornado.web import Application, RequestHandler from settings import DBPATH, HG, TEMPLATES, TESTHGREPO 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) if ':' in rev or '..' in rev: if re.search(r'(?<!rev)\(.*\)', rev) is not None: output = check_output([HG, 'log', '-R', TESTHGREPO, '-T', 'json', '-r', revset]) return json.loads(output) def showuser(user, short=False, domainre=re.compile(r'@[^ >]+')): user = domainre.sub('@...', user) return user.partition(' <')[0] return ','.join(quote_plus(i, '(),') for i in params) items = sorted(kwargs.items()) return '&'.join(quote_plus(k) + '=' + joinparams(v) for k, v in items) class BaseHandler(RequestHandler): self.conn = sqlite3.connect(DBPATH) super(BaseHandler, self).prepare() class IndexHandler(BaseHandler): self.redirect('results.html') class ResultsHandler(BaseHandler): def get(self, page, ext): if self.check_etag_header(): dbmt = os.stat(DBPATH).st_mtime changelog = os.path.join(TESTHGREPO, '.hg', 'store', '00changelog.i') repomt = os.stat(changelog).st_mtime return 'W/"{},{}"'.format(dbmt, repomt) chosen = self.get_argument('marks', None) chosen = chosen.split(',') marks = OrderedDict((mark, MARKS[mark]) for mark in chosen if mark in MARKS) moremarks = OrderedDict((mark, desc) for mark, desc in MARKS.items() if mark not in chosen) rev = self.get_argument('rev', 'tip') revset = 'reverse({})'.format(rev) revset = '{}:0'.format(rev, revcount) return getinfo('first({}, {})'.format(revset, revcount)) def getlimits(self, marks, changesets=None): 'SELECT MIN(time), MAX(time) FROM results' ' WHERE mark = ? AND cache = ?') query += ' AND node IN (' + ','.join('?' * len(changesets)) + ')' extra = [cset['node'] for cset in changesets] self.conn.execute(query, [mark, False] + extra).fetchone() self.conn.execute(query, [mark, True] + extra).fetchone() def getresults(self, changesets, marks, local=False, colors=True): limits = self.getlimits(marks, changesets if local else None) resultsq = self.conn.execute( 'SELECT node, mark, time, cache FROM results' ' WHERE node IN (' + ','.join('?' * len(changesets)) + ')' ' AND mark IN (' + ','.join('?' * len(marks)) + ')', [cset['node'] for cset in changesets] + marks.keys()) for node, mark, time, cache in resultsq: results.setdefault(node, {}).setdefault(mark, [None, None, None, None]) color = green_to_red(limits[mark][0:2], time) if time is not None else None results[node][mark][0:2] = [time, color] color = green_to_red(limits[mark][2:4], time) if time is not None else None results[node][mark][2:4] = [time, color] if colors and color not in colormap: colormap[color] = 'c{}'.format(len(colormap)) self.set_header('Content-Type', 'text/plain; charset=UTF-8') changesets = self.getchangesets() marks, _ = self.getmarks() results, _ = self.getresults(changesets, marks, colors=False) self.write('\t{0} (without cache)\t{0} (with cache)'.format(mark)) self.write('{rev}\t{node}'.format(**cset)) values = results.get(cset['node'], {}).get(mark, ('', '', '')) self.write('\t{0}\t{2}'.format(*values)) self.set_header('Content-Type', 'text/plain; charset=UTF-8') rev = self.get_argument('rev', 'tip') 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({}:0, {})'.format(rev, revcount) cmd = [HG, 'log', '-R', TESTHGREPO, '-G', '-T', template, '-r', revset] graph = Popen(cmd, stdout=PIPE) while graph.poll() is None: line = graph.stdout.readline() matches = regex.findall(line) rows = self.conn.execute( 'SELECT mark, time, cache FROM results WHERE node = ?', for mark, time, cache in rows: matchtimes.setdefault(mark, [None, None]) matchtimes[mark][1 if cache else 0] = time msg.append('{mark}: {0:.2f}s/{1:.2f}s'.format(*matchtimes[mark], mark=mark)) line = line.replace(match, ' '.join(msg)) def setlocal(self, value=None): kwargs = self.request.arguments.copy() kwargs['local'] = [str(value)] return '?' + urlencode(**kwargs) def setrev(self, value=None): kwargs = self.request.arguments.copy() kwargs['rev'] = ['rev({})'.format(value)] return '?' + urlencode(**kwargs) def setmarks(self, marks): def fn(value=None, add=None, remove=None): kwargs = self.request.arguments.copy() kwargs['marks'] = marks.keys() + [add] kwargs['marks'] = [mark for mark in marks if mark != remove] return '?' + urlencode(**kwargs) changesets = self.getchangesets() marks, moremarks = self.getmarks() local = self.get_argument('local', False) results, colormap = self.getresults(changesets, marks, local=local) 'changesets': changesets, 'setlocal': self.setlocal, 'setmarks': self.setmarks(marks), self.render('results.html', **context) changesets = self.getchangesets() marks, moremarks = self.getmarks() results, _ = self.getresults(changesets, marks, colors=False) item = {'rev': -cset['rev']} values = results.get(cset['node'], {}).get(mark, None) extra = [cset['branch']] + cset['tags'] if len(cset['parents']) > 1: 'branch': cset['branch'], 'merge': 'M' if len(cset['parents']) > 1 else '', 'shortnode': cset['node'][:12], 'firstline': xhtml_escape(cset['desc'].partition('\n')[0]) 'keys': {'x': 'rev', 'value': marks.keys()}, 'changesets': changesets, 'setmarks': self.setmarks(marks), self.render('fancy.html', **context) def green_to_red(limits, 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): (r'/(results)\.(html|tsv|asc)', ResultsHandler), (r'/(fancy)\.(html)', ResultsHandler), super(Viewer, self).__init__(handlers, **settings) def listen(self, port, address='', **kwargs): name = self.__class__.__name__ logging.info('%s is serving on http://%s:%d/', name, address, port) super(Viewer, self).listen(port, address, **kwargs) options.parse_command_line() application.listen(options.port, options.listen, xheaders=options.xheaders) if __name__ == '__main__':