#!/usr/bin/python -tt import argparse import koji import os import re import sys import traceback from collections import namedtuple SigEntry = namedtuple('SigEntry', ['cbstag', 'localdir', 'remotedir', 'desturl']) KOJI_URL = 'https://cbs.centos.org/kojihub/' WARNING = "WARNING: {0}: {1} {2}" ERROR = "ERROR: {0}: {1} {2}" TAGREGEX = r'(?P<signame>\w+)(?P<centosversion>\d)-(.*)-(?P<releasestage>candidate|testing|release)$' MIRRORREGEX = r'(?P<centosversion>\d)/(?P<signame>\w+)/(?P<sigstructure>.*)' def main(files=[]): kojiclient = koji.ClientSession(KOJI_URL) tags = [x.get('name') for x in kojiclient.listTags()] for filename in files: print '='*10 + ' Linting: {0} '.format(filename) + '='*10 with open(filename) as thefile: lines = thefile.readlines() for lineno,line in enumerate(map(str.strip, lines)): if line.startswith('#'): continue se = SigEntry(*line.split('|')) # Check that we put the right tags in the right list (testing -> buildlogs, release -> sign) # and that the CentOS Version matches for all the URLs try: gs = re.match(TAGREGEX, se.cbstag.strip('/')).groupdict() if gs['releasestage'] == 'release' and 'buildlogs' in filename: msg = 'release tag in buildlogs list' raise AssertionError if gs['releasestage'] == 'testing' and 'sign' in filename: msg = 'testing tag in sign list' raise AssertionError for attr in ['localdir','remotedir','desturl']: are = re.match(MIRRORREGEX, se._asdict()[attr]).groupdict() if are['centosversion'] != gs['centosversion']: msg = 'version location of {0} does not match the CentOS Version of the CBS tag'.format(attr) raise AssertionError except AttributeError, e: msg = 'bad cbs tag!' print e print(ERROR.format(filename+':'+str(lineno), se.cbstag.strip('/'), msg)) sys.exit(-1) except AssertionError, e: msg = msg or "Unkown error" print(WARNING.format(filename+':'+str(lineno), se.cbstag.strip('/'), msg)) continue # Check that we have trailing slashes for the path components so that RSYNC is happy try: for attr in ['cbstag','localdir','remotedir','desturl']: assert(se._asdict()[attr].endswith('/')) except AssertionError, e: msg = '{} is missing trailing slash!'.format(attr) print(WARNING.format(filename+':'+str(lineno), se.cbstag.strip('/'), msg)) continue try: assert(se.cbstag.strip('/') in tags) except AssertionError, e: print(ERROR.format(filename+':'+str(lineno), se.cbstag.strip('/'), 'CBS Tag does not exist!')) sys.exit(-1) # Check to be sure all the tags have RPMs in them try: builds = kojiclient.getLatestBuilds(se.cbstag.strip('/')) assert(len(builds) > 0) except AssertionError, e: print(ERROR.format(str(lineno), se.cbstag.strip('/'), 'No RPMS in tag!')) sys.exit(-1) if __name__ == '__main__': parser = argparse.ArgumentParser(description="Check the content control entries for sanity. If called without arguments, cclint will look in the current directory for any files named *_list") parser.add_argument('files', metavar='content-control-file', type=str, nargs="*", help="the file to check", default=filter(lambda x: '_list' in x, os.listdir('.')) ) args = parser.parse_args() main(args.files)