Rev 3479: Split things into a registry of annotation policies, and start in http://bzr.arbash-meinel.com/branches/bzr/1.6-dev/annotation
John Arbash Meinel
john at arbash-meinel.com
Fri Jun 6 03:30:10 BST 2008
At http://bzr.arbash-meinel.com/branches/bzr/1.6-dev/annotation
------------------------------------------------------------
revno: 3479
revision-id: john at arbash-meinel.com-20080606022951-uqtcqi14fvgtxld9
parent: john at arbash-meinel.com-20080605224745-wnih42sf8rqwbmdc
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: annotation
timestamp: Thu 2008-06-05 21:29:51 -0500
message:
Split things into a registry of annotation policies, and start
refactoring the tests to handle different policies.
-------------- next part --------------
=== modified file 'bzrlib/annotate.py'
--- a/bzrlib/annotate.py 2008-06-05 22:47:45 +0000
+++ b/bzrlib/annotate.py 2008-06-06 02:29:51 +0000
@@ -63,13 +63,13 @@
matcher = self._sequence_matcher(None, old, new)
return matcher.get_matching_blocks()
- def reannotate(self, parents_lines, new_lines, new_revision_id,
- _left_matching_blocks=None):
+ def reannotate(self, annotated_parents_lines, plain_child_lines,
+ child_revision_id, left_matching_blocks=None):
"""Annotate the lines given parent annotations.
- :param parents_lines: List of annotated lines for all parents
- :param new_lines: The un-annotated new lines
- :param new_revision_id: The revision-id to associate with new lines
+ :param annotated_parents_lines: List of annotated lines for all parents
+ :param plain_child_lines: The un-annotated new lines
+ :param child_revision_id: The revision-id to associate with new lines
(will often be CURRENT_REVISION)
:param left_matching_blocks: a hint about which areas are common
between the text and its left-hand-parent. The format is
@@ -77,24 +77,27 @@
(start_left, start_right, length_of_match).
:return: A list of annotated lines.
"""
- if len(parents_lines) == 0:
- lines = [(new_revision_id, line) for line in new_lines]
- elif len(parents_lines) == 1:
- lines = self._reannotate_one(parents_lines[0], new_lines,
- new_revision_id, _left_matching_blocks)
- elif len(parents_lines) == 2:
- left = self._reannotate_one(parents_lines[0], new_lines,
- new_revision_id, _left_matching_blocks)
- lines = self._reannotate_annotated(parents_lines[1], new_lines,
- new_revision_id, left)
+ if len(annotated_parents_lines) == 0:
+ lines = [(child_revision_id, line) for line in plain_child_lines]
+ elif len(annotated_parents_lines) == 1:
+ lines = self._reannotate_one(annotated_parents_lines[0],
+ plain_child_lines, child_revision_id,
+ left_matching_blocks)
+ elif len(annotated_parents_lines) == 2:
+ left = self._reannotate_one(annotated_parents_lines[0],
+ plain_child_lines, child_revision_id,
+ left_matching_blocks)
+ lines = self._reannotate_annotated(annotated_parents_lines[1],
+ plain_child_lines, child_revision_id, left)
else:
# Annotate the child lines versus each parent, and then match up the
# lines one-by-one
- reannotations = [self._reannotate_one(parents_lines[0], new_lines,
- new_revision_id, _left_matching_blocks)]
- reannotations.extend(self._reannotate_one(p, new_lines,
- new_revision_id)
- for p in parents_lines[1:])
+ reannotations = [self._reannotate_one(annotated_parents_lines[0],
+ plain_child_lines, child_revision_id,
+ left_matching_blocks)]
+ reannotations.extend(self._reannotate_one(p, plain_child_lines,
+ child_revision_id)
+ for p in annotated_parents_lines[1:])
lines = []
for annos in zip(*reannotations):
origins = set(a for a, l in annos)
@@ -103,12 +106,12 @@
lines.append(annos[0])
else:
line = annos[0][1]
- if len(origins) == 2 and new_revision_id in origins:
- origins.remove(new_revision_id)
+ if len(origins) == 2 and child_revision_id in origins:
+ origins.remove(child_revision_id)
if len(origins) == 1:
lines.append((origins.pop(), line))
else:
- lines.append((new_revision_id, line))
+ lines.append((child_revision_id, line))
return lines
def _reannotate_one(self, annotated_parent_lines, plain_child_lines,
=== modified file 'bzrlib/tests/test_annotate.py'
--- a/bzrlib/tests/test_annotate.py 2008-06-05 22:47:45 +0000
+++ b/bzrlib/tests/test_annotate.py 2008-06-06 02:29:51 +0000
@@ -23,6 +23,8 @@
annotate,
conflicts,
errors,
+ graph,
+ revision,
tests,
trace,
)
@@ -112,14 +114,17 @@
# We always change the fourth line so that the file is properly tracked as
# being modified in each revision. In reality, this probably would happen over
# many revisions, and it would be a different line that changes.
+#
+# The actual annotations will vary slightly based on the algorithm. For the
+# default algorithm, the values are as noted.
+#
# BASE
# |\
# A B # line should be annotated as new for A and B
# |\|
-# C D # line should 'converge' and say D
+# C D # line should 'converge' and say B
# |/
-# E # D should supersede A and stay as D (not become E because C references
-# A)
+# E # B should supersede A and stay as B
duplicate_base = annotation("""\
rev-base first
rev-base second
@@ -470,7 +475,29 @@
new_text, 'rev2', blocks)
-class TestAnnotationPolicy(tests.TestCaseWithTransport):
+class _AnnotationScenario(object):
+ """A class encapsulating results for an annotation use case."""
+
+class TestAnnotationPolicy(tests.TestCase):
+ """Base helper for testing different annotation policies"""
+
+ self._duplicate_base = duplicate_base
+ self._duplicate_A = duplicate_A
+ self._duplicate_B = duplicate_B
+ self._duplicate_C = duplicate_C
+ self._duplicate_D = duplicate_D
+ self._duplicate_E = duplicate_E
+
+ self._revision_graph = {
+ 'rev-base':(revision.NULL_REVISION),
+ 'rev-A':('rev-base',),
+ 'rev-B':('rev-base',),
+ 'rev-C':('rev-A',),
+ 'rev-D':('rev-B', 'rev-A',),
+ 'rev-E':('rev-C', 'rev-D',),
+ }
+
+ self._annotation_policy = None
def create_duplicate_lines_tree(self):
tree1 = self.make_branch_and_tree('tree1')
@@ -504,8 +531,15 @@
tree1.commit('E', rev_id='rev-E')
return tree1
- def assertRepoAnnotate(self, expected, repo, file_id, revision_id):
+ def get_heads_provider(self):
+ parent_provider = graph.DictParentsProvider(self._revision_graph)
+ graph_obj = graph.Graph(parent_provider)
+ return graph.FrozenHeadsCache(graph_obj)
+
+ def assertReannotate(self, expected, annotated_parents_lines,
+ plain_child_lines, new_id):
"""Assert that the revision is properly annotated."""
+ policy = self._annotation_policy(self.get_heads_provider())
actual = list(repo.revision_tree(revision_id).annotate_iter(file_id))
if actual != expected:
# Create an easier to understand diff when the lines don't actually
@@ -513,15 +547,37 @@
self.assertEqualDiff(''.join('\t'.join(l) for l in expected),
''.join('\t'.join(l) for l in actual))
- def test_annotate_duplicate_lines(self):
+ def help_test_annotate_duplicate_lines(self):
# XXX: Should this be a repository_implementations test?
- tree1 = self.create_duplicate_lines_tree()
- repo = tree1.branch.repository
- repo.lock_read()
- self.addCleanup(repo.unlock)
- self.assertRepoAnnotate(duplicate_base, repo, 'file-id', 'rev-base')
- self.assertRepoAnnotate(duplicate_A, repo, 'file-id', 'rev-A')
- self.assertRepoAnnotate(duplicate_B, repo, 'file-id', 'rev-B')
- self.assertRepoAnnotate(duplicate_C, repo, 'file-id', 'rev-C')
- self.assertRepoAnnotate(duplicate_D, repo, 'file-id', 'rev-D')
- self.assertRepoAnnotate(duplicate_E, repo, 'file-id', 'rev-E')
+ self.assertAnnotate(self._duplicate_base, [],
+ 'rev-base')
+ self.assertAnnotate(self._duplicate_A, repo, 'file-id', 'rev-A')
+ self.assertAnnotate(self._duplicate_B, repo, 'file-id', 'rev-B')
+ self.assertAnnotate(self._duplicate_C, repo, 'file-id', 'rev-C')
+ self.assertAnnotate(self._duplicate_D, repo, 'file-id', 'rev-D')
+ self.assertAnnotate(self._duplicate_E, repo, 'file-id', 'rev-E')
+
+
+class TestMergeNodeAnnotationPolicy(TestAnnotationPolicy):
+ #
+ # BASE
+ # |\
+ # A B # line should be annotated as new for A and B
+ # |\|
+ # C D # line should 'converge' and say D
+ # |/
+ # E # D should supersede A and stay as D (not become E because C
+ # # references A)
+ self._duplicate_D = annotation("""\
+rev-base first
+rev-D alt-second
+rev-base third
+rev-D fourth-D
+""")
+
+ self._duplicate_E = annotation("""\
+rev-base first
+rev-D alt-second
+rev-base third
+rev-E fourth-E
+""")
More information about the bazaar-commits
mailing list