key=inserted_order.index,
)
)
-
ancestors_by_idx = [get_ancestors(rev_id) for rev_id in current_heads]
output = []
candidate_rev = id_to_rev[candidate]
- # immediate ancestor nodes
+ # immediate ancestor nodes, use a set to uniquify
+ _u = set()
heads_to_add = [
r
for r in candidate_rev._normalized_down_revisions
- if r in todo and r not in current_heads
+ if r in todo
+ and r not in current_heads
+ and r not in _u
+ and (_u.add(r) or True)
]
if not heads_to_add:
--- /dev/null
+.. change::
+ :tags: bug, regression, versioning
+ :tickets: 843
+
+ Fixed regression where a revision file that contained its own down revision
+ as a dependency would cause an endless loop in the traversal logic.
)
self._assert_raises_revision_map_loop(map_, "a")
+ def test_revision_dupe_head(self):
+ r1 = Revision("user_foo", None)
+ r2 = Revision("user", "user_foo", dependencies="user_foo")
+
+ self.map = RevisionMap(lambda: [r1, r2])
+
+ self._assert_iteration("heads", None, ["user", "user_foo"])
+
+ eq_(self.map._topological_sort([r1, r2], [r2]), ["user", "user_foo"])
+
def test_revision_map_no_loop_w_overlapping_substrings(self):
r1 = Revision("user_foo", None)
r2 = Revision("user", "user_foo")
)
+class DependsOnOwnDownrevTest(MigrationTest):
+ @classmethod
+ def setup_class(cls):
+ """
+ test #843
+ """
+ cls.env = env = staging_env()
+ cls.a1 = env.generate_revision("a1", "->a1", head="base")
+ cls.a2 = env.generate_revision("a2", "->a2", depends_on="a1")
+
+ @classmethod
+ def teardown_class(cls):
+ clear_staging_env()
+
+ def test_traverse(self):
+ self._assert_upgrade(
+ self.a2.revision,
+ None,
+ [self.up_(self.a1), self.up_(self.a2)],
+ set(["a2"]),
+ )
+
+
class DependsOnBranchTestFour(MigrationTest):
@classmethod
def setup_class(cls):