OLD | NEW |
---|---|
1 # Copyright (c) 2012 Google Inc. All rights reserved. | 1 # Copyright (c) 2012 Google Inc. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 from compiler.ast import Const | 5 from compiler.ast import Const |
6 from compiler.ast import Dict | 6 from compiler.ast import Dict |
7 from compiler.ast import Discard | 7 from compiler.ast import Discard |
8 from compiler.ast import List | 8 from compiler.ast import List |
9 from compiler.ast import Module | 9 from compiler.ast import Module |
10 from compiler.ast import Node | 10 from compiler.ast import Node |
(...skipping 1538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1549 break | 1549 break |
1550 | 1550 |
1551 if is_in_degree_zero: | 1551 if is_in_degree_zero: |
1552 # All of the dependent's dependencies are already in flat_list. Add | 1552 # All of the dependent's dependencies are already in flat_list. Add |
1553 # it to in_degree_zeros where it will be processed in a future | 1553 # it to in_degree_zeros where it will be processed in a future |
1554 # iteration of the outer loop. | 1554 # iteration of the outer loop. |
1555 in_degree_zeros.add(node_dependent) | 1555 in_degree_zeros.add(node_dependent) |
1556 | 1556 |
1557 return list(flat_list) | 1557 return list(flat_list) |
1558 | 1558 |
1559 def FindCycles(self, path=None): | 1559 def FindCycles(self): |
1560 """ | 1560 """ |
1561 Returns a list of cycles in the graph, where each cycle is its own list. | 1561 Returns a list of cycles in the graph, where each cycle is its own list. |
1562 """ | 1562 """ |
1563 if path is None: | 1563 results = [] |
1564 path = [self] | 1564 visited = set() |
1565 | 1565 |
1566 results = [] | 1566 def Visit(node, path): |
1567 for node in self.dependents: | 1567 for child in node.dependents: |
1568 if node in path: | 1568 if child in path: |
1569 cycle = [node] | 1569 results.append(tuple([child] + path[:path.index(child) + 1])) |
scottmg
2014/10/21 02:53:07
Does this have to make a tuple() out of the list?
cjhopman
2014/10/21 18:22:23
Done.
This needed the tuple to convert results to
| |
1570 for part in path: | 1570 elif not child in visited: |
1571 cycle.append(part) | 1571 visited.add(child) |
1572 if part == node: | 1572 Visit(child, [child] + path) |
scottmg
2014/10/21 03:22:42
I'm probably reading this wrong, but... given A->B
cjhopman
2014/10/21 18:22:23
Ehh, I had the same problem. So the key is that th
| |
1573 break | 1573 |
1574 results.append(tuple(cycle)) | 1574 visited.add(self) |
1575 else: | 1575 Visit(self, [self]) |
1576 results.extend(node.FindCycles([node] + path)) | |
1577 | 1576 |
1578 return list(set(results)) | 1577 return list(set(results)) |
1579 | 1578 |
1580 def DirectDependencies(self, dependencies=None): | 1579 def DirectDependencies(self, dependencies=None): |
1581 """Returns a list of just direct dependencies.""" | 1580 """Returns a list of just direct dependencies.""" |
1582 if dependencies == None: | 1581 if dependencies == None: |
1583 dependencies = [] | 1582 dependencies = [] |
1584 | 1583 |
1585 for dependency in self.dependencies: | 1584 for dependency in self.dependencies: |
1586 # Check for None, corresponding to the root node. | 1585 # Check for None, corresponding to the root node. |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1785 dependency_node = dependency_nodes.get(dependency) | 1784 dependency_node = dependency_nodes.get(dependency) |
1786 if not dependency_node: | 1785 if not dependency_node: |
1787 raise GypError("Dependency '%s' not found while " | 1786 raise GypError("Dependency '%s' not found while " |
1788 "trying to load target %s" % (dependency, target)) | 1787 "trying to load target %s" % (dependency, target)) |
1789 target_node.dependencies.append(dependency_node) | 1788 target_node.dependencies.append(dependency_node) |
1790 dependency_node.dependents.append(target_node) | 1789 dependency_node.dependents.append(target_node) |
1791 | 1790 |
1792 flat_list = root_node.FlattenToList() | 1791 flat_list = root_node.FlattenToList() |
1793 | 1792 |
1794 # If there's anything left unvisited, there must be a circular dependency | 1793 # If there's anything left unvisited, there must be a circular dependency |
1795 # (cycle). If you need to figure out what's wrong, look for elements of | 1794 # (cycle). |
1796 # targets that are not in flat_list. | |
1797 if len(flat_list) != len(targets): | 1795 if len(flat_list) != len(targets): |
1798 raise DependencyGraphNode.CircularException( | 1796 cycles = [] |
1799 'Some targets not reachable, cycle in dependency graph detected: ' + | 1797 for cycle in root_node.FindCycles(): |
1800 ' '.join(set(flat_list) ^ set(targets))) | 1798 paths = [] |
1799 for node in cycle: | |
1800 paths.append(node.ref) | |
1801 cycles.append('Cycle: %s' % ' -> '.join(paths)) | |
1802 raise DependencyGraphNode.CircularException, \ | |
scottmg
2014/10/21 02:50:23
Why not CircularException(...)?
cjhopman
2014/10/21 18:22:23
Done.
I just did what was used for raising this b
| |
1803 'Cycles in dependency graph detected:\n' + '\n'.join(cycles) | |
scottmg
2014/10/21 02:50:23
Could you add a test for this improved output form
cjhopman
2014/10/21 18:22:23
Done.
| |
1801 | 1804 |
1802 return [dependency_nodes, flat_list] | 1805 return [dependency_nodes, flat_list] |
1803 | 1806 |
1804 | 1807 |
1805 def VerifyNoGYPFileCircularDependencies(targets): | 1808 def VerifyNoGYPFileCircularDependencies(targets): |
1806 # Create a DependencyGraphNode for each gyp file containing a target. Put | 1809 # Create a DependencyGraphNode for each gyp file containing a target. Put |
1807 # it into a dict for easy access. | 1810 # it into a dict for easy access. |
1808 dependency_nodes = {} | 1811 dependency_nodes = {} |
1809 for target in targets.iterkeys(): | 1812 for target in targets.iterkeys(): |
1810 build_file = gyp.common.BuildFile(target) | 1813 build_file = gyp.common.BuildFile(target) |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1843 root_node.dependents.append(build_file_node) | 1846 root_node.dependents.append(build_file_node) |
1844 | 1847 |
1845 flat_list = root_node.FlattenToList() | 1848 flat_list = root_node.FlattenToList() |
1846 | 1849 |
1847 # If there's anything left unvisited, there must be a circular dependency | 1850 # If there's anything left unvisited, there must be a circular dependency |
1848 # (cycle). | 1851 # (cycle). |
1849 if len(flat_list) != len(dependency_nodes): | 1852 if len(flat_list) != len(dependency_nodes): |
1850 bad_files = [] | 1853 bad_files = [] |
1851 for file in dependency_nodes.iterkeys(): | 1854 for file in dependency_nodes.iterkeys(): |
1852 if not file in flat_list: | 1855 if not file in flat_list: |
1853 bad_files.append(file) | 1856 bad_files.append(file) |
cjhopman
2014/10/21 18:22:23
bad_files was unused
| |
1854 common_path_prefix = os.path.commonprefix(dependency_nodes) | 1857 common_path_prefix = os.path.commonprefix(dependency_nodes) |
cjhopman
2014/10/21 18:22:23
This doesn't really seem helpful since the prefix
| |
1855 cycles = [] | 1858 cycles = [] |
1856 for cycle in root_node.FindCycles(): | 1859 for cycle in root_node.FindCycles(): |
1857 simplified_paths = [] | 1860 simplified_paths = [] |
1858 for node in cycle: | 1861 for node in cycle: |
1859 assert(node.ref.startswith(common_path_prefix)) | 1862 assert(node.ref.startswith(common_path_prefix)) |
1860 simplified_paths.append(node.ref[len(common_path_prefix):]) | 1863 simplified_paths.append(node.ref[len(common_path_prefix):]) |
1861 cycles.append('Cycle: %s' % ' -> '.join(simplified_paths)) | 1864 cycles.append('Cycle: %s' % ' -> '.join(simplified_paths)) |
1862 raise DependencyGraphNode.CircularException, \ | 1865 raise DependencyGraphNode.CircularException, \ |
1863 'Cycles in .gyp file dependency graph detected:\n' + '\n'.join(cycles) | 1866 'Cycles in .gyp file dependency graph detected:\n' + '\n'.join(cycles) |
1864 | 1867 |
(...skipping 999 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2864 ValidateRunAsInTarget(target, target_dict, build_file) | 2867 ValidateRunAsInTarget(target, target_dict, build_file) |
2865 ValidateActionsInTarget(target, target_dict, build_file) | 2868 ValidateActionsInTarget(target, target_dict, build_file) |
2866 | 2869 |
2867 # Generators might not expect ints. Turn them into strs. | 2870 # Generators might not expect ints. Turn them into strs. |
2868 TurnIntIntoStrInDict(data) | 2871 TurnIntIntoStrInDict(data) |
2869 | 2872 |
2870 # TODO(mark): Return |data| for now because the generator needs a list of | 2873 # TODO(mark): Return |data| for now because the generator needs a list of |
2871 # build files that came in. In the future, maybe it should just accept | 2874 # build files that came in. In the future, maybe it should just accept |
2872 # a list, and not the whole data dict. | 2875 # a list, and not the whole data dict. |
2873 return [flat_list, targets, data] | 2876 return [flat_list, targets, data] |
OLD | NEW |