diff options
author | ncteisen <ncteisen@gmail.com> | 2017-12-11 18:09:31 -0800 |
---|---|---|
committer | ncteisen <ncteisen@gmail.com> | 2017-12-11 18:10:00 -0800 |
commit | 5f8bf79bbf4915b928f75c83c66592b1fa97657e (patch) | |
tree | 38753ccc2a25774e87c27cd0af185e3d7c8cbe0a /tools/mkowners | |
parent | 888093c6ed0d24eed699173b5fb35235fe7a6069 (diff) |
yapf tools
Diffstat (limited to 'tools/mkowners')
-rwxr-xr-x | tools/mkowners/mkowners.py | 312 |
1 files changed, 161 insertions, 151 deletions
diff --git a/tools/mkowners/mkowners.py b/tools/mkowners/mkowners.py index e0ad998bdc..d8b3d3c332 100755 --- a/tools/mkowners/mkowners.py +++ b/tools/mkowners/mkowners.py @@ -24,10 +24,8 @@ import subprocess # Find the root of the git tree # -git_root = (subprocess - .check_output(['git', 'rev-parse', '--show-toplevel']) - .decode('utf-8') - .strip()) +git_root = (subprocess.check_output(['git', 'rev-parse', '--show-toplevel']) + .decode('utf-8').strip()) # # Parse command line arguments @@ -36,19 +34,22 @@ git_root = (subprocess default_out = os.path.join(git_root, '.github', 'CODEOWNERS') argp = argparse.ArgumentParser('Generate .github/CODEOWNERS file') -argp.add_argument('--out', '-o', - type=str, - default=default_out, - help='Output file (default %s)' % default_out) +argp.add_argument( + '--out', + '-o', + type=str, + default=default_out, + help='Output file (default %s)' % default_out) args = argp.parse_args() # # Walk git tree to locate all OWNERS files # -owners_files = [os.path.join(root, 'OWNERS') - for root, dirs, files in os.walk(git_root) - if 'OWNERS' in files] +owners_files = [ + os.path.join(root, 'OWNERS') for root, dirs, files in os.walk(git_root) + if 'OWNERS' in files +] # # Parse owners files @@ -57,39 +58,40 @@ owners_files = [os.path.join(root, 'OWNERS') Owners = collections.namedtuple('Owners', 'parent directives dir') Directive = collections.namedtuple('Directive', 'who globs') + def parse_owners(filename): - with open(filename) as f: - src = f.read().splitlines() - parent = True - directives = [] - for line in src: - line = line.strip() - # line := directive | comment - if not line: continue - if line[0] == '#': continue - # it's a directive - directive = None - if line == 'set noparent': - parent = False - elif line == '*': - directive = Directive(who='*', globs=[]) - elif ' ' in line: - (who, globs) = line.split(' ', 1) - globs_list = [glob - for glob in globs.split(' ') - if glob] - directive = Directive(who=who, globs=globs_list) - else: - directive = Directive(who=line, globs=[]) - if directive: - directives.append(directive) - return Owners(parent=parent, - directives=directives, - dir=os.path.relpath(os.path.dirname(filename), git_root)) - -owners_data = sorted([parse_owners(filename) - for filename in owners_files], - key=operator.attrgetter('dir')) + with open(filename) as f: + src = f.read().splitlines() + parent = True + directives = [] + for line in src: + line = line.strip() + # line := directive | comment + if not line: continue + if line[0] == '#': continue + # it's a directive + directive = None + if line == 'set noparent': + parent = False + elif line == '*': + directive = Directive(who='*', globs=[]) + elif ' ' in line: + (who, globs) = line.split(' ', 1) + globs_list = [glob for glob in globs.split(' ') if glob] + directive = Directive(who=who, globs=globs_list) + else: + directive = Directive(who=line, globs=[]) + if directive: + directives.append(directive) + return Owners( + parent=parent, + directives=directives, + dir=os.path.relpath(os.path.dirname(filename), git_root)) + + +owners_data = sorted( + [parse_owners(filename) for filename in owners_files], + key=operator.attrgetter('dir')) # # Modify owners so that parented OWNERS files point to the actual @@ -98,24 +100,24 @@ owners_data = sorted([parse_owners(filename) new_owners_data = [] for owners in owners_data: - if owners.parent == True: - best_parent = None - best_parent_score = None - for possible_parent in owners_data: - if possible_parent is owners: continue - rel = os.path.relpath(owners.dir, possible_parent.dir) - # '..' ==> we had to walk up from possible_parent to get to owners - # ==> not a parent - if '..' in rel: continue - depth = len(rel.split(os.sep)) - if not best_parent or depth < best_parent_score: - best_parent = possible_parent - best_parent_score = depth - if best_parent: - owners = owners._replace(parent = best_parent.dir) - else: - owners = owners._replace(parent = None) - new_owners_data.append(owners) + if owners.parent == True: + best_parent = None + best_parent_score = None + for possible_parent in owners_data: + if possible_parent is owners: continue + rel = os.path.relpath(owners.dir, possible_parent.dir) + # '..' ==> we had to walk up from possible_parent to get to owners + # ==> not a parent + if '..' in rel: continue + depth = len(rel.split(os.sep)) + if not best_parent or depth < best_parent_score: + best_parent = possible_parent + best_parent_score = depth + if best_parent: + owners = owners._replace(parent=best_parent.dir) + else: + owners = owners._replace(parent=None) + new_owners_data.append(owners) owners_data = new_owners_data # @@ -123,106 +125,114 @@ owners_data = new_owners_data # a CODEOWNERS file for GitHub # + def full_dir(rules_dir, sub_path): - return os.path.join(rules_dir, sub_path) if rules_dir != '.' else sub_path + return os.path.join(rules_dir, sub_path) if rules_dir != '.' else sub_path + # glob using git gg_cache = {} + + def git_glob(glob): - global gg_cache - if glob in gg_cache: return gg_cache[glob] - r = set(subprocess - .check_output(['git', 'ls-files', os.path.join(git_root, glob)]) - .decode('utf-8') - .strip() - .splitlines()) - gg_cache[glob] = r - return r + global gg_cache + if glob in gg_cache: return gg_cache[glob] + r = set( + subprocess.check_output( + ['git', 'ls-files', os.path.join(git_root, glob)]).decode('utf-8') + .strip().splitlines()) + gg_cache[glob] = r + return r + def expand_directives(root, directives): - globs = collections.OrderedDict() - # build a table of glob --> owners - for directive in directives: - for glob in directive.globs or ['**']: - if glob not in globs: - globs[glob] = [] - if directive.who not in globs[glob]: - globs[glob].append(directive.who) - # expand owners for intersecting globs - sorted_globs = sorted(globs.keys(), - key=lambda g: len(git_glob(full_dir(root, g))), - reverse=True) - out_globs = collections.OrderedDict() - for glob_add in sorted_globs: - who_add = globs[glob_add] - pre_items = [i for i in out_globs.items()] - out_globs[glob_add] = who_add.copy() - for glob_have, who_have in pre_items: - files_add = git_glob(full_dir(root, glob_add)) - files_have = git_glob(full_dir(root, glob_have)) - intersect = files_have.intersection(files_add) - if intersect: - for f in sorted(files_add): # sorted to ensure merge stability - if f not in intersect: - out_globs[os.path.relpath(f, start=root)] = who_add - for who in who_have: - if who not in out_globs[glob_add]: - out_globs[glob_add].append(who) - return out_globs + globs = collections.OrderedDict() + # build a table of glob --> owners + for directive in directives: + for glob in directive.globs or ['**']: + if glob not in globs: + globs[glob] = [] + if directive.who not in globs[glob]: + globs[glob].append(directive.who) + # expand owners for intersecting globs + sorted_globs = sorted( + globs.keys(), + key=lambda g: len(git_glob(full_dir(root, g))), + reverse=True) + out_globs = collections.OrderedDict() + for glob_add in sorted_globs: + who_add = globs[glob_add] + pre_items = [i for i in out_globs.items()] + out_globs[glob_add] = who_add.copy() + for glob_have, who_have in pre_items: + files_add = git_glob(full_dir(root, glob_add)) + files_have = git_glob(full_dir(root, glob_have)) + intersect = files_have.intersection(files_add) + if intersect: + for f in sorted(files_add): # sorted to ensure merge stability + if f not in intersect: + out_globs[os.path.relpath(f, start=root)] = who_add + for who in who_have: + if who not in out_globs[glob_add]: + out_globs[glob_add].append(who) + return out_globs + def add_parent_to_globs(parent, globs, globs_dir): - if not parent: return - for owners in owners_data: - if owners.dir == parent: - owners_globs = expand_directives(owners.dir, owners.directives) - for oglob, oglob_who in owners_globs.items(): - for gglob, gglob_who in globs.items(): - files_parent = git_glob(full_dir(owners.dir, oglob)) - files_child = git_glob(full_dir(globs_dir, gglob)) - intersect = files_parent.intersection(files_child) - gglob_who_orig = gglob_who.copy() - if intersect: - for f in sorted(files_child): # sorted to ensure merge stability - if f not in intersect: - who = gglob_who_orig.copy() - globs[os.path.relpath(f, start=globs_dir)] = who - for who in oglob_who: - if who not in gglob_who: - gglob_who.append(who) - add_parent_to_globs(owners.parent, globs, globs_dir) - return - assert(False) + if not parent: return + for owners in owners_data: + if owners.dir == parent: + owners_globs = expand_directives(owners.dir, owners.directives) + for oglob, oglob_who in owners_globs.items(): + for gglob, gglob_who in globs.items(): + files_parent = git_glob(full_dir(owners.dir, oglob)) + files_child = git_glob(full_dir(globs_dir, gglob)) + intersect = files_parent.intersection(files_child) + gglob_who_orig = gglob_who.copy() + if intersect: + for f in sorted(files_child + ): # sorted to ensure merge stability + if f not in intersect: + who = gglob_who_orig.copy() + globs[os.path.relpath(f, start=globs_dir)] = who + for who in oglob_who: + if who not in gglob_who: + gglob_who.append(who) + add_parent_to_globs(owners.parent, globs, globs_dir) + return + assert (False) + todo = owners_data.copy() done = set() with open(args.out, 'w') as out: - out.write('# Auto-generated by the tools/mkowners/mkowners.py tool\n') - out.write('# Uses OWNERS files in different modules throughout the\n') - out.write('# repository as the source of truth for module ownership.\n') - written_globs = [] - while todo: - head, *todo = todo - if head.parent and not head.parent in done: - todo.append(head) - continue - globs = expand_directives(head.dir, head.directives) - add_parent_to_globs(head.parent, globs, head.dir) - for glob, owners in globs.items(): - skip = False - for glob1, owners1, dir1 in reversed(written_globs): - files = git_glob(full_dir(head.dir, glob)) - files1 = git_glob(full_dir(dir1, glob1)) - intersect = files.intersection(files1) - if files == intersect: - if sorted(owners) == sorted(owners1): - skip = True # nothing new in this rule - break - elif intersect: - # continuing would cause a semantic change since some files are - # affected differently by this rule and CODEOWNERS is order dependent - break - if not skip: - out.write('/%s %s\n' % ( - full_dir(head.dir, glob), ' '.join(owners))) - written_globs.append((glob, owners, head.dir)) - done.add(head.dir) + out.write('# Auto-generated by the tools/mkowners/mkowners.py tool\n') + out.write('# Uses OWNERS files in different modules throughout the\n') + out.write('# repository as the source of truth for module ownership.\n') + written_globs = [] + while todo: + head, *todo = todo + if head.parent and not head.parent in done: + todo.append(head) + continue + globs = expand_directives(head.dir, head.directives) + add_parent_to_globs(head.parent, globs, head.dir) + for glob, owners in globs.items(): + skip = False + for glob1, owners1, dir1 in reversed(written_globs): + files = git_glob(full_dir(head.dir, glob)) + files1 = git_glob(full_dir(dir1, glob1)) + intersect = files.intersection(files1) + if files == intersect: + if sorted(owners) == sorted(owners1): + skip = True # nothing new in this rule + break + elif intersect: + # continuing would cause a semantic change since some files are + # affected differently by this rule and CODEOWNERS is order dependent + break + if not skip: + out.write('/%s %s\n' % (full_dir(head.dir, glob), + ' '.join(owners))) + written_globs.append((glob, owners, head.dir)) + done.add(head.dir) |