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([child] + path[:path.index(child) + 1]) |
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) |
1573 break | |
1574 results.append(tuple(cycle)) | |
1575 else: | |
1576 results.extend(node.FindCycles([node] + path)) | |
1577 | 1573 |
1578 return list(set(results)) | 1574 visited.add(self) |
1575 Visit(self, [self]) | |
1576 | |
1577 return 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. |
1587 if dependency.ref != None and dependency.ref not in dependencies: | 1586 if dependency.ref != None and dependency.ref not in dependencies: |
1588 dependencies.append(dependency.ref) | 1587 dependencies.append(dependency.ref) |
(...skipping 196 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 if not root_node.dependents: |
1799 'Some targets not reachable, cycle in dependency graph detected: ' + | 1797 # If all targets have dependencies, add the first target as a dependent |
1800 ' '.join(set(flat_list) ^ set(targets))) | 1798 # of root_node so that the cycle can be discovered from root_node. |
1799 target = targets.keys()[0] | |
1800 target_node = dependency_nodes[target] | |
1801 target_node.dependencies.append(root_node) | |
1802 root_node.dependents.append(target_node) | |
1803 | |
1804 cycles = [] | |
1805 for cycle in root_node.FindCycles(): | |
1806 paths = [node.ref for node in cycle] | |
1807 cycles.append('Cycle: %s' % ' -> '.join(paths)) | |
1808 raise DependencyGraphNode.CircularException, \ | |
scottmg
2014/10/21 18:31:47
I meant this \ vs. (, mostly since that's what it
cjhopman
2014/10/21 19:52:54
Ha, I really thought I fixed it here before.
| |
1809 'Cycles in dependency graph detected:\n' + '\n'.join(cycles) | |
1801 | 1810 |
1802 return [dependency_nodes, flat_list] | 1811 return [dependency_nodes, flat_list] |
1803 | 1812 |
1804 | 1813 |
1805 def VerifyNoGYPFileCircularDependencies(targets): | 1814 def VerifyNoGYPFileCircularDependencies(targets): |
1806 # Create a DependencyGraphNode for each gyp file containing a target. Put | 1815 # Create a DependencyGraphNode for each gyp file containing a target. Put |
1807 # it into a dict for easy access. | 1816 # it into a dict for easy access. |
1808 dependency_nodes = {} | 1817 dependency_nodes = {} |
1809 for target in targets.iterkeys(): | 1818 for target in targets.iterkeys(): |
1810 build_file = gyp.common.BuildFile(target) | 1819 build_file = gyp.common.BuildFile(target) |
(...skipping 29 matching lines...) Expand all Loading... | |
1840 for build_file_node in dependency_nodes.itervalues(): | 1849 for build_file_node in dependency_nodes.itervalues(): |
1841 if len(build_file_node.dependencies) == 0: | 1850 if len(build_file_node.dependencies) == 0: |
1842 build_file_node.dependencies.append(root_node) | 1851 build_file_node.dependencies.append(root_node) |
1843 root_node.dependents.append(build_file_node) | 1852 root_node.dependents.append(build_file_node) |
1844 | 1853 |
1845 flat_list = root_node.FlattenToList() | 1854 flat_list = root_node.FlattenToList() |
1846 | 1855 |
1847 # If there's anything left unvisited, there must be a circular dependency | 1856 # If there's anything left unvisited, there must be a circular dependency |
1848 # (cycle). | 1857 # (cycle). |
1849 if len(flat_list) != len(dependency_nodes): | 1858 if len(flat_list) != len(dependency_nodes): |
1850 bad_files = [] | 1859 if not root_node.dependents: |
1851 for file in dependency_nodes.iterkeys(): | 1860 # If all files have dependencies, add the first file as a dependent |
1852 if not file in flat_list: | 1861 # of root_node so that the cycle can be discovered from root_node. |
1853 bad_files.append(file) | 1862 file_node = dependency_nodes.values()[0] |
1854 common_path_prefix = os.path.commonprefix(dependency_nodes) | 1863 file_node.dependencies.append(root_node) |
1864 root_node.dependents.append(file_node) | |
1855 cycles = [] | 1865 cycles = [] |
1856 for cycle in root_node.FindCycles(): | 1866 for cycle in root_node.FindCycles(): |
1857 simplified_paths = [] | 1867 paths = [node.ref for node in cycle] |
1858 for node in cycle: | 1868 cycles.append('Cycle: %s' % ' -> '.join(paths)) |
1859 assert(node.ref.startswith(common_path_prefix)) | 1869 raise DependencyGraphNode.CircularException( |
1860 simplified_paths.append(node.ref[len(common_path_prefix):]) | 1870 'Cycles in .gyp file dependency graph detected:\n' + '\n'.join(cycles)) |
1861 cycles.append('Cycle: %s' % ' -> '.join(simplified_paths)) | |
1862 raise DependencyGraphNode.CircularException, \ | |
1863 'Cycles in .gyp file dependency graph detected:\n' + '\n'.join(cycles) | |
1864 | 1871 |
1865 | 1872 |
1866 def DoDependentSettings(key, flat_list, targets, dependency_nodes): | 1873 def DoDependentSettings(key, flat_list, targets, dependency_nodes): |
1867 # key should be one of all_dependent_settings, direct_dependent_settings, | 1874 # key should be one of all_dependent_settings, direct_dependent_settings, |
1868 # or link_settings. | 1875 # or link_settings. |
1869 | 1876 |
1870 for target in flat_list: | 1877 for target in flat_list: |
1871 target_dict = targets[target] | 1878 target_dict = targets[target] |
1872 build_file = gyp.common.BuildFile(target) | 1879 build_file = gyp.common.BuildFile(target) |
1873 | 1880 |
(...skipping 990 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2864 ValidateRunAsInTarget(target, target_dict, build_file) | 2871 ValidateRunAsInTarget(target, target_dict, build_file) |
2865 ValidateActionsInTarget(target, target_dict, build_file) | 2872 ValidateActionsInTarget(target, target_dict, build_file) |
2866 | 2873 |
2867 # Generators might not expect ints. Turn them into strs. | 2874 # Generators might not expect ints. Turn them into strs. |
2868 TurnIntIntoStrInDict(data) | 2875 TurnIntIntoStrInDict(data) |
2869 | 2876 |
2870 # TODO(mark): Return |data| for now because the generator needs a list of | 2877 # 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 | 2878 # build files that came in. In the future, maybe it should just accept |
2872 # a list, and not the whole data dict. | 2879 # a list, and not the whole data dict. |
2873 return [flat_list, targets, data] | 2880 return [flat_list, targets, data] |
OLD | NEW |