diff --git a/tools/normalize_acl.py b/tools/normalize_acl.py new file mode 100755 index 0000000000..d8c9b4297c --- /dev/null +++ b/tools/normalize_acl.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python + +# Usage: normalize_acl.py acl.config [transformation [transformation [...]]] +# +# Transformations: +# 0 - dry run (default, print to stdout rather than modifying file in place) +# 1 - strip/condense whitespace and sort (implied by any other transformation) +# 2 - get rid of unneeded create on refs/tags +# 3 - remove any project.stat{e,us} = active since it's a default or a typo +# 4 - strip default *.owner = group Administrators permissions +# 5 - sort the exclusiveGroupPermissions group lists + +import re +import sys + +aclfile = sys.argv[1] + +try: + transformations = sys.argv[2:] +except KeyError: + transformations = [] + + +def tokens(data): + """Human-order comparison + + This handles embedded positive and negative integers, for sorting + strings in a more human-friendly order.""" + data = data.replace('.', ' ').split() + for n in range(len(data)): + try: + data[n] = int(data[n]) + except ValueError: + pass + return data + + +acl = {} +out = '' + +if '0' in transformations or not transformations: + dry_run = True +else: + dry_run = False + +aclfd = open(aclfile) +for line in aclfd: + # condense whitespace to single spaces and get rid of leading/trailing + line = re.sub('\s+', ' ', line).strip() + # skip empty lines + if not line: + continue + # this is a section heading + if line.startswith('['): + section = line.strip(' []') + # use a list for this because some options can have the same "key" + acl[section] = [] + # key=value lines + elif '=' in line: + acl[section].append(line) + # WTF + else: + raise Exception('Unrecognized line!') +aclfd.close() + +if '2' in transformations: + try: + acl['access "refs/tags/*"'] = [ + x for x in acl['access "refs/tags/*"'] + if not x.startswith('create = ')] + except KeyError: + pass + +if '3' in transformations: + try: + acl['project'] = [x for x in acl['project'] if x not in + ('state = active', 'status = active')] + except KeyError: + pass + +if '4' in transformations: + for section in acl.keys(): + acl[section] = [x for x in acl[section] if x != + 'owner = group Administrators'] + +if '5' in transformations: + for section in acl.keys(): + newsection = [] + for option in acl[section]: + key, value = [x.strip() for x in option.split('=')] + if key == 'exclusiveGroupPermissions': + newsection.append('%s = %s' % ( + key, ' '.join(sorted(value.split())))) + else: + newsection.append(option) + acl[section] = newsection + +for section in sorted(acl.keys()): + if acl[section]: + out += '\n[%s]\n' % section + for option in sorted(acl[section], key=tokens): + out += '%s\n' % option + +if dry_run: + print(out[1:-1]) +else: + aclfd = open(aclfile, 'w') + aclfd.write(out[1:]) + aclfd.close()