53:ed7f35f52927
Anton Shestakov <av6@dwimlabs.net>, Thu, 23 Jun 2016 14:58:09 +0800
checker: try and catch exceptions from execute() and somewhat finish the job Exceptions coming from execute() are programming errors in checker.py, but jobs still need to tell that they are finished (and failed) to be processed by incoming.py.

next change 61:0d94aa1eb6c7
previous change 51:0552f5ca41a3

incoming.py

Permissions: -rwxr-xr-x

Other formats: Feeds:
#!/usr/bin/env python
from __future__ import absolute_import
import fileinput
import logging
import os
import re
from datetime import datetime
from urlparse import urlparse
from tornado.escape import json_encode
from candolint.models import database, Project, Change, Check
rel = lambda *x: os.path.abspath(os.path.join(os.path.dirname(__file__), *x))
def parse_timestamp(value):
return datetime.strptime(value, '%Y-%m-%dT%H:%M:%S+00:00')
def parse_project_url(url):
parsed = urlparse(url)
domain = parsed.hostname
if domain is None:
domain = 'self'
parts = [part for part in parsed.path.split('/') if part]
if len(parts) > 1:
user = parts[0]
name = '/'.join(parts[1:])
else:
user = None
name = parts[0]
return domain, user, name
def match_linter_output(line):
errors = 0
warnings = 0
item = {}
m = re.match(r'^(.+):(\d+):\d+: ', line)
if m is not None:
item['filename'] = m.group(1)
item['fileline'] = int(m.group(2))
rest = line[m.end():]
patterns = (
# pep8-specific E9xx
# https://pep8.readthedocs.io/en/latest/intro.html#error-codes
(r'^E9\d{2}', 'error'),
(r'^[EWFCN]\d{3}', 'warning'),
(r'^\[error\]', 'error'),
(r'^\[warning\]', 'warning'),
(r'^\(E\d{3}\)', 'error'),
(r'^\(W\d{3}\)', 'warning'),
)
for regex, cls in patterns:
m = re.match(regex, rest)
if m is not None:
item['cls'] = cls
if cls == 'error':
errors += 1
elif cls == 'warning':
warnings += 1
break
else:
warnings += 1
item['cls'] = 'warning'
return errors, warnings, item
def insert_check(lines):
text = ''.join(lines)
meta_prefix = '# C&O '
state = 'not even started'
result = []
errors = 0
warnings = 0
url = None
rev = None
node = None
branch = None
date = None
author = None
message = None
success = True
started = None
finished = None
for line in lines:
item = {'text': line}
if line.startswith(meta_prefix):
item['cls'] = 'meta'
rest = line[len(meta_prefix):]
m = re.match('^task: (\w+)$', rest)
if m is not None:
state = m.group(1)
item['cls'] = 'task'
m = re.match('^job failed$', rest)
if m is not None:
success = False
m = re.match('^job (started|finished): ([\dT:+-]+)$', rest)
if m is not None:
if m.group(1) == 'started':
started = parse_timestamp(m.group(2))
elif m.group(1) == 'finished':
finished = parse_timestamp(m.group(2))
m = re.match('^project URL: (\S+)$', rest)
if m is not None:
url = m.group(1)
m = re.match('^commit: (\d+):(\w+) (\w+)$', rest)
if m is not None:
rev = m.group(1)
node = m.group(2)
branch = m.group(3)
m = re.match('^commit date: (.+)$', rest)
if m is not None:
date = m.group(1)
m = re.match('^commit author: (.+)$', rest)
if m is not None:
author = m.group(1)
m = re.match('^commit message: (.+)$', rest)
if m is not None:
message = m.group(1)
elif state == 'checks':
de, dw, extra = match_linter_output(line)
errors += de
warnings += dw
item.update(extra)
result.append(item)
domain, user, name = parse_project_url(url)
with database.transaction():
project, created = Project.create_or_get(
url=url,
domain=domain,
user=user,
name=name)
change, created = Change.create_or_get(
rev=rev,
node=node,
branch=branch,
date=date,
author=author,
message=message,
project=project)
Check.create(
ordinal=Check.select().where(Check.project == project).count() + 1,
errors=errors,
warnings=warnings,
raw=text,
lines=json_encode(result),
success=success,
started=started,
finished=finished,
project=project,
change=change)
def main():
database.init(rel('database.sqlite'))
database.connect()
database.create_tables([Project, Change, Check], safe=True)
logger = logging.getLogger('peewee')
logger.setLevel(logging.DEBUG)
logger.addHandler(logging.StreamHandler())
insert_check(list(fileinput.input()))
database.close()
if __name__ == '__main__':
main()