Rev 3678: Begin fixing bug #233817. in lp:~vila/bzr/233817-missing

Vincent Ladeuil v.ladeuil+lp at free.fr
Wed Sep 3 17:33:37 BST 2008


At lp:~vila/bzr/233817-missing

------------------------------------------------------------
revno: 3678
revision-id: v.ladeuil+lp at free.fr-20080903163327-hpgcpvx2ziit96og
parent: pqm at pqm.ubuntu.com-20080902062416-dxdxccqki90bcynl
committer: Vincent Ladeuil <v.ladeuil+lp at free.fr>
branch nick: 233817-missing
timestamp: Wed 2008-09-03 18:33:27 +0200
message:
  Begin fixing bug #233817.
  
  * tests/test_missing.py:
  revnos returned by fin_unmerged are strings, update tests.
  (TestFindUnmerged.test_include_merges): Check that we get the
  merged revisions too.
  
  * missing.py:
  (find_unmerged): Add 'reverse' and 'include_merges' parameters.
  (_enumerate_mainline): Add reverse parameter so that we reverse
  the mainline revision list only when needed.
  (_enumerate_with_merges): When including merges, building the
  revision list is a bit more work.
  (_find_unmerged): Build the revision list depending on
  include_merges.
  
  * log.py:
  (LineLogFormatter.log_string): Fix doc string, the revno may be a
  string.
  
  * builtins.py:
  (cmd_missing): Add an '--include-merges' option. Let fin_unmerged
  handles the ordering.
modified:
  bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
  bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
  bzrlib/missing.py              missing.py-20050812153334-097f7097e2a8bcd1
  bzrlib/tests/test_missing.py   test_missing.py-20051212000028-694fa4f658a81f48
-------------- next part --------------
=== modified file 'bzrlib/builtins.py'
--- a/bzrlib/builtins.py	2008-09-01 23:49:18 +0000
+++ b/bzrlib/builtins.py	2008-09-03 16:33:27 +0000
@@ -3318,14 +3318,17 @@
             Option('other', 'Same as --theirs-only.'),
             'log-format',
             'show-ids',
-            'verbose'
+            'verbose',
+            Option('include-merges', 'Show merged revisions.'),
             ]
     encoding_type = 'replace'
 
     @display_command
     def run(self, other_branch=None, reverse=False, mine_only=False,
-            theirs_only=False, log_format=None, long=False, short=False, line=False, 
-            show_ids=False, verbose=False, this=False, other=False):
+            theirs_only=False,
+            log_format=None, long=False, short=False, line=False,
+            show_ids=False, verbose=False, this=False, other=False,
+            include_merges=False):
         from bzrlib.missing import find_unmerged, iter_log_revisions
 
         if this:
@@ -3361,7 +3364,9 @@
             remote_branch.lock_read()
             try:
                 local_extra, remote_extra = find_unmerged(
-                    local_branch, remote_branch, restrict)
+                    local_branch, remote_branch, restrict,
+                    reverse=reverse,
+                    include_merges=include_merges)
 
                 if log_format is None:
                     registry = log.log_formatter_registry
@@ -3369,11 +3374,6 @@
                 lf = log_format(to_file=self.outf,
                                 show_ids=show_ids,
                                 show_timezone='original')
-                if reverse is False:
-                    if local_extra is not None:
-                        local_extra.reverse()
-                    if remote_extra is not None:
-                        remote_extra.reverse()
 
                 status_code = 0
                 if local_extra and not theirs_only:

=== modified file 'bzrlib/log.py'
--- a/bzrlib/log.py	2008-09-01 00:56:53 +0000
+++ b/bzrlib/log.py	2008-09-03 16:33:27 +0000
@@ -642,7 +642,7 @@
     elif direction != 'reverse':
         raise ValueError('invalid direction %r' % direction)
 
-    for sequence, rev_id, merge_depth, revno, end_of_merge in merge_sorted_revisions:
+    for seq, rev_id, merge_depth, revno, end_of_merge in merge_sorted_revisions:
         yield rev_id, '.'.join(map(str, revno)), merge_depth
 
 
@@ -865,7 +865,7 @@
 
     def log_string(self, revno, rev, max_chars):
         """Format log info into one string. Truncate tail of string
-        :param  revno:      revision number (int) or None.
+        :param  revno:      revision number or None.
                             Revision numbers counts from 1.
         :param  rev:        revision info object
         :param  max_chars:  maximum length of resulting string

=== modified file 'bzrlib/missing.py'
--- a/bzrlib/missing.py	2008-05-20 02:34:01 +0000
+++ b/bzrlib/missing.py	2008-09-03 16:33:27 +0000
@@ -16,8 +16,10 @@
 
 """Display what revisions are missing in 'other' from 'this' and vice versa."""
 
-from bzrlib.log import (
-    LogRevision,
+from bzrlib import (
+    log,
+    repository as _mod_repository,
+    tsort,
     )
 
 
@@ -39,10 +41,11 @@
             delta = revision_tree.changes_from(parent_tree)
         else:
             delta = None
-        yield LogRevision(rev, revno, delta=delta)
-
-
-def find_unmerged(local_branch, remote_branch, restrict='all'):
+        yield log.LogRevision(rev, revno, delta=delta)
+
+
+def find_unmerged(local_branch, remote_branch, restrict='all',
+                  include_merges=False, reverse=False):
     """Find revisions from each side that have not been merged.
 
     :param local_branch: Compare the history of local_branch
@@ -52,6 +55,10 @@
         unique revisions from both sides. If 'local', we will return None
         for the remote revisions, similarly if 'remote' we will return None for
         the local revisions.
+    :param include_merges: Show mainline revisions only if False,
+        all revisions otherwise.
+    :param reverse: Show oldest versions first when True, newest versions
+        first when False. 
 
     :return: A list of [(revno, revision_id)] for the mainline revisions on
         each side.
@@ -60,15 +67,16 @@
     try:
         remote_branch.lock_read()
         try:
-            return _find_unmerged(local_branch,
-                remote_branch, restrict=restrict)
+            return _find_unmerged(
+                local_branch, remote_branch, restrict=restrict,
+                include_merges=include_merges, reverse=reverse)
         finally:
             remote_branch.unlock()
     finally:
         local_branch.unlock()
 
 
-def _enumerate_mainline(ancestry, graph, tip_revno, tip):
+def _enumerate_mainline(ancestry, graph, tip_revno, tip, reverse=False):
     """Enumerate the mainline revisions for these revisions.
 
     :param ancestry: A set of revisions that we care about
@@ -95,14 +103,51 @@
         parents = parent_map.get(cur)
         if not parents:
             break # Ghost, we are done
-        mainline.append((cur_revno, cur))
+        mainline.append((str(cur_revno), cur))
         cur = parents[0]
         cur_revno -= 1
-    mainline.reverse()
+    if reverse:
+        mainline.reverse()
     return mainline
 
 
-def _find_unmerged(local_branch, remote_branch, restrict):
+def _enumerate_with_merges(ancestry, graph, tip_revno, tip, reverse=False):
+    """Enumerate the revisions for the ancestry.
+
+    :param ancestry: A set of revisions that we care about
+    :param graph: A Graph which lets us find the parents for a revision
+    :param tip_revno: The revision number for the tip revision
+    :param tip: The tip of the ancsetry
+    :return: [(revno, revision_id)] for all revisions in ancestry that
+        are parents from tip, or None if ancestry is None.
+    """
+    if ancestry is None:
+        return None
+    if not ancestry: #Empty ancestry, no need to do any work
+        return []
+
+    parent_map = graph.get_parent_map(ancestry)
+    # filter out ghosts; merge_sort errors on ghosts. 
+    # XXX: is this needed here ? -- vila080903
+    rev_graph = _mod_repository._strip_NULL_ghosts(parent_map)
+    # XXX: what if rev_graph is empty now ?
+    merge_sorted_revisions = tsort.merge_sort(rev_graph, tip,
+                                              None, generate_revno=True)
+    # merge_sort calculate revno for the given graph, we have to recalculate
+    # the correct revno from the tip_revno.
+    ms_tip_revno = merge_sorted_revisions[0][3]
+    revno_delta = tip_revno - ms_tip_revno[0]
+    if reverse:
+        merge_sorted_revisions = log.reverse_by_depth(merge_sorted_revisions)
+    revline = []
+    for seq, rev_id, merge_depth, revno, end_of_merge in merge_sorted_revisions:
+        real_revno = (revno[0] + revno_delta,) + revno[1:]
+        revline.append(('.'.join(map(str, real_revno)), rev_id))
+    return revline
+
+
+def _find_unmerged(local_branch, remote_branch, restrict,
+                   include_merges, reverse):
     """See find_unmerged.
 
     The branches should already be locked before entering.
@@ -112,29 +157,34 @@
     if local_revno == remote_revno and local_revision_id == remote_revision_id:
         # A simple shortcut when the tips are at the same point
         return [], []
-    graph = local_branch.repository.get_graph(
-                remote_branch.repository)
+    graph = local_branch.repository.get_graph(remote_branch.repository)
     if restrict == 'remote':
         local_extra = None
-        remote_extra = graph.find_unique_ancestors(
-            remote_revision_id, [local_revision_id])
+        remote_extra = graph.find_unique_ancestors(remote_revision_id,
+                                                   [local_revision_id])
     elif restrict == 'local':
         remote_extra = None
-        local_extra = graph.find_unique_ancestors(
-            local_revision_id, [remote_revision_id])
+        local_extra = graph.find_unique_ancestors(local_revision_id,
+                                                  [remote_revision_id])
     else:
         if restrict != 'all':
             raise ValueError('param restrict not one of "all", "local",'
                              ' "remote": %r' % (restrict,))
-        local_extra, remote_extra = graph.find_difference(
-            local_revision_id, remote_revision_id)
-    # Now that we have unique ancestors, compute just the mainline, and
-    # generate revnos for them.
-    local_mainline = _enumerate_mainline(local_extra, graph, local_revno,
-                                         local_revision_id)
-    remote_mainline = _enumerate_mainline(remote_extra, graph, remote_revno,
-                                          remote_revision_id)
-    return local_mainline, remote_mainline
+        local_extra, remote_extra = graph.find_difference(local_revision_id,
+                                                          remote_revision_id)
+    if include_merges:
+        locals = _enumerate_with_merges(local_extra, graph, local_revno,
+                                        local_revision_id, reverse)
+        remotes = _enumerate_with_merges(remote_extra, graph, remote_revno,
+                                      remote_revision_id, reverse)
+    else:
+        # Now that we have unique ancestors, compute just the mainline, and
+        # generate revnos for them.
+        locals = _enumerate_mainline(local_extra, graph, local_revno,
+                                     local_revision_id, reverse)
+        remotes = _enumerate_mainline(remote_extra, graph, remote_revno,
+                                      remote_revision_id, reverse)
+    return locals, remotes
 
 
 def sorted_revisions(revisions, history_map):

=== modified file 'bzrlib/tests/test_missing.py'
--- a/bzrlib/tests/test_missing.py	2008-05-19 21:35:52 +0000
+++ b/bzrlib/tests/test_missing.py	2008-09-03 16:33:27 +0000
@@ -33,7 +33,7 @@
     def assertUnmerged(self, expected, source, target, restrict='all'):
         unmerged = missing.find_unmerged(source, target, restrict=restrict)
         self.assertEqual(expected, unmerged)
-            
+
     def test_find_unmerged(self):
         original_tree = self.make_branch_and_tree('original')
         original = original_tree.branch
@@ -43,24 +43,24 @@
         merger = merger_tree.branch
         self.assertUnmerged(([], []), original, puller)
         original_tree.commit('a', rev_id='a')
-        self.assertUnmerged(([(1, 'a')], []), original, puller)
+        self.assertUnmerged(([('1', 'a')], []), original, puller)
         puller_tree.pull(original)
         self.assertUnmerged(([], []), original, puller)
         merger_tree.pull(original)
         original_tree.commit('b', rev_id='b')
         original_tree.commit('c', rev_id='c')
-        self.assertUnmerged(([(2, 'b'), (3, 'c')], []),
+        self.assertUnmerged(([('2', 'b'), ('3', 'c')], []),
                             original, puller)
 
         puller_tree.pull(original)
         self.assertUnmerged(([], []), original, puller)
-        self.assertUnmerged(([(2, 'b'), (3, 'c')], []),
+        self.assertUnmerged(([('2', 'b'), ('3', 'c')], []),
                             original, merger)
         merger_tree.merge_from_branch(original)
-        self.assertUnmerged(([(2, 'b'), (3, 'c')], []),
+        self.assertUnmerged(([('2', 'b'), ('3', 'c')], []),
                             original, merger)
         merger_tree.commit('d', rev_id='d')
-        self.assertUnmerged(([], [(2, 'd')]), original, merger)
+        self.assertUnmerged(([], [('2', 'd')]), original, merger)
 
     def test_iter_log_revisions(self):
         base_tree = self.make_branch_and_tree('base')
@@ -85,7 +85,7 @@
 
         base_extra, child_extra = missing.find_unmerged(base_tree.branch,
                                                         child_tree.branch)
-        results = list(iter_log_revisions(base_extra, 
+        results = list(iter_log_revisions(base_extra,
                             base_tree.branch.repository,
                             verbose=True))
         self.assertEqual([], results)
@@ -97,10 +97,10 @@
 
         r0,r1,r2,r3 = results
 
-        self.assertEqual((2, 'c-2'), (r0.revno, r0.rev.revision_id))
-        self.assertEqual((3, 'c-3'), (r1.revno, r1.rev.revision_id))
-        self.assertEqual((4, 'c-4'), (r2.revno, r2.rev.revision_id))
-        self.assertEqual((5, 'c-5'), (r3.revno, r3.rev.revision_id))
+        self.assertEqual(('2', 'c-2'), (r0.revno, r0.rev.revision_id))
+        self.assertEqual(('3', 'c-3'), (r1.revno, r1.rev.revision_id))
+        self.assertEqual(('4', 'c-4'), (r2.revno, r2.rev.revision_id))
+        self.assertEqual(('5', 'c-5'), (r3.revno, r3.rev.revision_id))
 
         delta0 = r0.delta
         self.assertNotEqual(None, delta0)
@@ -135,10 +135,11 @@
 class TestFindUnmerged(tests.TestCaseWithTransport):
 
     def assertUnmerged(self, local, remote, local_branch, remote_branch,
-                       restrict):
+                       restrict, include_merges=False):
         """Check the output of find_unmerged_mainline_revisions"""
         local_extra, remote_extra = missing.find_unmerged(
-                                        local_branch, remote_branch, restrict)
+                                        local_branch, remote_branch, restrict,
+                                        include_merges=include_merges)
         self.assertEqual(local, local_extra)
         self.assertEqual(remote, remote_extra)
 
@@ -154,25 +155,17 @@
         rev1 = tree.commit('one')
         tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
         rev2 = tree2.commit('two')
-        tree.lock_read()
-        self.addCleanup(tree.unlock)
-        tree2.lock_read()
-        self.addCleanup(tree2.unlock)
-        self.assertUnmerged([], [(2, rev2)], tree.branch, tree2.branch, 'all')
-        self.assertUnmerged([(2, rev2)], [], tree2.branch, tree.branch, 'all')
+        self.assertUnmerged([], [('2', rev2)], tree.branch, tree2.branch, 'all')
+        self.assertUnmerged([('2', rev2)], [], tree2.branch, tree.branch, 'all')
 
     def test_restrict(self):
         tree = self.make_branch_and_tree('tree')
         rev1 = tree.commit('one')
         tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
         rev2 = tree2.commit('two')
-        tree.lock_read()
-        self.addCleanup(tree.unlock)
-        tree2.lock_read()
-        self.addCleanup(tree2.unlock)
-        self.assertUnmerged([], [(2, rev2)], tree.branch, tree2.branch, 'all')
+        self.assertUnmerged([], [('2', rev2)], tree.branch, tree2.branch, 'all')
         self.assertUnmerged([], None, tree.branch, tree2.branch, 'local')
-        self.assertUnmerged(None, [(2, rev2)], tree.branch, tree2.branch,
+        self.assertUnmerged(None, [('2', rev2)], tree.branch, tree2.branch,
                                                'remote')
 
     def test_merged(self):
@@ -184,9 +177,29 @@
         tree.merge_from_branch(tree2.branch)
         rev4 = tree.commit('four')
 
-        tree.lock_read()
-        self.addCleanup(tree.unlock)
-        tree2.lock_read()
-        self.addCleanup(tree2.unlock)
-
-        self.assertUnmerged([(2, rev4)], [], tree.branch, tree2.branch, 'all')
+        self.assertUnmerged([('2', rev4)], [], tree.branch, tree2.branch, 'all')
+
+    def test_include_merges(self):
+        tree = self.make_branch_and_tree('tree')
+        rev1 = tree.commit('one', rev_id='rev1')
+
+        tree2 = tree.bzrdir.sprout('tree2').open_workingtree()
+        rev2 = tree2.commit('two', rev_id='rev2')
+        rev3 = tree2.commit('three', rev_id='rev3')
+
+        tree3 = tree2.bzrdir.sprout('tree3').open_workingtree()
+        rev4 = tree3.commit('four', rev_id='rev4')
+        rev5 = tree3.commit('five', rev_id='rev5')
+
+        tree2.merge_from_branch(tree3.branch)
+        rev6 = tree2.commit('six', rev_id='rev6')
+
+        import pdb; pdb.set_trace()
+        self.assertUnmerged([], [('4', 'rev6'),
+                                 ('3.1.2', 'rev5'), ('3.1.1', 'rev4'),
+                                 ('3', 'rev3'), ('2', 'rev2'),
+                                 ],
+                            tree.branch, tree2.branch, 'all',
+                            include_merges=True)
+
+    # TODO: test_dont_include_already_merged_merges ?



More information about the bazaar-commits mailing list