| 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 __future__ import with_statement |    5 from __future__ import with_statement | 
|    6  |    6  | 
|    7 import errno |    7 import errno | 
|    8 import filecmp |    8 import filecmp | 
|    9 import os.path |    9 import os.path | 
|   10 import re |   10 import re | 
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  394     if idfun is None: |  394     if idfun is None: | 
|  395         def idfun(x): return x |  395         def idfun(x): return x | 
|  396     seen = {} |  396     seen = {} | 
|  397     result = [] |  397     result = [] | 
|  398     for item in seq: |  398     for item in seq: | 
|  399         marker = idfun(item) |  399         marker = idfun(item) | 
|  400         if marker in seen: continue |  400         if marker in seen: continue | 
|  401         seen[marker] = 1 |  401         seen[marker] = 1 | 
|  402         result.append(item) |  402         result.append(item) | 
|  403     return result |  403     return result | 
 |  404  | 
 |  405  | 
 |  406 class CycleError(Exception): | 
 |  407   """An exception raised when an unexpected cycle is detected.""" | 
 |  408   def __init__(self, nodes): | 
 |  409     self.nodes = nodes | 
 |  410   def __str__(self): | 
 |  411     return 'CycleError: cycle involving: ' + str(self.nodes) | 
 |  412  | 
 |  413  | 
 |  414 def TopologicallySorted(graph, get_edges): | 
 |  415   """Topologically sort based on a user provided edge definition. | 
 |  416  | 
 |  417   Args: | 
 |  418     graph: A list of node names. | 
 |  419     get_edges: A function mapping from node name to a hashable collection | 
 |  420                of node names which this node has outgoing edges to. | 
 |  421   Returns: | 
 |  422     A list containing all of the node in graph in topological order. | 
 |  423     It is assumed that calling get_edges once for each node and caching is | 
 |  424     cheaper than repeatedly calling get_edges. | 
 |  425   Raises: | 
 |  426     CycleError in the event of a cycle. | 
 |  427   Example: | 
 |  428     graph = {'a': '$(b) $(c)', 'b': 'hi', 'c': '$(b)'} | 
 |  429     def GetEdges(node): | 
 |  430       return re.findall(r'\$\(([^))]\)', graph[node]) | 
 |  431     print TopologicallySorted(graph.keys(), GetEdges) | 
 |  432     ==> | 
 |  433     ['a', 'c', b'] | 
 |  434   """ | 
 |  435   get_edges = memoize(get_edges) | 
 |  436   visited = set() | 
 |  437   visiting = set() | 
 |  438   ordered_nodes = [] | 
 |  439   def Visit(node): | 
 |  440     if node in visiting: | 
 |  441       raise CycleError(visiting) | 
 |  442     if node in visited: | 
 |  443       return | 
 |  444     visited.add(node) | 
 |  445     visiting.add(node) | 
 |  446     for neighbor in get_edges(node): | 
 |  447       Visit(neighbor) | 
 |  448     visiting.remove(node) | 
 |  449     ordered_nodes.insert(0, node) | 
 |  450   for node in sorted(graph): | 
 |  451     Visit(node) | 
 |  452   return ordered_nodes | 
| OLD | NEW |