246:f31fc5c409e1
Anton Shestakov <av6@dwimlabs.net>, Wed, 26 Oct 2016 18:42:45 +0800
viewer: add <link type="alternate"> element for atom feed

next change 314:a3c2e221cadf
previous change 145:9c65d66fcda1

incoming.py

Permissions: -rwxr-xr-x

Other formats: Feeds:
#!/usr/bin/env python
from __future__ import absolute_import
import logging
import re
import sys
from argparse import ArgumentParser, FileType
from urlparse import urlparse
from tornado.escape import json_encode
from candolint.models import database, Project, Change, Check
from candolint.utils import parse_timestamp, rel
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'^(?P<filename>.+):(?P<line_number>\d+):\d+: ', line)
if m is not None:
item['filename'] = m.group('filename')
item['line_number'] = int(m.group('line_number'))
item['link_start'] = m.start('filename')
item['link_end'] = m.end('line_number')
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'),
# luacheck
(r'^\(E\d{3}\)', 'error'),
(r'^\(W\d{3}\)', 'warning'),
# jshint
(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):
meta_prefix = '# C&O '
state = None
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:
line = line.rstrip('\r\n')
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
item['cls'] = 'failure'
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))
state = None
m = re.match('^project URL: (\S+)$', rest)
if m is not None:
url = m.group(1)
m = re.match('^commit: (?:(\d+):)?(\w+)$', rest)
if m is not None:
rev = m.group(1)
node = m.group(2)
m = re.match('^commit branch: (.+)$', rest)
if m is not None:
branch = m.group(1)
m = re.match('^commit ref names:.* HEAD -> (\S+)(, |$)', rest)
if m is not None:
branch = m.group(1)
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)
if state is not None:
item['task'] = state
result.append(item)
if not url or not node or not branch:
return
domain, user, name = parse_project_url(url)
with database.transaction():
project, created = Project.manual_upsert(
url=url,
domain=domain,
user=user,
name=name)
change, created = Change.manual_upsert(
rev=rev,
node=node,
branch=branch,
date=date,
author=author,
message=message,
project=project)
Check.create(
ordinal=Check.get_next_ordinal(project),
errors=errors,
warnings=warnings,
lines=json_encode(result),
success=success,
started=started,
finished=finished,
project=project,
change=change)
def main():
parser = ArgumentParser()
parser.add_argument(
'file', type=FileType('r'), nargs='?', default=sys.stdin,
help='file to read from (if - or not specified, read from stdin)')
parser.add_argument(
'-d', '--debug', action='store_true',
help='enable debugging output')
args = parser.parse_args()
database.init(rel('database.sqlite'))
database.connect()
database.create_tables([Project, Change, Check], safe=True)
if args.debug:
logger = logging.getLogger('peewee')
logger.setLevel(logging.DEBUG)
logger.addHandler(logging.StreamHandler())
insert_check(args.file)
database.close()
if __name__ == '__main__':
main()