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