Rev 5130: (vila) Log exclude non-ancestry revisions in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Fri Apr 2 17:00:38 BST 2010


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 5130 [merge]
revision-id: pqm at pqm.ubuntu.com-20100402160036-4d8279awdw22uudr
parent: pqm at pqm.ubuntu.com-20100401133704-eo1imatu4ipjqaq4
parent: v.ladeuil+lp at free.fr-20100402150655-td33fj8ibubd4hic
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Fri 2010-04-02 17:00:36 +0100
message:
  (vila) Log exclude non-ancestry revisions
modified:
  bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
  bzrlib/tests/per_branch/test_iter_merge_sorted_revisions.py test_merge_sorted_re-20090121004847-to3gvjwigstu93eh-1
=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2010-03-22 13:59:33 +0000
+++ b/bzrlib/branch.py	2010-04-02 15:06:55 +0000
@@ -455,6 +455,9 @@
         filtered = self._filter_merge_sorted_revisions(
             self._merge_sorted_revisions_cache, start_revision_id,
             stop_revision_id, stop_rule)
+        # Make sure we don't return revisions that are not part of the
+        # start_revision_id ancestry.
+        filtered = self._filter_non_ancestors(filtered)
         if direction == 'reverse':
             return filtered
         if direction == 'forward':
@@ -525,6 +528,51 @@
         else:
             raise ValueError('invalid stop_rule %r' % stop_rule)
 
+    def _filter_non_ancestors(self, rev_iter):
+        # If we started from a dotted revno, we want to consider it as a tip
+        # and don't want to yield revisions that are not part of its
+        # ancestry. Given the order guaranteed by the merge sort, we will see
+        # uninteresting descendants of the first parent of our tip before the
+        # tip itself.
+        first = rev_iter.next()
+        (rev_id, merge_depth, revno, end_of_merge) = first
+        yield first
+        if not merge_depth:
+            # We start at a mainline revision so by definition, all others
+            # revisions in rev_iter are ancestors
+            for node in rev_iter:
+                yield node
+
+        clean = False
+        whitelist = set()
+        pmap = self.repository.get_parent_map([rev_id])
+        parents = pmap.get(rev_id, [])
+        if parents:
+            whitelist.update(parents)
+        else:
+            # If there is no parents, there is nothing of interest left
+
+            # FIXME: It's hard to test this scenario here as this code is never
+            # called in that case. -- vila 20100322
+            return
+
+        for (rev_id, merge_depth, revno, end_of_merge) in rev_iter:
+            if not clean:
+                if rev_id in whitelist:
+                    pmap = self.repository.get_parent_map([rev_id])
+                    parents = pmap.get(rev_id, [])
+                    whitelist.remove(rev_id)
+                    whitelist.update(parents)
+                    if merge_depth == 0:
+                        # We've reached the mainline, there is nothing left to
+                        # filter
+                        clean = True
+                else:
+                    # A revision that is not part of the ancestry of our
+                    # starting revision.
+                    continue
+            yield (rev_id, merge_depth, revno, end_of_merge)
+
     def leave_lock_in_place(self):
         """Tell this branch object not to release the physical lock when this
         object is unlocked.

=== modified file 'bzrlib/tests/per_branch/test_iter_merge_sorted_revisions.py'
--- a/bzrlib/tests/per_branch/test_iter_merge_sorted_revisions.py	2010-03-19 12:42:56 +0000
+++ b/bzrlib/tests/per_branch/test_iter_merge_sorted_revisions.py	2010-04-02 15:05:24 +0000
@@ -25,43 +25,52 @@
 from bzrlib.tests import per_branch
 
 
-class TestIterMergeSortedRevisions(per_branch.TestCaseWithBranch):
+class TestIterMergeSortedRevisionsSimpleGraph(per_branch.TestCaseWithBranch):
 
     def setUp(self):
-        super(TestIterMergeSortedRevisions, self).setUp()
-        self.branch = self.make_branch_with_merges('.')
+        super(TestIterMergeSortedRevisionsSimpleGraph, self).setUp()
+        builder = self.make_builder_with_merges('.')
+        self.branch = builder.get_branch()
+        self.branch.lock_read()
+        self.addCleanup(self.branch.unlock)
 
-    def make_branch_with_merges(self, relpath):
+    def make_builder_with_merges(self, relpath):
         try:
             builder = self.make_branch_builder(relpath)
         except (errors.TransportNotPossible, errors.UninitializableFormat):
             raise tests.TestNotApplicable('format not directly constructable')
         builder.start_series()
+        # 1
+        # |\
+        # 2 |
+        # | |
+        # | 1.1.1
+        # |/
+        # 3
         builder.build_snapshot('1', None, [
             ('add', ('', 'TREE_ROOT', 'directory', '')),])
         builder.build_snapshot('1.1.1', ['1'], [])
         builder.build_snapshot('2', ['1'], [])
         builder.build_snapshot('3', ['2', '1.1.1'], [])
         builder.finish_series()
-        return builder.get_branch()
-
+        return builder
 
     def assertIterRevids(self, expected, *args, **kwargs):
         # We don't care about depths and revnos here, only about returning the
         # right revids.
-        revids = [ revid for (revid, depth, revno, eom) in
-                   self.branch.iter_merge_sorted_revisions(*args, **kwargs)]
+        revids = [revid for (revid, depth, revno, eom) in
+                  self.branch.iter_merge_sorted_revisions(*args, **kwargs)]
         self.assertEqual(expected, revids)
 
     def test_merge_sorted(self):
         self.assertIterRevids(['3', '1.1.1', '2', '1'])
 
     def test_merge_sorted_range(self):
-        self.assertIterRevids(['1.1.1', '2'],
+        self.assertIterRevids(['1.1.1'],
                               start_revision_id='1.1.1', stop_revision_id='1')
 
     def test_merge_sorted_range_start_only(self):
-        self.assertIterRevids(['1.1.1', '2', '1'],
+        self.assertIterRevids(['1.1.1', '1'],
                               start_revision_id='1.1.1')
 
     def test_merge_sorted_range_stop_exclude(self):
@@ -105,12 +114,12 @@
         self.assertIterRevids(['1', '2', '1.1.1', '3'], direction='forward')
 
     def test_merge_sorted_range_forward(self):
-        self.assertIterRevids(['2', '1.1.1'],
+        self.assertIterRevids(['1.1.1'],
                               start_revision_id='1.1.1', stop_revision_id='1',
                               direction='forward')
 
     def test_merge_sorted_range_start_only_forward(self):
-        self.assertIterRevids(['1', '2', '1.1.1'],
+        self.assertIterRevids(['1', '1.1.1'],
                               start_revision_id='1.1.1', direction='forward')
 
     def test_merge_sorted_range_stop_exclude_forward(self):
@@ -126,3 +135,127 @@
         self.assertIterRevids(['1.1.1', '3'],
                               stop_revision_id='3', stop_rule='with-merges',
                               direction='forward')
+
+
+class TestIterMergeSortedRevisionsBushyGraph(per_branch.TestCaseWithBranch):
+
+    def make_branch_builder(self, relpath):
+        try:
+            builder = super(TestIterMergeSortedRevisionsBushyGraph,
+                            self).make_branch_builder(relpath)
+        except (errors.TransportNotPossible, errors.UninitializableFormat):
+            raise tests.TestNotApplicable('format not directly constructable')
+        return builder
+
+    def make_branch_with_embedded_merges(self, relpath='.'):
+        builder = self.make_branch_builder(relpath)
+        # 1
+        # |\
+        # | 1.1.1
+        # | /
+        # 2
+        # | \
+        # 3 |
+        # | |
+        # | 2.1.1
+        # | |    \
+        # | 2.1.2 |
+        # | |     |
+        # | |   2.2.1
+        # | |  /
+        # | 2.1.3
+        # |/
+        # 4
+        builder.start_series()
+        builder.build_snapshot('1', None, [
+            ('add', ('', 'TREE_ROOT', 'directory', '')),])
+        builder.build_snapshot('1.1.1', ['1'], [])
+        builder.build_snapshot('2', ['1', '1.1.1'], [])
+        builder.build_snapshot('2.1.1', ['2'], [])
+        builder.build_snapshot('2.1.2', ['2.1.1'], [])
+        builder.build_snapshot('2.2.1', ['2.1.1'], [])
+        builder.build_snapshot('2.1.3', ['2.1.2', '2.2.1'], [])
+        builder.build_snapshot('3', ['2'], [])
+        builder.build_snapshot('4', ['3', '2.1.3'], [])
+        builder.finish_series()
+        br = builder.get_branch()
+        br.lock_read()
+        self.addCleanup(br.unlock)
+        return br
+
+    def make_branch_with_different_depths_merges(self, relpath='.'):
+        builder = self.make_branch_builder(relpath)
+        # 1
+        # |\
+        # | 1.1.1
+        # | /
+        # 2
+        # | \
+        # 3 |
+        # | |
+        # | 2.1.1
+        # | |    \
+        # | 2.1.2 |
+        # | |     |
+        # | |     2.2.1
+        # | |    /
+        # | 2.1.3
+        # |/
+        # 4
+        builder.start_series()
+        builder.build_snapshot('1', None, [
+            ('add', ('', 'TREE_ROOT', 'directory', '')),])
+        builder.build_snapshot('2', ['1'], [])
+        builder.build_snapshot('1.1.1', ['1'], [])
+        builder.build_snapshot('1.1.2', ['1.1.1'], [])
+        builder.build_snapshot('1.2.1', ['1.1.1'], [])
+        builder.build_snapshot('1.2.2', ['1.2.1'], [])
+        builder.build_snapshot('1.3.1', ['1.2.1'], [])
+        builder.build_snapshot('1.3.2', ['1.3.1'], [])
+        builder.build_snapshot('1.4.1', ['1.3.1'], [])
+        builder.build_snapshot('1.3.3', ['1.3.2', '1.4.11'], [])
+        builder.build_snapshot('1.2.3', ['1.2.2', '1.3.3'], [])
+        builder.build_snapshot('2.1.1', ['2'], [])
+        builder.build_snapshot('2.1.2', ['2.1.1'], [])
+        builder.build_snapshot('2.2.1', ['2.1.1'], [])
+        builder.build_snapshot('2.1.3', ['2.1.2', '2.2.1'], [])
+        builder.build_snapshot('3', ['2',  '1.2.3'], [])
+        # .. to bring them all and ... bind them
+        builder.build_snapshot('4', ['3', '2.1.3'],
+                               [])
+        builder.finish_series()
+        br = builder.get_branch()
+        br.lock_read()
+        self.addCleanup(br.unlock)
+        return br
+
+    def assertIterRevids(self, expected, branch, *args, **kwargs):
+        # We don't care about depths and revnos here, only about returning the
+        # right revids.
+        revs = list(branch.iter_merge_sorted_revisions(*args, **kwargs))
+        revids = [revid for (revid, depth, revno, eom) in revs]
+        self.assertEqual(expected, revids)
+
+    def test_merge_sorted_starting_at_embedded_merge(self):
+        branch = self.make_branch_with_embedded_merges()
+        self.assertIterRevids(['4', '2.1.3', '2.2.1', '2.1.2', '2.1.1',
+                               '3', '2', '1.1.1', '1'],
+                              branch)
+        # 3 and 2.1.2 are not part of 2.2.1 ancestry and should not appear
+        self.assertIterRevids(['2.2.1', '2.1.1', '2', '1.1.1', '1'],
+                              branch, start_revision_id='2.2.1',
+                              stop_rule='with-merges')
+
+    def test_merge_sorted_with_different_depths_merge(self):
+        branch = self.make_branch_with_different_depths_merges()
+        self.assertIterRevids(['4', '2.1.3', '2.2.1', '2.1.2', '2.1.1',
+                               '3',
+                               '1.2.3', '1.3.3', '1.3.2', '1.3.1',
+                               '1.2.2', '1.2.1', '1.1.1',
+                               '2', '1'],
+                              branch)
+        # 3 (and its descendants) and 2.1.2 are not part of 2.2.1 ancestry and
+        # should not appear
+        self.assertIterRevids(['2.2.1', '2.1.1', '2', '1'],
+                              branch, start_revision_id='2.2.1',
+                              stop_rule='with-merges')




More information about the bazaar-commits mailing list