Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(747)

Unified Diff: pylib/gyp/input.py

Issue 664253005: Simplify and optimize FindCycles (Closed) Base URL: https://chromium.googlesource.com/external/gyp.git@master
Patch Set: Rebase Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pylib/gyp/input_test.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pylib/gyp/input.py
diff --git a/pylib/gyp/input.py b/pylib/gyp/input.py
index bb853a5408ecf7c93bd38524e4d962438e63a51c..4f07eaaab15df95b51711a6f0a771b4ced8969f5 100644
--- a/pylib/gyp/input.py
+++ b/pylib/gyp/input.py
@@ -1556,26 +1556,25 @@ class DependencyGraphNode(object):
return list(flat_list)
- def FindCycles(self, path=None):
+ def FindCycles(self):
"""
Returns a list of cycles in the graph, where each cycle is its own list.
"""
- if path is None:
- path = [self]
-
results = []
- for node in self.dependents:
- if node in path:
- cycle = [node]
- for part in path:
- cycle.append(part)
- if part == node:
- break
- results.append(tuple(cycle))
- else:
- results.extend(node.FindCycles([node] + path))
+ visited = set()
- return list(set(results))
+ def Visit(node, path):
+ for child in node.dependents:
+ if child in path:
+ results.append([child] + path[:path.index(child) + 1])
+ elif not child in visited:
+ visited.add(child)
+ Visit(child, [child] + path)
+
+ visited.add(self)
+ Visit(self, [self])
+
+ return results
def DirectDependencies(self, dependencies=None):
"""Returns a list of just direct dependencies."""
@@ -1792,12 +1791,22 @@ def BuildDependencyList(targets):
flat_list = root_node.FlattenToList()
# If there's anything left unvisited, there must be a circular dependency
- # (cycle). If you need to figure out what's wrong, look for elements of
- # targets that are not in flat_list.
+ # (cycle).
if len(flat_list) != len(targets):
+ if not root_node.dependents:
+ # If all targets have dependencies, add the first target as a dependent
+ # of root_node so that the cycle can be discovered from root_node.
+ target = targets.keys()[0]
+ target_node = dependency_nodes[target]
+ target_node.dependencies.append(root_node)
+ root_node.dependents.append(target_node)
+
+ cycles = []
+ for cycle in root_node.FindCycles():
+ paths = [node.ref for node in cycle]
+ cycles.append('Cycle: %s' % ' -> '.join(paths))
raise DependencyGraphNode.CircularException(
- 'Some targets not reachable, cycle in dependency graph detected: ' +
- ' '.join(set(flat_list) ^ set(targets)))
+ 'Cycles in dependency graph detected:\n' + '\n'.join(cycles))
return [dependency_nodes, flat_list]
@@ -1847,20 +1856,18 @@ def VerifyNoGYPFileCircularDependencies(targets):
# If there's anything left unvisited, there must be a circular dependency
# (cycle).
if len(flat_list) != len(dependency_nodes):
- bad_files = []
- for file in dependency_nodes.iterkeys():
- if not file in flat_list:
- bad_files.append(file)
- common_path_prefix = os.path.commonprefix(dependency_nodes)
+ if not root_node.dependents:
+ # If all files have dependencies, add the first file as a dependent
+ # of root_node so that the cycle can be discovered from root_node.
+ file_node = dependency_nodes.values()[0]
+ file_node.dependencies.append(root_node)
+ root_node.dependents.append(file_node)
cycles = []
for cycle in root_node.FindCycles():
- simplified_paths = []
- for node in cycle:
- assert(node.ref.startswith(common_path_prefix))
- simplified_paths.append(node.ref[len(common_path_prefix):])
- cycles.append('Cycle: %s' % ' -> '.join(simplified_paths))
- raise DependencyGraphNode.CircularException, \
- 'Cycles in .gyp file dependency graph detected:\n' + '\n'.join(cycles)
+ paths = [node.ref for node in cycle]
+ cycles.append('Cycle: %s' % ' -> '.join(paths))
+ raise DependencyGraphNode.CircularException(
+ 'Cycles in .gyp file dependency graph detected:\n' + '\n'.join(cycles))
def DoDependentSettings(key, flat_list, targets, dependency_nodes):
« no previous file with comments | « no previous file | pylib/gyp/input_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698