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 54:53e3c39fff13
previous change 52:e1ca1959db76

checker.py

Permissions: -rwxr-xr-x

Other formats: Feeds:
#!/usr/bin/env python -u
from __future__ import print_function
import os
from argparse import ArgumentParser, FileType
from datetime import datetime
from shutil import rmtree
from subprocess import check_call, check_output, CalledProcessError
from tempfile import mkdtemp
import yaml
def run_ignore_codes(fn, args, codes):
try:
return fn(args)
except CalledProcessError as e:
if e.returncode not in codes:
raise
return e.output
def run(args, silent=False, get_output=False, ignore_codes=None):
if get_output:
fn = check_output
else:
fn = check_call
try:
if not silent:
print('$ ' + ' '.join(args))
if ignore_codes:
result = run_ignore_codes(fn, args, ignore_codes)
else:
result = fn(args)
if get_output:
return result
else:
return True
except Exception as e:
print('# C&O error: {}'.format(e))
print('# C&O job failed')
return False
def now():
return datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S+00:00')
def execute(config):
ok = True
print('# C&O job started: {}'.format(now()))
tmp = mkdtemp(prefix='candolint.')
os.chdir(tmp)
print('# C&O task: clone')
print('# C&O project URL: {}'.format(config['url']))
source = './source'
if ok and not run(['hg', 'clone', config['url'], source]):
ok = False
if ok:
print('$ cd {}'.format(source))
os.chdir(source)
if ok and not run(['hg', 'sum']):
ok = False
if ok:
template = (r'# C&O commit: {rev}:{node} {branch}\n'
r'# C&O commit date: {date|isodatesec}\n'
r'# C&O commit author: {author|person}\n'
r'# C&O commit message: {desc|firstline}\n')
if not run(['hg', 'log', '-r', '.', '-T', template], silent=True):
ok = False
if ok:
print('# C&O task: setup')
venv = '../venv'
run(['virtualenv', venv])
pip = os.path.join(venv, 'bin', 'pip')
for linter in config['linters']:
if 'pip' in linter:
if not run([pip, 'install'] + linter['pip']):
ok = False
break
if ok:
print('# C&O task: checks')
for linter in config['linters']:
if 'cmd' not in linter or 'files' not in linter:
continue
cmd = ['hg', 'files', 'set:' + ' or '.join(linter['files'])]
files = run(cmd, silent=True, get_output=True, ignore_codes=(1,))
if files is False:
ok = False
break
for f in files.splitlines():
if 'pip' in linter:
cmd = [os.path.join(venv, 'bin', linter['cmd'])]
if not run(cmd + linter.get('flags', []) + [f], ignore_codes=(1,)):
ok = False
break
print('# C&O task: cleanup')
rmtree(tmp)
print('# C&O job finished: {}'.format(now()))
def bad_exit():
print('# C&O job failed (exception not caught)')
print('# C&O job finished: {}'.format(now()))
def main():
parser = ArgumentParser()
parser.add_argument('config', help='configuration file (YAML)', type=FileType('r'))
args = parser.parse_args()
config = yaml.safe_load(args.config)
try:
execute(config)
except:
bad_exit()
if __name__ == '__main__':
main()