diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py index bc209f92fde..f6bcaf5835a 100644 --- a/lib/spack/spack/spec.py +++ b/lib/spack/spack/spec.py @@ -3815,8 +3815,7 @@ def _cmp_iter(self): # 2. A generator over canonical edges # # Canonical edges have consistent ids defined by breadth-first traversal order. That is, - # the fake edge from nothing to the root is (0, 1), the root is always 1, dependencies of - # the root are 2, 3, 4, 5, etc., and so on. + # the root is always 0, dependencies of the root are 1, 2, 3, etc., and so on. # # The three cases are: # @@ -3839,19 +3838,14 @@ def _cmp_iter(self): # need for the complexity here. It was not clear at the time of writing that how # much optimization was possible in `spack.traverse`. - def yield_root_edge(): - yield 0 # id of None (parent of root) - yield 1 # id of root - yield 0 # depflag on fake edge - yield () # virtuals on fake edge - if not self._dependencies: # Spec has no dependencies -- simplest case def nodes(): yield self._cmp_node # just yield this node def edges(): - yield yield_root_edge + return + yield elif not any( dep.spec._dependencies for deplist in self._dependencies.values() for dep in deplist @@ -3879,15 +3873,12 @@ def nodes(): yield edge.spec._cmp_node def edges(): - # yield root edge consistent with what traverse would do. - yield yield_root_edge - # we've already sorted to yield dependency nodes in order, now yield # edges for comparison in the same order, with BFS-consistent ids - for i, edge in enumerate(sorted_edges, start=2): + for i, edge in enumerate(sorted_edges, start=1): def yield_edge(i=i, edge=edge): - yield 1 # id of root + yield 0 # id of root yield i # id of dependency in BFS order yield edge.depflag yield edge.virtuals @@ -3900,7 +3891,6 @@ def yield_edge(i=i, edge=edge): # We need a way to compare edges consistently between two arbitrary specs. # node_ids generates consistent node ids based on BFS traversal order. node_ids = collections.defaultdict(lambda: len(node_ids)) - node_ids[id(None)] # None (parent of root) is always node id 0 # To avoid traversing twice, we put edges in this list as we yield the nodes. # edges() yields the edge functions later, if necessary. @@ -3915,6 +3905,10 @@ def nodes(): yield edge.spec._cmp_node node_ids[id(edge.spec)] + # skip fake edge to root + if edge.parent is None: + continue + # create "edges" with the ids we generated above def yield_edge(edge=edge): yield node_ids[id(edge.parent)] diff --git a/lib/spack/spack/test/spec_semantics.py b/lib/spack/spack/test/spec_semantics.py index 7c995796aa7..29dd072506d 100644 --- a/lib/spack/spack/test/spec_semantics.py +++ b/lib/spack/spack/test/spec_semantics.py @@ -2057,10 +2057,7 @@ def test_spec_ordering(specs_in_expected_order): "spec,expected_tuplified", [ # simple, no dependencies - [ - ("a"), - ((("a", None, EMPTY_VER, EMPTY_VAR, EMPTY_FLG, None, None, None),), ((0, 1, 0, ()),)), - ], + [("a"), ((("a", None, EMPTY_VER, EMPTY_VAR, EMPTY_FLG, None, None, None),), ())], # with some node attributes [ ("a@1.0 +foo cflags='-O3 -g'"), @@ -2077,7 +2074,7 @@ def test_spec_ordering(specs_in_expected_order): None, ), ), - ((0, 1, 0, ()),), + (), ), ], # single edge case @@ -2088,7 +2085,7 @@ def test_spec_ordering(specs_in_expected_order): ("a", None, EMPTY_VER, EMPTY_VAR, EMPTY_FLG, None, None, None), ("b", None, EMPTY_VER, EMPTY_VAR, EMPTY_FLG, None, None, None), ), - ((0, 1, 0, ()), (1, 2, 0, ())), + ((0, 1, 0, ()),), ), ], # root with multiple deps @@ -2101,7 +2098,7 @@ def test_spec_ordering(specs_in_expected_order): ("c", None, EMPTY_VER, EMPTY_VAR, EMPTY_FLG, None, None, None), ("d", None, EMPTY_VER, EMPTY_VAR, EMPTY_FLG, None, None, None), ), - ((0, 1, 0, ()), (1, 2, 0, ()), (1, 3, 0, ()), (1, 4, 0, ())), + ((0, 1, 0, ()), (0, 2, 0, ()), (0, 3, 0, ())), ), ], # root with multiple build deps @@ -2114,7 +2111,7 @@ def test_spec_ordering(specs_in_expected_order): ("c", None, EMPTY_VER, EMPTY_VAR, EMPTY_FLG, None, None, None), ("d", None, EMPTY_VER, EMPTY_VAR, EMPTY_FLG, None, None, None), ), - ((0, 1, 0, ()), (1, 2, dt.BUILD, ()), (1, 3, dt.BUILD, ()), (1, 4, dt.BUILD, ())), + ((0, 1, dt.BUILD, ()), (0, 2, dt.BUILD, ()), (0, 3, dt.BUILD, ())), ), ], # dependencies with dependencies @@ -2132,12 +2129,11 @@ def test_spec_ordering(specs_in_expected_order): ), ( (0, 1, 0, ()), - (1, 2, 0, ()), - (1, 3, 0, ()), - (2, 4, dt.BUILD, ()), + (0, 2, 0, ()), + (1, 3, dt.BUILD, ()), + (1, 4, dt.BUILD, ()), (2, 5, dt.BUILD, ()), - (3, 6, dt.BUILD, ()), - (3, 7, dt.BUILD, ()), + (2, 6, dt.BUILD, ()), ), ), ],