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