Rev 2452: (John Arbash Meinel) Add Branch.get_revision_id_to_revno_map in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Tue Apr 24 23:44:31 BST 2007


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

------------------------------------------------------------
revno: 2452
revision-id: pqm at pqm.ubuntu.com-20070424224426-po331pf12jpzmrvk
parent: pqm at pqm.ubuntu.com-20070424141924-i4w482pi1pb95pob
parent: john at arbash-meinel.com-20070424220920-1pamgmk2mo44wlm3
committer: Canonical.com Patch Queue Manager<pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Tue 2007-04-24 23:44:26 +0100
message:
  (John Arbash Meinel) Add Branch.get_revision_id_to_revno_map
added:
  bzrlib/tests/branch_implementations/test_get_revision_id_to_revno_map.py test_get_revision_id-20070417211641-6kcoj1c704gqqopn-1
  bzrlib/tests/branch_implementations/test_revision_id_to_revno.py test_revision_id_to_-20070417200738-lo776wkqikhe5goo-1
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/annotate.py             annotate.py-20050922133147-7c60541d2614f022
  bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
  bzrlib/memorytree.py           memorytree.py-20060906023413-4wlkalbdpsxi2r4y-1
  bzrlib/mutabletree.py          mutabletree.py-20060906023413-4wlkalbdpsxi2r4y-2
  bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
  bzrlib/revisionspec.py         revisionspec.py-20050907152633-17567659fd5c0ddb
  bzrlib/tests/branch_implementations/__init__.py __init__.py-20060123013057-b12a52c3f361daf4
  bzrlib/tests/branch_implementations/test_branch.py testbranch.py-20050711070244-121d632bc37d7253
    ------------------------------------------------------------
    revno: 2418.5.15
    merged: john at arbash-meinel.com-20070424220920-1pamgmk2mo44wlm3
    parent: john at arbash-meinel.com-20070424194505-mv5dwjw0mx4tfpfs
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: branch_revision_id_to_revno
    timestamp: Tue 2007-04-24 17:09:20 -0500
    message:
      NEWS
    ------------------------------------------------------------
    revno: 2418.5.14
    merged: john at arbash-meinel.com-20070424194505-mv5dwjw0mx4tfpfs
    parent: john at arbash-meinel.com-20070424194309-nt3sxw7x4sqwnykh
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: branch_revision_id_to_revno
    timestamp: Tue 2007-04-24 14:45:05 -0500
    message:
      clean up ASCII revision graph art.
    ------------------------------------------------------------
    revno: 2418.5.13
    merged: john at arbash-meinel.com-20070424194309-nt3sxw7x4sqwnykh
    parent: john at arbash-meinel.com-20070424194013-zjckbpsbq7vff1wh
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: branch_revision_id_to_revno
    timestamp: Tue 2007-04-24 14:43:09 -0500
    message:
      Remove revision_id_to_dotted_revno, because it isn't used.
    ------------------------------------------------------------
    revno: 2418.5.12
    merged: john at arbash-meinel.com-20070424194013-zjckbpsbq7vff1wh
    parent: john at arbash-meinel.com-20070424032327-w2tz2smz41eco4u1
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: branch_revision_id_to_revno
    timestamp: Tue 2007-04-24 14:40:13 -0500
    message:
      Move functions from BzrBranch to base Branch object.
      Fix RemoteBranch to properly clear its cache at the right time.
    ------------------------------------------------------------
    revno: 2418.5.11
    merged: john at arbash-meinel.com-20070424032327-w2tz2smz41eco4u1
    parent: john at arbash-meinel.com-20070417213150-yf8r9e1ufueedb3q
    parent: pqm at pqm.ubuntu.com-20070423170758-qd512ltqglzfo6w9
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: branch_revision_id_to_revno
    timestamp: Mon 2007-04-23 22:23:27 -0500
    message:
      [merge] bzr.dev 2447
    ------------------------------------------------------------
    revno: 2418.5.10
    merged: john at arbash-meinel.com-20070417213150-yf8r9e1ufueedb3q
    parent: john at arbash-meinel.com-20070417212608-84w0sw1e7tiuhgr4
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: branch_revision_id_to_revno
    timestamp: Tue 2007-04-17 16:31:50 -0500
    message:
      fix typo
    ------------------------------------------------------------
    revno: 2418.5.9
    merged: john at arbash-meinel.com-20070417212608-84w0sw1e7tiuhgr4
    parent: john at arbash-meinel.com-20070417211929-rchob1jeahy30cj0
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: branch_revision_id_to_revno
    timestamp: Tue 2007-04-17 16:26:08 -0500
    message:
      Have RevisionSpec_revno() also use the new helper
    ------------------------------------------------------------
    revno: 2418.5.8
    merged: john at arbash-meinel.com-20070417211929-rchob1jeahy30cj0
    parent: john at arbash-meinel.com-20070417211809-f225hrm1juxoityu
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: branch_revision_id_to_revno
    timestamp: Tue 2007-04-17 16:19:29 -0500
    message:
      Update annotate.py to use the new helper function.
    ------------------------------------------------------------
    revno: 2418.5.7
    merged: john at arbash-meinel.com-20070417211809-f225hrm1juxoityu
    parent: john at arbash-meinel.com-20070417210124-rfr3w1llh869058q
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: branch_revision_id_to_revno
    timestamp: Tue 2007-04-17 16:18:09 -0500
    message:
      Move the revision_id=>map generation to be a public function.
    ------------------------------------------------------------
    revno: 2418.5.6
    merged: john at arbash-meinel.com-20070417210124-rfr3w1llh869058q
    parent: john at arbash-meinel.com-20070417203323-xbmbi9cyjr6cocuf
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: branch_revision_id_to_revno
    timestamp: Tue 2007-04-17 16:01:24 -0500
    message:
      Cache the revision_id => revno map as appropriate.
    ------------------------------------------------------------
    revno: 2418.5.5
    merged: john at arbash-meinel.com-20070417203323-xbmbi9cyjr6cocuf
    parent: john at arbash-meinel.com-20070417202335-0cc0thlj5sy28m9m
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: branch_revision_id_to_revno
    timestamp: Tue 2007-04-17 15:33:23 -0500
    message:
      Add some tests and an api for revision_id_to_dotted_revno
      This should use caching to be fast for multiple calls
      but for now it just implements what is needed.
    ------------------------------------------------------------
    revno: 2418.5.4
    merged: john at arbash-meinel.com-20070417202335-0cc0thlj5sy28m9m
    parent: john at arbash-meinel.com-20070417201836-2bso1f1clhhx7k1a
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: branch_revision_id_to_revno
    timestamp: Tue 2007-04-17 15:23:35 -0500
    message:
      Included a test for revision_id=None
    ------------------------------------------------------------
    revno: 2418.5.3
    merged: john at arbash-meinel.com-20070417201836-2bso1f1clhhx7k1a
    parent: john at arbash-meinel.com-20070417201724-5seu77st1h843nie
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: branch_revision_id_to_revno
    timestamp: Tue 2007-04-17 15:18:36 -0500
    message:
      Use a more straightforward implementation of generating 'tree_with_merge'
    ------------------------------------------------------------
    revno: 2418.5.2
    merged: john at arbash-meinel.com-20070417201724-5seu77st1h843nie
    parent: john at arbash-meinel.com-20070417201004-1v7sim0tlt19l8o4
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: branch_revision_id_to_revno
    timestamp: Tue 2007-04-17 15:17:24 -0500
    message:
      Move TestCaseWithBranch into branch_implementations from test_branch.py
    ------------------------------------------------------------
    revno: 2418.5.1
    merged: john at arbash-meinel.com-20070417201004-1v7sim0tlt19l8o4
    parent: pqm at pqm.ubuntu.com-20070413174100-zpfqleaf5ph9ycx4
    committer: John Arbash Meinel <john at arbash-meinel.com>
    branch nick: branch_revision_id_to_revno
    timestamp: Tue 2007-04-17 15:10:04 -0500
    message:
      Make a Branch helper which can create a very basic MemoryTree with history.
      This updates MutableTree to include 'set_parent_ids' which is helpful
      when setting up simple tests.
      It also creates a helper function in branch_implementations..TestCaseWithBranch
      so that we can create a Branch which has a simple merge in it.
      It also adds a test for revision_id_to_revno which previously did not have any
      direct tests.
=== added file 'bzrlib/tests/branch_implementations/test_get_revision_id_to_revno_map.py'
--- a/bzrlib/tests/branch_implementations/test_get_revision_id_to_revno_map.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/branch_implementations/test_get_revision_id_to_revno_map.py	2007-04-24 19:43:09 +0000
@@ -0,0 +1,118 @@
+# Copyright (C) 2007 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Tests for Branch.get_revision_id_to_revno_map()"""
+
+from bzrlib import (
+    errors,
+    revision,
+    )
+
+from bzrlib.tests.branch_implementations import TestCaseWithBranch
+
+
+class TestRevisionIdToDottedRevno(TestCaseWithBranch):
+
+    def test_simple_revno(self):
+        tree = self.create_tree_with_merge()
+        the_branch = tree.branch
+
+        self.assertEqual({'rev-1':(1,), 'rev-2':(2,), 'rev-3':(3,),
+                          'rev-1.1.1':(1,1,1)
+                         }, tree.branch.get_revision_id_to_revno_map())
+
+
+class TestCaching(TestCaseWithBranch):
+    """Tests for the caching of branches' dotted revno generation.
+
+    When locked, branches should avoid regenerating revision_id=>dotted revno
+    mapping.
+
+    When not locked, obviously the revision_id => dotted revno will need to be
+    regenerated or reread each time.
+
+    We test if revision_history is using the cache by instrumenting the branch's
+    _gen_revno_map method, which is called by get_revision_id_to_revno_map.
+    """
+
+    def get_instrumented_branch(self):
+        """Get a branch and monkey patch it to log calls to _gen_revno_map.
+
+        :returns: a tuple of (the branch, list that calls will be logged to)
+        """
+        tree = self.create_tree_with_merge()
+        calls = []
+        real_func = tree.branch._gen_revno_map
+        def wrapper():
+            calls.append('_gen_revno_map')
+            return real_func()
+        tree.branch._gen_revno_map = wrapper
+        return tree.branch, calls
+
+    def test_unlocked(self):
+        """Repeated calls will call _gen_revno_map each time."""
+        branch, calls = self.get_instrumented_branch()
+        # Repeatedly call revision_history.
+        branch.get_revision_id_to_revno_map()
+        branch.get_revision_id_to_revno_map()
+        branch.get_revision_id_to_revno_map()
+        self.assertEqual(['_gen_revno_map']*3, calls)
+
+    def test_locked(self):
+        """Repeated calls will only call _gen_revno_map once.
+        """
+        branch, calls = self.get_instrumented_branch()
+        # Lock the branch, then repeatedly call revision_history.
+        branch.lock_read()
+        try:
+            branch.get_revision_id_to_revno_map()
+            self.assertEqual(['_gen_revno_map'], calls)
+        finally:
+            branch.unlock()
+
+    def test_set_revision_history_when_locked(self):
+        """Calling set_revision_history should reset the cache."""
+        branch, calls = self.get_instrumented_branch()
+        branch.lock_write()
+        try:
+            self.assertEqual({'rev-1':(1,), 'rev-2':(2,), 'rev-3':(3,),
+                              'rev-1.1.1':(1,1,1)
+                             }, branch.get_revision_id_to_revno_map())
+            branch.set_revision_history(['rev-1', 'rev-2'])
+            self.assertEqual({'rev-1':(1,), 'rev-2':(2,)},
+                             branch.get_revision_id_to_revno_map())
+            self.assertEqual({'rev-1':(1,), 'rev-2':(2,)},
+                             branch.get_revision_id_to_revno_map())
+            self.assertEqual(['_gen_revno_map']*2, calls)
+        finally:
+            branch.unlock()
+
+    def test_set_last_revision_info_when_locked(self):
+        """Calling set_last_revision_info should reset the cache."""
+        branch, calls = self.get_instrumented_branch()
+        branch.lock_write()
+        try:
+            self.assertEqual({'rev-1':(1,), 'rev-2':(2,), 'rev-3':(3,),
+                              'rev-1.1.1':(1,1,1)
+                             }, branch.get_revision_id_to_revno_map())
+            branch.set_last_revision_info(2, 'rev-2')
+            self.assertEqual({'rev-1':(1,), 'rev-2':(2,)},
+                             branch.get_revision_id_to_revno_map())
+            self.assertEqual({'rev-1':(1,), 'rev-2':(2,)},
+                             branch.get_revision_id_to_revno_map())
+            self.assertEqual(['_gen_revno_map']*2, calls)
+        finally:
+            branch.unlock()

=== added file 'bzrlib/tests/branch_implementations/test_revision_id_to_revno.py'
--- a/bzrlib/tests/branch_implementations/test_revision_id_to_revno.py	1970-01-01 00:00:00 +0000
+++ b/bzrlib/tests/branch_implementations/test_revision_id_to_revno.py	2007-04-17 20:23:35 +0000
@@ -0,0 +1,41 @@
+# Copyright (C) 2007 Canonical Ltd
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+"""Tests for Branch.revision_id_to_revno()"""
+
+from bzrlib import errors
+
+from bzrlib.tests.branch_implementations import TestCaseWithBranch
+
+
+class TestRevisionIdToRevno(TestCaseWithBranch):
+
+    def test_simple_revno(self):
+        tree = self.create_tree_with_merge()
+        the_branch = tree.branch
+
+        self.assertEqual(0, the_branch.revision_id_to_revno(None))
+        self.assertEqual(1, the_branch.revision_id_to_revno('rev-1'))
+        self.assertEqual(2, the_branch.revision_id_to_revno('rev-2'))
+        self.assertEqual(3, the_branch.revision_id_to_revno('rev-3'))
+
+        self.assertRaises(errors.NoSuchRevision,
+                          the_branch.revision_id_to_revno, 'rev-none')
+        # revision_id_to_revno is defined as returning only integer revision
+        # numbers, so non-mainline revisions get NoSuchRevision raised
+        self.assertRaises(errors.NoSuchRevision,
+                          the_branch.revision_id_to_revno, 'rev-1.1.1')
+

=== modified file 'NEWS'
--- a/NEWS	2007-04-24 05:02:04 +0000
+++ b/NEWS	2007-04-24 22:44:26 +0000
@@ -140,6 +140,12 @@
     * New class 'TransportListRegistry', derived from the Registry class, which 
       simplifies tracking the available Transports. (Goffredo Baroncelli)
 
+    * New function ``Branch.get_revision_id_to_revno_map`` which will
+      return a dictionary mapping revision ids to dotted revnos. Since
+      dotted revnos are defined in the context of the branch tip, it makes
+      sense to generate them from a ``Branch`` object.
+      (John Arbash Meinel)
+
   BUGFIXES:
 
     * Don't fail bundle selftest if email has 'two' embedded.  

=== modified file 'bzrlib/annotate.py'
--- a/bzrlib/annotate.py	2007-02-02 09:17:23 +0000
+++ b/bzrlib/annotate.py	2007-04-17 21:19:29 +0000
@@ -89,16 +89,7 @@
     This includes detailed information, such as the committer name, and
     date string for the commit, rather than just the revision id.
     """
-    branch_last_revision = branch.last_revision()
-    revision_graph = branch.repository.get_revision_graph(branch_last_revision)
-    merge_sorted_revisions = tsort.merge_sort(
-        revision_graph,
-        branch_last_revision,
-        None,
-        generate_revno=True)
-    revision_id_to_revno = dict((rev_id, revno)
-                                for seq_num, rev_id, depth, revno, end_of_merge
-                                 in merge_sorted_revisions)
+    revision_id_to_revno = branch.get_revision_id_to_revno_map()
     w = branch.repository.weave_store.get_weave(file_id,
         branch.repository.get_transaction())
     last_origin = None

=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2007-04-18 05:10:19 +0000
+++ b/bzrlib/branch.py	2007-04-24 19:43:09 +0000
@@ -35,6 +35,7 @@
         revision as _mod_revision,
         transport,
         tree,
+        tsort,
         ui,
         urlutils,
         )
@@ -100,6 +101,7 @@
     def __init__(self, *ignored, **ignored_too):
         self.tags = self._make_tags()
         self._revision_history_cache = None
+        self._revision_id_to_revno_cache = None
 
     def break_lock(self):
         """Break a lock if one is present from another instance.
@@ -195,6 +197,48 @@
     def get_physical_lock_status(self):
         raise NotImplementedError(self.get_physical_lock_status)
 
+    @needs_read_lock
+    def get_revision_id_to_revno_map(self):
+        """Return the revision_id => dotted revno map.
+
+        This will be regenerated on demand, but will be cached.
+
+        :return: A dictionary mapping revision_id => dotted revno.
+            This dictionary should not be modified by the caller.
+        """
+        if self._revision_id_to_revno_cache is not None:
+            mapping = self._revision_id_to_revno_cache
+        else:
+            mapping = self._gen_revno_map()
+            self._cache_revision_id_to_revno(mapping)
+        # TODO: jam 20070417 Since this is being cached, should we be returning
+        #       a copy?
+        # I would rather not, and instead just declare that users should not
+        # modify the return value.
+        return mapping
+
+    def _gen_revno_map(self):
+        """Create a new mapping from revision ids to dotted revnos.
+
+        Dotted revnos are generated based on the current tip in the revision
+        history.
+        This is the worker function for get_revision_id_to_revno_map, which
+        just caches the return value.
+
+        :return: A dictionary mapping revision_id => dotted revno.
+        """
+        last_revision = self.last_revision()
+        revision_graph = self.repository.get_revision_graph(last_revision)
+        merge_sorted_revisions = tsort.merge_sort(
+            revision_graph,
+            last_revision,
+            None,
+            generate_revno=True)
+        revision_id_to_revno = dict((rev_id, revno)
+                                    for seq_num, rev_id, depth, revno, end_of_merge
+                                     in merge_sorted_revisions)
+        return revision_id_to_revno
+
     def leave_lock_in_place(self):
         """Tell this branch object not to release the physical lock when this
         object is unlocked.
@@ -344,6 +388,14 @@
         """
         self._revision_history_cache = rev_history
 
+    def _cache_revision_id_to_revno(self, revision_id_to_revno):
+        """Set the cached revision_id => revno map to revision_id_to_revno.
+
+        This API is semi-public; it only for use by subclasses, all other code
+        should consider it to be private.
+        """
+        self._revision_id_to_revno_cache = revision_id_to_revno
+
     def _clear_cached_state(self):
         """Clear any cached data on this branch, e.g. cached revision history.
 
@@ -354,6 +406,7 @@
         should consider it to be private.
         """
         self._revision_history_cache = None
+        self._revision_id_to_revno_cache = None
 
     def _gen_revision_history(self):
         """Return sequence of revision hashes on to this branch.
@@ -461,7 +514,7 @@
         try:
             return history.index(revision_id) + 1
         except ValueError:
-            raise bzrlib.errors.NoSuchRevision(self, revision_id)
+            raise errors.NoSuchRevision(self, revision_id)
 
     def get_rev_id(self, revno, history=None):
         """Find the revision id of the specified revno."""
@@ -470,7 +523,7 @@
         if history is None:
             history = self.revision_history()
         if revno <= 0 or revno > len(history):
-            raise bzrlib.errors.NoSuchRevision(self, revno)
+            raise errors.NoSuchRevision(self, revno)
         return history[revno - 1]
 
     def pull(self, source, overwrite=False, stop_revision=None):
@@ -1325,6 +1378,7 @@
     def set_revision_history(self, rev_history):
         """See Branch.set_revision_history."""
         rev_history = [osutils.safe_revision_id(r) for r in rev_history]
+        self._clear_cached_state()
         self._write_revision_history(rev_history)
         self._cache_revision_history(rev_history)
         for hook in Branch.hooks['set_rh']:
@@ -1542,7 +1596,7 @@
                 try: 
                     url = url.encode('ascii')
                 except UnicodeEncodeError:
-                    raise bzrlib.errors.InvalidURL(url,
+                    raise errors.InvalidURL(url,
                         "Urls must be 7-bit ascii, "
                         "use bzrlib.urlutils.escape")
             url = urlutils.relative_url(self.base, url)

=== modified file 'bzrlib/memorytree.py'
--- a/bzrlib/memorytree.py	2007-02-06 14:52:16 +0000
+++ b/bzrlib/memorytree.py	2007-04-17 20:10:04 +0000
@@ -222,18 +222,29 @@
             else:
                 raise errors.NoSuchId(self, file_id)
 
+    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
+        """See MutableTree.set_parent_trees()."""
+        if len(revision_ids) == 0:
+            self._parent_ids = []
+            self._basis_tree = self.branch.repository.revision_tree(None)
+        else:
+            self._parent_ids = revision_ids
+            self._basis_tree = self.branch.repository.revision_tree(
+                                    revision_ids[0])
+            self._branch_revision_id = revision_ids[0]
+
     def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
         """See MutableTree.set_parent_trees()."""
         if len(parents_list) == 0:
             self._parent_ids = []
-            self._basis_tree = self.branch.repository.revisiontree(None)
+            self._basis_tree = self.branch.repository.revision_tree(None)
         else:
             if parents_list[0][1] is None and not allow_leftmost_as_ghost:
                 # a ghost in the left most parent
                 raise errors.GhostRevisionUnusableHere(parents_list[0][0])
             self._parent_ids = [parent_id for parent_id, tree in parents_list]
             if parents_list[0][1] is None:
-                self._basis_tree = self.branch.repository.revisiontree(None)
+                self._basis_tree = self.branch.repository.revision_tree(None)
             else:
                 self._basis_tree = parents_list[0][1]
             self._branch_revision_id = parents_list[0][0]

=== modified file 'bzrlib/mutabletree.py'
--- a/bzrlib/mutabletree.py	2007-04-02 17:55:02 +0000
+++ b/bzrlib/mutabletree.py	2007-04-17 20:10:04 +0000
@@ -245,6 +245,13 @@
         """
         raise NotImplementedError(self.mkdir)
 
+    def set_parent_ids(self, revision_ids, allow_leftmost_as_ghost=False):
+        """Set the parents ids of the working tree.
+
+        :param revision_ids: A list of revision_ids.
+        """
+        raise NotImplementedError(self.set_parent_ids)
+
     def set_parent_trees(self, parents_list, allow_leftmost_as_ghost=False):
         """Set the parents of the working tree.
 

=== modified file 'bzrlib/remote.py'
--- a/bzrlib/remote.py	2007-04-23 08:30:30 +0000
+++ b/bzrlib/remote.py	2007-04-24 19:40:13 +0000
@@ -901,6 +901,7 @@
             rev_id = 'null:'
         else:
             rev_id = rev_history[-1]
+        self._clear_cached_state()
         response = self._client.call('Branch.set_last_revision',
             path, self._lock_token, self._repo_lock_token, rev_id)
         if response[0] == 'NoSuchRevision':

=== modified file 'bzrlib/revisionspec.py'
--- a/bzrlib/revisionspec.py	2007-03-12 16:29:47 +0000
+++ b/bzrlib/revisionspec.py	2007-04-17 21:26:08 +0000
@@ -321,14 +321,10 @@
         if dotted:
             branch.lock_read()
             try:
-                last_rev = branch.last_revision()
-                merge_sorted_revisions = tsort.merge_sort(
-                    branch.repository.get_revision_graph(last_rev),
-                    last_rev,
-                    generate_revno=True)
-                def match(item):
-                    return item[3] == match_revno
-                revisions = filter(match, merge_sorted_revisions)
+                revision_id_to_revno = branch.get_revision_id_to_revno_map()
+                revisions = [revision_id for revision_id, revno
+                             in revision_id_to_revno.iteritems()
+                             if revno == match_revno]
             finally:
                 branch.unlock()
             if len(revisions) != 1:
@@ -336,7 +332,7 @@
             else:
                 # there is no traditional 'revno' for dotted-decimal revnos.
                 # so for  API compatability we return None.
-                return RevisionInfo(branch, None, revisions[0][1])
+                return RevisionInfo(branch, None, revisions[0])
         else:
             if revno < 0:
                 # if get_rev_id supported negative revnos, there would not be a

=== modified file 'bzrlib/tests/branch_implementations/__init__.py'
--- a/bzrlib/tests/branch_implementations/__init__.py	2007-04-18 05:38:31 +0000
+++ b/bzrlib/tests/branch_implementations/__init__.py	2007-04-24 19:45:05 +0000
@@ -24,31 +24,91 @@
 rather than in tests/branch_implementations/*.py.
 """
 
+from bzrlib import (
+    errors,
+    tests,
+    )
 from bzrlib.branch import (BranchFormat,
                            BranchTestProviderAdapter,
                            _legacy_formats,
                            )
+from bzrlib.remote import RemoteBranchFormat, RemoteBzrDirFormat
 from bzrlib.smart.server import (
     SmartTCPServer_for_testing,
     ReadonlySmartTCPServer_for_testing,
     )
-from bzrlib.tests import (
-                          adapt_modules,
-                          TestLoader,
-                          TestSuite,
-                          )
-from bzrlib.remote import RemoteBranchFormat, RemoteBzrDirFormat
+from bzrlib.tests.bzrdir_implementations.test_bzrdir import TestCaseWithBzrDir
 from bzrlib.transport.memory import MemoryServer
 
 
+class TestCaseWithBranch(TestCaseWithBzrDir):
+    """This helper will be adapted for each branch_implementation test."""
+
+    def setUp(self):
+        super(TestCaseWithBranch, self).setUp()
+        self.branch = None
+
+    def get_branch(self):
+        if self.branch is None:
+            self.branch = self.make_branch('')
+        return self.branch
+
+    def make_branch(self, relpath, format=None):
+        repo = self.make_repository(relpath, format=format)
+        # fixme RBC 20060210 this isnt necessarily a fixable thing,
+        # Skipped is the wrong exception to raise.
+        try:
+            return self.branch_format.initialize(repo.bzrdir)
+        except errors.UninitializableFormat:
+            raise tests.TestSkipped('Uninitializable branch format')
+
+    def make_repository(self, relpath, shared=False, format=None):
+        made_control = self.make_bzrdir(relpath, format=format)
+        return made_control.create_repository(shared=shared)
+
+    def create_tree_with_merge(self):
+        """Create a branch with a simple ancestry.
+
+        The graph should look like:
+            digraph H {
+                "rev-1" -> "rev-2" -> "rev-3";
+                "rev-1" -> "rev-1.1.1" -> "rev-3";
+            }
+
+        Or in ASCII:
+            1
+            |\
+            2 1.1.1
+            |/
+            3
+        """
+        tree = self.make_branch_and_memory_tree('tree')
+        tree.lock_write()
+        try:
+            tree.add('')
+            tree.commit('first', rev_id='rev-1')
+            tree.commit('second', rev_id='rev-1.1.1')
+            # Uncommit that last commit and switch to the other line
+            tree.branch.set_last_revision_info(1, 'rev-1')
+            tree.set_parent_ids(['rev-1'])
+            tree.commit('alt-second', rev_id='rev-2')
+            tree.set_parent_ids(['rev-2', 'rev-1.1.1'])
+            tree.commit('third', rev_id='rev-3')
+        finally:
+            tree.unlock()
+
+        return tree
+
+
 def test_suite():
-    result = TestSuite()
+    result = tests.TestSuite()
     test_branch_implementations = [
         'bzrlib.tests.branch_implementations.test_bound_sftp',
         'bzrlib.tests.branch_implementations.test_branch',
         'bzrlib.tests.branch_implementations.test_break_lock',
         'bzrlib.tests.branch_implementations.test_create_checkout',
         'bzrlib.tests.branch_implementations.test_commit',
+        'bzrlib.tests.branch_implementations.test_get_revision_id_to_revno_map',
         'bzrlib.tests.branch_implementations.test_hooks',
         'bzrlib.tests.branch_implementations.test_http',
         'bzrlib.tests.branch_implementations.test_last_revision_info',
@@ -58,6 +118,7 @@
         'bzrlib.tests.branch_implementations.test_pull',
         'bzrlib.tests.branch_implementations.test_push',
         'bzrlib.tests.branch_implementations.test_revision_history',
+        'bzrlib.tests.branch_implementations.test_revision_id_to_revno',
         'bzrlib.tests.branch_implementations.test_tags',
         'bzrlib.tests.branch_implementations.test_uncommit',
         'bzrlib.tests.branch_implementations.test_update',
@@ -73,9 +134,8 @@
         # by the TestCaseWithTransport.get_readonly_transport method.
         None,
         combinations)
-    loader = TestLoader()
-    adapt_modules(test_branch_implementations, adapter, loader, result)
-
+    loader = tests.TestLoader()
+    tests.adapt_modules(test_branch_implementations, adapter, loader, result)
 
     adapt_to_smart_server = BranchTestProviderAdapter(
         SmartTCPServer_for_testing,
@@ -83,9 +143,9 @@
         [(RemoteBranchFormat(), RemoteBzrDirFormat())],
         MemoryServer
         )
-    adapt_modules(test_branch_implementations,
-                  adapt_to_smart_server,
-                  loader,
-                  result)
+    tests.adapt_modules(test_branch_implementations,
+                        adapt_to_smart_server,
+                        loader,
+                        result)
 
     return result

=== modified file 'bzrlib/tests/branch_implementations/test_branch.py'
--- a/bzrlib/tests/branch_implementations/test_branch.py	2007-04-13 07:39:17 +0000
+++ b/bzrlib/tests/branch_implementations/test_branch.py	2007-04-24 03:23:27 +0000
@@ -40,7 +40,7 @@
 from bzrlib.osutils import getcwd
 import bzrlib.revision
 from bzrlib.tests import TestCase, TestCaseWithTransport, TestSkipped
-from bzrlib.tests.bzrdir_implementations.test_bzrdir import TestCaseWithBzrDir
+from bzrlib.tests.branch_implementations import TestCaseWithBranch
 from bzrlib.tests.HttpServer import HttpServer
 from bzrlib.trace import mutter
 from bzrlib.transport import get_transport
@@ -49,31 +49,6 @@
 from bzrlib.workingtree import WorkingTree
 
 
-class TestCaseWithBranch(TestCaseWithBzrDir):
-
-    def setUp(self):
-        super(TestCaseWithBranch, self).setUp()
-        self.branch = None
-
-    def get_branch(self):
-        if self.branch is None:
-            self.branch = self.make_branch('')
-        return self.branch
-
-    def make_branch(self, relpath, format=None):
-        repo = self.make_repository(relpath, format=format)
-        # fixme RBC 20060210 this isnt necessarily a fixable thing,
-        # Skipped is the wrong exception to raise.
-        try:
-            return self.branch_format.initialize(repo.bzrdir)
-        except errors.UninitializableFormat:
-            raise TestSkipped('Uninitializable branch format')
-
-    def make_repository(self, relpath, shared=False, format=None):
-        made_control = self.make_bzrdir(relpath, format=format)
-        return made_control.create_repository(shared=shared)
-
-
 class TestBranch(TestCaseWithBranch):
 
     def test_append_revisions(self):
@@ -91,6 +66,15 @@
         self.assertEquals(br.revision_history(), ["rev1", "rev2", "rev3"])
         self.assertRaises(errors.ReservedId, br.append_revision, 'current:')
 
+    def test_create_tree_with_merge(self):
+        tree = self.create_tree_with_merge()
+        ancestry_graph = tree.branch.repository.get_revision_graph('rev-3')
+        self.assertEqual({'rev-1':[],
+                          'rev-2':['rev-1'],
+                          'rev-1.1.1':['rev-1'],
+                          'rev-3':['rev-2', 'rev-1.1.1'],
+                         }, ancestry_graph)
+
     def test_revision_ids_are_utf8(self):
         wt = self.make_branch_and_tree('tree')
         wt.commit('f', rev_id='rev1')




More information about the bazaar-commits mailing list