Last active
April 18, 2022 17:58
-
-
Save methylDragon/357080fda22ad73824f42a5288841131 to your computer and use it in GitHub Desktop.
Get topologically sorted level-groups for packages and their dependents on gazebodistro (Place script in gazebodistro root and run)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import yaml | |
| import os | |
| import re | |
| from collections import defaultdict | |
| # PARAMS =========================================================================================== | |
| PATH = "." | |
| BUMP_TARGETS = ["ign-cmake", "ign-tools", "ign-plugin", "ign-utils"] | |
| # PARSE YAMLS ====================================================================================== | |
| os.chdir(PATH) | |
| files = [f for f in os.listdir() if os.path.isfile(f)] | |
| # Get library names and corresponding versions from file-list | |
| lib_re = re.compile("(\D*)(\d+).yaml") | |
| lib_tuples = [ | |
| (f_re.group(1), int(f_re.group(2))) | |
| for f in files | |
| if (f_re := lib_re.match(f)) | |
| ] | |
| # Abuse sorting to get max lib versions | |
| lib_tuples.sort() | |
| max_libs_dict = {lib: "".join((os.path.curdir, "/", lib, str(ver), ".yaml")) | |
| for lib, ver in lib_tuples} | |
| # OBTAIN DEPENDANTS ================================================================================ | |
| dependant_dict = {target: [] for target in BUMP_TARGETS} | |
| for target in BUMP_TARGETS: | |
| for lib, filename in max_libs_dict.items(): | |
| with open(filename, "r") as f: | |
| try: | |
| conf = yaml.safe_load(f) | |
| except yaml.YAMLError as exc: | |
| print(exc) | |
| continue | |
| if target in conf['repositories'].keys(): | |
| dependant_dict[target].append(lib) | |
| dependants = set() # Union of all dependants of all target libraries | |
| for dependant_list in dependant_dict.values(): | |
| dependants.update(dependant_list) | |
| # TOPO SORT UTILS ================================================================================== | |
| class Graph: | |
| def __init__(self, vertex_count): | |
| self.graph = defaultdict(list) # Adjacency List | |
| self.V_num = vertex_count | |
| def add_edge(self,u,v): | |
| self.graph[u].append(v) | |
| def assignlevel(graph, v, level): | |
| """ | |
| Get topological level of vertex. | |
| Source: https://stackoverflow.com/questions/3420685/how-to-assign-levels-to-vertices-of-an-acyclic-directed-graph | |
| Uses the heuristic of longest directed path length. | |
| The highest level is first in topological order! | |
| """ | |
| if v not in level: | |
| if v not in graph or not graph[v]: | |
| level[v] = 1 | |
| else: | |
| level[v] = max(assignlevel(graph, w, level) + 1 for w in graph[v]) | |
| return level[v] | |
| # EXECUTE TOPO SORT ================================================================================ | |
| g = Graph(len(dependants)) | |
| # This dict stores the DOWNSTREAM dependants of each library! | |
| extended_dependant_dict = {parent_dep: [] for parent_dep in dependants} # Deps of deps and targets | |
| for dep in dependants: | |
| for lib, filename in max_libs_dict.items(): | |
| with open(filename, "r") as f: | |
| try: | |
| conf = yaml.safe_load(f) | |
| except yaml.YAMLError as exc: | |
| print(exc) | |
| continue | |
| if dep in conf['repositories'].keys(): | |
| if lib == dep: | |
| continue | |
| extended_dependant_dict[dep].append(lib) | |
| for lib, dependant_list in extended_dependant_dict.items(): | |
| for dependant in dependant_list: | |
| if lib == dependant: | |
| continue | |
| g.add_edge(lib, dependant) | |
| l = {} # Vertex level dict | |
| for v in g.graph: | |
| assignlevel(g.graph, v, l) | |
| topo_groups = [(level, lib) for lib, level in l.items()] | |
| topo_groups.sort() | |
| topo_groups.reverse() | |
| topo_groups | |
| # OUT ============================================================================================== | |
| # The level number of a vertex is the max length of path in the dependency tree starting from it | |
| # Merging PRs from highest level downwards should fix most if not all dependency issues | |
| # | |
| # Vertices on the same level can be merged together | |
| # | |
| # Note: This ordering might not be the most efficient, but it will be safe | |
| # E.g. Merging top level vertices from separate branches would work, but this strategy | |
| # doesn't account for that | |
| topo_group_dict = defaultdict(list) | |
| for level, lib in topo_groups: | |
| topo_group_dict[level].append(lib) | |
| for level, libs in topo_group_dict.items(): | |
| print(level, libs) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment