aboutsummaryrefslogtreecommitdiff
path: root/scripts/maint/checkIncludes.py
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2019-08-05 11:49:52 -0400
committerNick Mathewson <nickm@torproject.org>2019-08-05 13:40:59 -0400
commit65a69f861e192ae77c7edafe46bc2674bc39b9ea (patch)
treecb054f7a725cf0ffdc7d6f7d50e80e40c346f127 /scripts/maint/checkIncludes.py
parent3f35ac772b0428e77c93968fdfc6f4add1c9f15d (diff)
downloadtor-65a69f861e192ae77c7edafe46bc2674bc39b9ea.tar.gz
tor-65a69f861e192ae77c7edafe46bc2674bc39b9ea.zip
checkIncludes.py: extract topological sort code
Our topological sort code really deserves a function of its own. Additionally, don't print from inside the topological sort code: instead, return a result, and let the caller print it.
Diffstat (limited to 'scripts/maint/checkIncludes.py')
-rwxr-xr-xscripts/maint/checkIncludes.py67
1 files changed, 50 insertions, 17 deletions
diff --git a/scripts/maint/checkIncludes.py b/scripts/maint/checkIncludes.py
index a67397bfaa..c4e77c71e7 100755
--- a/scripts/maint/checkIncludes.py
+++ b/scripts/maint/checkIncludes.py
@@ -139,6 +139,50 @@ def load_include_rules(fname):
include_rules_cache[fname] = result
return result
+def remove_self_edges(graph):
+ """Takes a directed graph in as an adjacency mapping (a mapping from
+ node to a list of the nodes to which it connects).
+
+ Remove all edges from a node to itself."""
+
+ for k in list(graph):
+ graph[k] = [ d for d in graph[k] if d != k ]
+
+def toposort(graph, limit=100):
+ """Takes a directed graph in as an adjacency mapping (a mapping from
+ node to a list of the nodes to which it connects). Tries to
+ perform a topological sort on the graph, arranging the nodes into
+ "levels", such that every member of each level is only reachable
+ by members of later levels.
+
+ Returns a list of the members of each level.
+
+ Modifies the input graph, removing every member that could be
+ sorted. If the graph does not become empty, then it contains a
+ cycle.
+
+ "limit" is the max depth of the graph after which we give up trying
+ to sort it and conclude we have a cycle.
+ """
+ all_levels = []
+
+ n = 0
+ while graph:
+ n += 0
+ cur_level = []
+ all_levels.append(cur_level)
+ for k in list(graph):
+ graph[k] = [ d for d in graph[k] if d in graph ]
+ if graph[k] == []:
+ cur_level.append(k)
+ for k in cur_level:
+ del graph[k]
+ n += 1
+ if n > limit:
+ break
+
+ return all_levels
+
if __name__ == '__main__':
list_unused = False
log_sorted_levels = False
@@ -162,24 +206,13 @@ if __name__ == '__main__':
files in its enclosing directory.""".format(RULES_FNAME))
sys.exit(1)
- all_levels = []
+ remove_self_edges(uses_dirs)
+ all_levels = toposort(uses_dirs)
- n = 0
- while uses_dirs:
- n += 0
- cur_level = []
- for k in list(uses_dirs):
- uses_dirs[k] = [ d for d in uses_dirs[k]
- if (d in uses_dirs and d != k)]
- if uses_dirs[k] == []:
- cur_level.append(k)
- for k in cur_level:
- del uses_dirs[k]
- n += 1
- if cur_level and log_sorted_levels:
- print(n, cur_level)
- if n > 100:
- break
+ if log_sorted_levels:
+ for (n, cur_level) in enumerate(all_levels):
+ if cur_level:
+ print(n, cur_level)
if uses_dirs:
print("There are circular .may_include dependencies in here somewhere:",