Anton Shestakov <av6@dwimlabs.net>, Tue, 28 Jun 2016 18:52:52 +0800
viewer: setup and clone tasks without errors/warnings are collapsed by default
In addition to errors and warnings, which leave task expanded, target line also
does the same, so sharing a link to a specific line doesn't surprise people by
hiding the line somewhere.
viewer.py
Permissions: -rwxr-xr-x
from __future__ import absolute_import, division from peewee import DoesNotExist from tornado.escape import json_decode from tornado.ioloop import IOLoop from tornado.options import define, options from tornado.web import Application, HTTPError, RequestHandler, URLSpec from tornado.web import ErrorHandler as BaseErrorHandler from candolint import uimodules from candolint.models import database, Project, Change, Check rel = lambda *x: os.path.abspath(os.path.join(os.path.dirname(__file__), *x)) define('listen', metavar='IP', default='127.0.0.1') define('port', metavar='PORT', default=8033, type=int) define('xheaders', metavar='True|False', default=False, type=bool) define('debug', metavar='True|False', default=False, type=bool) def get_or_404(query, *args, **kwargs): return query.get(*args, **kwargs) class BaseHandler(RequestHandler): super(BaseHandler, self).prepare() if not database.is_closed(): def write_error(self, status_code, **kwargs): if self.settings.get('serve_traceback'): fexc = traceback.format_exception(*kwargs['exc_info']) data['debug_message'] = '\n'.join(fexc) self.render('404.html', **data) self.render('500.html', **data) class IndexHandler(BaseHandler): .select(Check, Project, Change) .group_by(Check.project)) self.render('index.html', checks=checks) class ProjectHandler(BaseHandler): def get(self, domain, user, name): pq = Project.select().where( Project.domain == domain, Project.user == (user if user != '-' else None), .where(Check.project == project) self.render('project.html', project=project, checks=checks) class CheckHandler(BaseHandler): def get(self, domain, user, name, check_num): pq = Project.select().where( Project.domain == domain, Project.user == (user if user != '-' else None), if check_num == 'latest': check = get_or_404(Check, project=project) check = get_or_404(Check, project=project, ordinal=check_num) lines = json_decode(check.lines) self.render('check.html', project=project, check=check, lines=lines) class StatusHandler(BaseHandler): def get(self, domain, user, name): pq = Project.select().where( Project.domain == domain, Project.user == (user if user != '-' else None), check = get_or_404(Check, project=project) parts = [('#555', 30, 14.5, 'lint')] parts.append(('#777', 62, 30.5, 'unknown')) elif check.errors or check.warnings: msg = self.locale.translate('{} error', '{} errors', check.errors) text = msg.format(check.errors) width = 7 + 6 * len(text) + 7 parts.append(('#da314b', width, width // 2 - 0.5, text)) msg = self.locale.translate('{} warning', '{} warnings', check.warnings) text = msg.format(check.warnings) width = 7 + 6 * len(text) + 9 parts.append(('#faa732', width, width // 2 + 0.5, text)) parts.append(('#8cc14c', 40, 19.5, 'none')) width = sum(p[1] for p in parts) self.set_header('Content-Type', 'image/svg+xml; charset=utf-8') self.render('status.svg', width=width, parts=parts, height=20) class ErrorHandler(BaseHandler, BaseErrorHandler): class CandolintViewer(Application): URLSpec(r'/', IndexHandler), URLSpec(r'/([.a-z0-9_-]+)/([^/]+)/([^/]+)', ProjectHandler), URLSpec(r'/([.a-z0-9_-]+)/([^/]+)/([^/]+)/([\d]+|latest)', CheckHandler), URLSpec(r'/([.a-z0-9_-]+)/([^/]+)/([^/]+)/status\.svg', StatusHandler), URLSpec(r'.*', ErrorHandler, {'status_code': 404}) static_path=rel('static'), template_path=rel('templates'), super(CandolintViewer, self).__init__(handlers, **settings) logging.getLogger('peewee').setLevel(logging.DEBUG) database.init(rel('database.sqlite')) def listen(self, port, address='', **kwargs): name = self.__class__.__name__ logging.info('%s is serving on %s:%d', name, address, port) super(CandolintViewer, self).listen(port, address, **kwargs) options.parse_command_line() application = CandolintViewer() application.listen(options.port, address=options.listen, xheaders=options.xheaders) IOLoop.instance().start() if __name__ == '__main__':