| 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 1425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1436 """ | 1436 """ |
| 1437 | 1437 |
| 1438 class CircularException(GypError): | 1438 class CircularException(GypError): |
| 1439 pass | 1439 pass |
| 1440 | 1440 |
| 1441 def __init__(self, ref): | 1441 def __init__(self, ref): |
| 1442 self.ref = ref | 1442 self.ref = ref |
| 1443 self.dependencies = [] | 1443 self.dependencies = [] |
| 1444 self.dependents = [] | 1444 self.dependents = [] |
| 1445 | 1445 |
| 1446 def __repr__(self): |
| 1447 return '<DependencyGraphNode: %r>' % self.ref |
| 1448 |
| 1446 def FlattenToList(self): | 1449 def FlattenToList(self): |
| 1447 # flat_list is the sorted list of dependencies - actually, the list items | 1450 # flat_list is the sorted list of dependencies - actually, the list items |
| 1448 # are the "ref" attributes of DependencyGraphNodes. Every target will | 1451 # are the "ref" attributes of DependencyGraphNodes. Every target will |
| 1449 # appear in flat_list after all of its dependencies, and before all of its | 1452 # appear in flat_list after all of its dependencies, and before all of its |
| 1450 # dependents. | 1453 # dependents. |
| 1451 flat_list = [] | 1454 flat_list = [] |
| 1452 | 1455 |
| 1453 # in_degree_zeros is the list of DependencyGraphNodes that have no | 1456 # in_degree_zeros is the list of DependencyGraphNodes that have no |
| 1454 # dependencies not in flat_list. Initially, it is a copy of the children | 1457 # dependencies not in flat_list. Initially, it is a copy of the children |
| 1455 # of this node, because when the graph was built, nodes with no | 1458 # of this node, because when the graph was built, nodes with no |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1478 break | 1481 break |
| 1479 | 1482 |
| 1480 if is_in_degree_zero: | 1483 if is_in_degree_zero: |
| 1481 # All of the dependent's dependencies are already in flat_list. Add | 1484 # All of the dependent's dependencies are already in flat_list. Add |
| 1482 # it to in_degree_zeros where it will be processed in a future | 1485 # it to in_degree_zeros where it will be processed in a future |
| 1483 # iteration of the outer loop. | 1486 # iteration of the outer loop. |
| 1484 in_degree_zeros.add(node_dependent) | 1487 in_degree_zeros.add(node_dependent) |
| 1485 | 1488 |
| 1486 return flat_list | 1489 return flat_list |
| 1487 | 1490 |
| 1491 def FindCycles(self, path=None): |
| 1492 """ |
| 1493 Returns a list of cycles in the graph, where each cycle is its own list. |
| 1494 """ |
| 1495 if path is None: |
| 1496 path = [self] |
| 1497 |
| 1498 results = [] |
| 1499 for node in self.dependents: |
| 1500 if node in path: |
| 1501 cycle = [node] |
| 1502 for part in path: |
| 1503 cycle.append(part) |
| 1504 if part == node: |
| 1505 break |
| 1506 results.append(tuple(cycle)) |
| 1507 else: |
| 1508 results.extend(node.FindCycles([node] + path)) |
| 1509 |
| 1510 return list(set(results)) |
| 1511 |
| 1488 def DirectDependencies(self, dependencies=None): | 1512 def DirectDependencies(self, dependencies=None): |
| 1489 """Returns a list of just direct dependencies.""" | 1513 """Returns a list of just direct dependencies.""" |
| 1490 if dependencies == None: | 1514 if dependencies == None: |
| 1491 dependencies = [] | 1515 dependencies = [] |
| 1492 | 1516 |
| 1493 for dependency in self.dependencies: | 1517 for dependency in self.dependencies: |
| 1494 # Check for None, corresponding to the root node. | 1518 # Check for None, corresponding to the root node. |
| 1495 if dependency.ref != None and dependency.ref not in dependencies: | 1519 if dependency.ref != None and dependency.ref not in dependencies: |
| 1496 dependencies.append(dependency.ref) | 1520 dependencies.append(dependency.ref) |
| 1497 | 1521 |
| (...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1710 | 1734 |
| 1711 flat_list = root_node.FlattenToList() | 1735 flat_list = root_node.FlattenToList() |
| 1712 | 1736 |
| 1713 # If there's anything left unvisited, there must be a circular dependency | 1737 # If there's anything left unvisited, there must be a circular dependency |
| 1714 # (cycle). | 1738 # (cycle). |
| 1715 if len(flat_list) != len(dependency_nodes): | 1739 if len(flat_list) != len(dependency_nodes): |
| 1716 bad_files = [] | 1740 bad_files = [] |
| 1717 for file in dependency_nodes.iterkeys(): | 1741 for file in dependency_nodes.iterkeys(): |
| 1718 if not file in flat_list: | 1742 if not file in flat_list: |
| 1719 bad_files.append(file) | 1743 bad_files.append(file) |
| 1744 common_path_prefix = os.path.commonprefix(dependency_nodes) |
| 1745 cycles = [] |
| 1746 for cycle in root_node.FindCycles(): |
| 1747 simplified_paths = [] |
| 1748 for node in cycle: |
| 1749 assert(node.ref.startswith(common_path_prefix)) |
| 1750 simplified_paths.append(node.ref[len(common_path_prefix):]) |
| 1751 cycles.append('Cycle: %s' % ' -> '.join(simplified_paths)) |
| 1720 raise DependencyGraphNode.CircularException, \ | 1752 raise DependencyGraphNode.CircularException, \ |
| 1721 'Some files not reachable, cycle in .gyp file dependency graph ' + \ | 1753 'Cycles in .gyp file dependency graph detected:\n' + '\n'.join(cycles) |
| 1722 'detected involving some or all of: ' + \ | |
| 1723 ' '.join(bad_files) | |
| 1724 | 1754 |
| 1725 | 1755 |
| 1726 def DoDependentSettings(key, flat_list, targets, dependency_nodes): | 1756 def DoDependentSettings(key, flat_list, targets, dependency_nodes): |
| 1727 # key should be one of all_dependent_settings, direct_dependent_settings, | 1757 # key should be one of all_dependent_settings, direct_dependent_settings, |
| 1728 # or link_settings. | 1758 # or link_settings. |
| 1729 | 1759 |
| 1730 for target in flat_list: | 1760 for target in flat_list: |
| 1731 target_dict = targets[target] | 1761 target_dict = targets[target] |
| 1732 build_file = gyp.common.BuildFile(target) | 1762 build_file = gyp.common.BuildFile(target) |
| 1733 | 1763 |
| (...skipping 940 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2674 ValidateRunAsInTarget(target, target_dict, build_file) | 2704 ValidateRunAsInTarget(target, target_dict, build_file) |
| 2675 ValidateActionsInTarget(target, target_dict, build_file) | 2705 ValidateActionsInTarget(target, target_dict, build_file) |
| 2676 | 2706 |
| 2677 # Generators might not expect ints. Turn them into strs. | 2707 # Generators might not expect ints. Turn them into strs. |
| 2678 TurnIntIntoStrInDict(data) | 2708 TurnIntIntoStrInDict(data) |
| 2679 | 2709 |
| 2680 # TODO(mark): Return |data| for now because the generator needs a list of | 2710 # TODO(mark): Return |data| for now because the generator needs a list of |
| 2681 # build files that came in. In the future, maybe it should just accept | 2711 # build files that came in. In the future, maybe it should just accept |
| 2682 # a list, and not the whole data dict. | 2712 # a list, and not the whole data dict. |
| 2683 return [flat_list, targets, data] | 2713 return [flat_list, targets, data] |
| OLD | NEW |