Rev 4034: Create and use a RPC call to create branches on bzr servers rather than using VFS calls. in http://people.ubuntu.com/~robertc/baz2.0/push.roundtrips

Robert Collins robertc at robertcollins.net
Tue Feb 24 05:37:21 GMT 2009


At http://people.ubuntu.com/~robertc/baz2.0/push.roundtrips

------------------------------------------------------------
revno: 4034
revision-id: robertc at robertcollins.net-20090224053717-sau62hnxgo2f1pzr
parent: robertc at robertcollins.net-20090223051205-92ypm6chik138tpy
committer: Robert Collins <robertc at robertcollins.net>
branch nick: push.roundtrips
timestamp: Tue 2009-02-24 16:37:17 +1100
message:
  Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
=== modified file 'NEWS'
--- a/NEWS	2009-02-23 01:26:23 +0000
+++ b/NEWS	2009-02-24 05:37:17 +0000
@@ -70,6 +70,13 @@
 
   INTERNALS:
 
+    * Branch and Repository creation on a bzr+ssh://server are now done
+      via RPC calls rather than VFS calls, reducing round trips for
+      pushing new branches substantially. (Robert Collins)
+
+    * ``BzrDirFormat.__str__`` now uses the human readable description
+      rather than the sometimes-absent disk label. (Robert Collins)
+
     * ``bzrlib.fetch`` is now composed of a sender and a sink component
       allowing for decoupling over a network connection. Fetching into
       a RemoteRepository uses this to stream the operation.
@@ -81,13 +88,13 @@
     * ``bzrlib.tests.run_suite`` accepts a runner_class parameter
       supporting the use of different runners. (Robert Collins)
 
-    * Creating a repository on a bzr+ssh:// server will now make a single
-      call rather than many VFS calls. (Robert Collins)
-
     * New hook Commands['extend_command'] to allow plugins to access a
       command object before the command is run (or help generated from
       it), without overriding the command. (Robert Collins)
 
+    * ``RemoteBranchFormat`` no longer claims to have a disk format string.
+      (Robert Collins)
+
     * ``RepositoryFormat`` objects now have a ``network_name`` for passing
       the format across RPC calls. (Robert Collins, Andrew Bennetts)
 

=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2009-02-23 05:12:05 +0000
+++ b/bzrlib/branch.py	2009-02-24 05:37:17 +0000
@@ -1297,7 +1297,7 @@
         del klass._formats[format.get_format_string()]
 
     def __str__(self):
-        return self.get_format_string().rstrip()
+        return self.get_format_description().rstrip()
 
     def supports_tags(self):
         """True if this format supports tags stored in the branch"""

=== modified file 'bzrlib/bzrdir.py'
--- a/bzrlib/bzrdir.py	2009-02-21 06:33:41 +0000
+++ b/bzrlib/bzrdir.py	2009-02-24 05:37:17 +0000
@@ -1850,7 +1850,7 @@
 
     def __str__(self):
         # Trim the newline
-        return self.get_format_string().rstrip()
+        return self.get_format_description().rstrip()
 
     def _supply_sub_formats_to(self, other_format):
         """Give other_format the same values for sub formats as this has.
@@ -2084,8 +2084,9 @@
             # target doesn't support stacking.  So force a branch that *can*
             # support stacking.
             from bzrlib.branch import BzrBranchFormat7
-            self._branch_format = BzrBranchFormat7()
-            mutter("using %r for stacking" % (self._branch_format,))
+            branch_format = BzrBranchFormat7()
+            self.set_branch_format(branch_format)
+            mutter("using %r for stacking" % (branch_format,))
             from bzrlib.repofmt import pack_repo
             if self.repository_format.rich_root_data:
                 bzrdir_format_name = '1.6.1-rich-root'
@@ -2698,6 +2699,9 @@
 
     def get_format_description(self):
         return 'bzr remote bzrdir'
+
+    def get_format_string(self):
+        raise NotImplementedError(self.get_format_string)
     
     @classmethod
     def probe_transport(klass, transport):
@@ -2764,6 +2768,16 @@
             result.rich_root_data = custom_format.rich_root_data
         return result
 
+    def get_branch_format(self):
+        result = BzrDirMetaFormat1.get_branch_format(self)
+        if not isinstance(result, remote.RemoteBranchFormat):
+            new_result = remote.RemoteBranchFormat()
+            new_result._custom_format = result
+            # cache the result
+            self.set_branch_format(new_result)
+            result = new_result
+        return result
+
     repository_format = property(__return_repository_format,
         BzrDirMetaFormat1._set_repository_format) #.im_func)
 

=== modified file 'bzrlib/push.py'
--- a/bzrlib/push.py	2009-01-02 01:58:48 +0000
+++ b/bzrlib/push.py	2009-02-24 05:37:17 +0000
@@ -103,6 +103,8 @@
         # all of the dependent branches, etc.
         dir_to = br_from.bzrdir.clone_on_transport(to_transport,
             revision_id=revision_id, stacked_on=stacked_on)
+        # XXX: Fix this API to allow getting the branch back from the clone
+        # call. Or something. 20090224 RBC/spiv.
         br_to = dir_to.open_branch()
         # TODO: Some more useful message about what was copied
         try:

=== modified file 'bzrlib/remote.py'
--- a/bzrlib/remote.py	2009-02-23 05:12:05 +0000
+++ b/bzrlib/remote.py	2009-02-24 05:37:17 +0000
@@ -69,7 +69,18 @@
                 method, args, body_bytes)
         except errors.ErrorFromSmartServer, err:
             self._translate_error(err, **err_context)
-        
+
+
+def response_tuple_to_repo_format(response):
+    """Convert a response tuple describing a repository format to a format."""
+    format = RemoteRepositoryFormat()
+    format.rich_root_data = (response[0] == 'yes')
+    format.supports_tree_reference = (response[1] == 'yes')
+    format.supports_external_lookups = (response[2] == 'yes')
+    format._network_name = response[3]
+    return format
+
+
 # Note: RemoteBzrDirFormat is in bzrdir.py
 
 class RemoteBzrDir(BzrDir, _RpcHelper):
@@ -343,11 +354,7 @@
             return self._vfs_initialize(a_bzrdir, shared)
         else:
             # Turn the response into a RemoteRepository object.
-            format = RemoteRepositoryFormat()
-            format.rich_root_data = (response[1] == 'yes')
-            format.supports_tree_reference = (response[2] == 'yes')
-            format.supports_external_lookups = (response[3] == 'yes')
-            format._network_name = response[4]
+            format = response_tuple_to_repo_format(response[1:])
             # Used to support creating a real format instance when needed.
             format._creating_bzrdir = a_bzrdir
             remote_repo = RemoteRepository(a_bzrdir, format)
@@ -382,12 +389,19 @@
 
     @property
     def _serializer(self):
-        # We should only be getting asked for the serializer for
-        # RemoteRepositoryFormat objects when the RemoteRepositoryFormat object
-        # is a concrete instance for a RemoteRepository. In this case we know
-        # the creating_repo and can use it to supply the serializer.
-        self._creating_repo._ensure_real()
-        return self._creating_repo._real_repository._format._serializer
+        if self._custom_format is not None:
+            return self._custom_format._serializer
+        elif self._network_name is not None:
+            self._custom_format = repository.network_format_registry.get(
+                self._network_name)
+            return self._custom_format._serializer
+        else:
+            # We should only be getting asked for the serializer for
+            # RemoteRepositoryFormat objects when the RemoteRepositoryFormat object
+            # is a concrete instance for a RemoteRepository. In this case we know
+            # the creating_repo and can use it to supply the serializer.
+            self._creating_repo._ensure_real()
+            return self._creating_repo._real_repository._format._serializer
 
 
 class RemoteRepository(_RpcHelper):
@@ -754,6 +768,8 @@
             raise errors.UnexpectedSmartServerResponse(response)
 
     def unlock(self):
+        if not self._lock_count:
+            raise errors.LockNotHeld(self)
         self._lock_count -= 1
         if self._lock_count > 0:
             return
@@ -1456,6 +1472,7 @@
         super(RemoteBranchFormat, self).__init__()
         self._matchingbzrdir = RemoteBzrDirFormat()
         self._matchingbzrdir.set_branch_format(self)
+        self._custom_format = None
 
     def __eq__(self, other):
         return (isinstance(other, RemoteBranchFormat) and 
@@ -1464,28 +1481,69 @@
     def get_format_description(self):
         return 'Remote BZR Branch'
 
-    def get_format_string(self):
-        return 'Remote BZR Branch'
-
     def network_name(self):
         return self._network_name
 
     def open(self, a_bzrdir):
         return a_bzrdir.open_branch()
 
+    def _vfs_initialize(self, a_bzrdir):
+        # Initialisation when using a local bzrdir object, or a non-vfs init
+        # method is not available on the server.
+        # self._custom_format is always set - the start of initialize ensures
+        # that.
+        if isinstance(a_bzrdir, RemoteBzrDir):
+            a_bzrdir._ensure_real()
+            result = self._custom_format.initialize(a_bzrdir._real_bzrdir)
+        else:
+            # We assume the bzrdir is parameterised; it may not be.
+            result = self._custom_format.initialize(a_bzrdir)
+        if (isinstance(a_bzrdir, RemoteBzrDir) and
+            not isinstance(result, RemoteBranch)):
+            result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result)
+        return result
+
     def initialize(self, a_bzrdir):
-        # Delegate to a _real object here - the RemoteBzrDir format now
-        # supports delegating to parameterised branch formats and as such
-        # this RemoteBranchFormat method is only called when no specific format
-        # is selected.
+        # 1) get the network name to use.
+        if self._custom_format:
+            network_name = self._custom_format.network_name()
+        else:
+            # Select the current bzrlib default and ask for that.
+            reference_bzrdir_format = bzrdir.format_registry.get('default')()
+            reference_format = reference_bzrdir_format.get_branch_format()
+            self._custom_format = reference_format
+            network_name = reference_format.network_name()
+        # Being asked to create on a non RemoteBzrDir:
         if not isinstance(a_bzrdir, RemoteBzrDir):
-            result = a_bzrdir.create_branch()
+            return self._vfs_initialize(a_bzrdir)
+        medium = a_bzrdir._client._medium
+        if medium._is_remote_before((1, 13)):
+            return self._vfs_initialize(a_bzrdir)
+        # Creating on a remote bzr dir.
+        # 2) try direct creation via RPC
+        path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
+        verb = 'BzrDir.create_branch'
+        try:
+            response = a_bzrdir._call(verb, path, network_name)
+        except errors.UnknownSmartMethod:
+            # Fallback - use vfs methods
+            return self._vfs_initialize(a_bzrdir)
+        if response[0] != 'ok':
+            raise errors.UnexpectedSmartServerResponse(response)
+        # Turn the response into a RemoteRepository object.
+        format = RemoteBranchFormat()
+        format._network_name = response[1]
+        repo_format = response_tuple_to_repo_format(response[3:])
+        if response[2] == '':
+            repo_bzrdir = a_bzrdir
         else:
-            a_bzrdir._ensure_real()
-            result = a_bzrdir._real_bzrdir.create_branch()
-        if not isinstance(result, RemoteBranch):
-            result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result)
-        return result
+            repo_bzrdir = RemoteBzrDir(
+                a_bzrdir.root_transport.clone(response[2]), a_bzrdir._format,
+                a_bzrdir._client)
+        remote_repo = RemoteRepository(repo_bzrdir, repo_format)
+        remote_branch = RemoteBranch(a_bzrdir, remote_repo,
+            format=format, setup_stacking=False)
+        return remote_branch
 
     def supports_tags(self):
         # Remote branches might support tags, but we won't know until we
@@ -1500,12 +1558,18 @@
     """
 
     def __init__(self, remote_bzrdir, remote_repository, real_branch=None,
-        _client=None):
+        _client=None, format=None, setup_stacking=True):
         """Create a RemoteBranch instance.
 
         :param real_branch: An optional local implementation of the branch
             format, usually accessing the data via the VFS.
         :param _client: Private parameter for testing.
+        :param format: A RemoteBranchFormat object, None to create one
+            automatically. If supplied it should have a network_name already
+            supplied.
+        :param setup_stacking: If True make an RPC call to determine the
+            stacked (or not) status of the branch. If False assume the branch
+            is not stacked.
         """
         # We intentionally don't call the parent class's __init__, because it
         # will try to assign to self.tags, which is a property in this subclass.
@@ -1534,7 +1598,6 @@
         else:
             self._real_branch = None
         # Fill out expected attributes of branch for bzrlib api users.
-        self._format = RemoteBranchFormat()
         self.base = self.bzrdir.root_transport.base
         self._control_files = None
         self._lock_mode = None
@@ -1542,19 +1605,27 @@
         self._repo_lock_token = None
         self._lock_count = 0
         self._leave_lock = False
-        if real_branch is not None:
-            self._format._network_name = \
-                self._real_branch._format.network_name()
+        # Setup a format: note that we cannot call _ensure_real until all the
+        # attributes above are set: This code cannot be moved higher up in this
+        # function.
+        if format is None:
+            self._format = RemoteBranchFormat()
+            if real_branch is not None:
+                self._format._network_name = \
+                    self._real_branch._format.network_name()
+            #else:
+            #    # XXX: Need to get this from BzrDir.open_branch's return value.
+            #    self._ensure_real()
+            #    self._format._network_name = \
+            #        self._real_branch._format.network_name()
         else:
-            # XXX: Need to get this from BzrDir.open_branch's return value.
-            self._ensure_real()
-            self._format._network_name = \
-                self._real_branch._format.network_name()
+            self._format = format
         # The base class init is not called, so we duplicate this:
         hooks = branch.Branch.hooks['open']
         for hook in hooks:
             hook(self)
-        self._setup_stacking()
+        if setup_stacking:
+            self._setup_stacking()
 
     def _setup_stacking(self):
         # configure stacking into the remote repository, by reading it from
@@ -1900,25 +1971,6 @@
         self._ensure_real()
         return self._real_branch.set_stacked_on_url(stacked_location)
 
-    def sprout(self, to_bzrdir, revision_id=None):
-        branch_format = to_bzrdir._format._branch_format
-        if (branch_format is None or
-            isinstance(branch_format, RemoteBranchFormat)):
-            # The to_bzrdir specifies RemoteBranchFormat (or no format, which
-            # implies the same thing), but RemoteBranches can't be created at
-            # arbitrary URLs.  So create a branch in the same format as
-            # _real_branch instead.
-            # XXX: if to_bzrdir is a RemoteBzrDir, this should perhaps do
-            # to_bzrdir.create_branch to create a RemoteBranch after all...
-            self._ensure_real()
-            result = self._real_branch._format.initialize(to_bzrdir)
-            self.copy_content_into(result, revision_id=revision_id)
-            result.set_parent(self.bzrdir.root_transport.base)
-        else:
-            result = branch.Branch.sprout(
-                self, to_bzrdir, revision_id=revision_id)
-        return result
-
     @needs_write_lock
     def pull(self, source, overwrite=False, stop_revision=None,
              **kwargs):

=== modified file 'bzrlib/smart/bzrdir.py'
--- a/bzrlib/smart/bzrdir.py	2009-02-19 07:28:37 +0000
+++ b/bzrlib/smart/bzrdir.py	2009-02-24 05:37:17 +0000
@@ -17,14 +17,13 @@
 """Server-side bzrdir related request implmentations."""
 
 
-from bzrlib import errors
+from bzrlib import branch, errors, repository
 from bzrlib.bzrdir import BzrDir, BzrDirFormat
 from bzrlib.smart.request import (
     FailedSmartServerResponse,
     SmartServerRequest,
     SuccessfulSmartServerResponse,
     )
-from bzrlib.repository import network_format_registry
 
 
 class SmartServerRequestOpenBzrDir(SmartServerRequest):
@@ -68,6 +67,54 @@
             repo_format.supports_external_lookups)
         return rich_root, tree_ref, external_lookup
 
+    def _repo_relpath(self, current_transport, repository):
+        """Get the relative path for repository from current_transport."""
+        # the relpath of the bzrdir in the found repository gives us the
+        # path segments to pop-out.
+        relpath = repository.bzrdir.root_transport.relpath(
+            current_transport.base)
+        if len(relpath):
+            segments = ['..'] * len(relpath.split('/'))
+        else:
+            segments = []
+        return '/'.join(segments)
+
+
+class SmartServerRequestCreateBranch(SmartServerRequestBzrDir):
+
+    def do(self, path, network_name):
+        """Create a branch in the bzr dir at path.
+
+        This operates precisely like 'bzrdir.create_branch'.
+
+        If a bzrdir is not present, an exception is propogated
+        rather than 'no branch' because these are different conditions (and
+        this method should only be called after establishing that a bzr dir
+        exists anyway).
+
+        This is the initial version of this method introduced to the smart
+        server for 1.13.
+
+        :param path: The path to the bzrdir.
+        :param network_name: The network name of the branch type to create.
+        :return: (ok, network_name)
+        """
+        bzrdir = BzrDir.open_from_transport(
+            self.transport_from_client_path(path))
+        format = branch.network_format_registry.get(network_name)
+        bzrdir.branch_format = format
+        result = format.initialize(bzrdir)
+        rich_root, tree_ref, external_lookup = self._format_to_capabilities(
+            result.repository._format)
+        branch_format = result._format.network_name()
+        repo_format = result.repository._format.network_name()
+        repo_path = self._repo_relpath(bzrdir.root_transport,
+            result.repository)
+        # branch format, repo relpath, rich_root, tree_ref, external_lookup,
+        # repo_network_name
+        return SuccessfulSmartServerResponse(('ok', branch_format, repo_path,
+            rich_root, tree_ref, external_lookup, repo_format))
+
 
 class SmartServerRequestCreateRepository(SmartServerRequestBzrDir):
 
@@ -93,7 +140,7 @@
         bzrdir = BzrDir.open_from_transport(
             self.transport_from_client_path(path))
         shared = shared == 'True'
-        format = network_format_registry.get(network_name)
+        format = repository.network_format_registry.get(network_name)
         bzrdir.repository_format = format
         result = format.initialize(bzrdir, shared=shared)
         rich_root, tree_ref, external_lookup = self._format_to_capabilities(
@@ -118,17 +165,10 @@
         bzrdir = BzrDir.open_from_transport(
             self.transport_from_client_path(path))
         repository = bzrdir.find_repository()
-        # the relpath of the bzrdir in the found repository gives us the 
-        # path segments to pop-out.
-        relpath = repository.bzrdir.root_transport.relpath(
-            bzrdir.root_transport.base)
-        if len(relpath):
-            segments = ['..'] * len(relpath.split('/'))
-        else:
-            segments = []
+        path = self._repo_relpath(bzrdir.root_transport, repository)
         rich_root, tree_ref, external_lookup = self._format_to_capabilities(
             repository._format)
-        return '/'.join(segments), rich_root, tree_ref, external_lookup
+        return path, rich_root, tree_ref, external_lookup
 
 
 class SmartServerRequestFindRepositoryV1(SmartServerRequestFindRepository):

=== modified file 'bzrlib/smart/request.py'
--- a/bzrlib/smart/request.py	2009-02-20 08:26:50 +0000
+++ b/bzrlib/smart/request.py	2009-02-24 05:37:17 +0000
@@ -401,6 +401,8 @@
 request_handlers.register_lazy(
     'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock')
 request_handlers.register_lazy(
+    'BzrDir.create_branch', 'bzrlib.smart.bzrdir', 'SmartServerRequestCreateBranch')
+request_handlers.register_lazy(
     'BzrDir.create_repository', 'bzrlib.smart.bzrdir', 'SmartServerRequestCreateRepository')
 request_handlers.register_lazy(
     'BzrDir.find_repository', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV1')

=== modified file 'bzrlib/tests/blackbox/test_push.py'
--- a/bzrlib/tests/blackbox/test_push.py	2009-02-23 05:12:05 +0000
+++ b/bzrlib/tests/blackbox/test_push.py	2009-02-24 05:37:17 +0000
@@ -202,7 +202,7 @@
         # being too low. If rpc_count increases, more network roundtrips have
         # become necessary for this use case. Please do not adjust this number
         # upwards without agreement from bzr's network support maintainers.
-        self.assertEqual(64, rpc_count)
+        self.assertEqual(40, rpc_count)
 
     def test_push_smart_stacked_streaming_acceptance(self):
         self.setup_smart_server_with_call_log()
@@ -219,7 +219,7 @@
         # being too low. If rpc_count increases, more network roundtrips have
         # become necessary for this use case. Please do not adjust this number
         # upwards without agreement from bzr's network support maintainers.
-        self.assertEqual(88, rpc_count)
+        self.assertEqual(65, rpc_count)
         remote = Branch.open('public')
         self.assertEndsWith(remote.get_stacked_on_url(), '/parent')
 

=== modified file 'bzrlib/tests/blackbox/test_upgrade.py'
--- a/bzrlib/tests/blackbox/test_upgrade.py	2009-01-16 02:49:35 +0000
+++ b/bzrlib/tests/blackbox/test_upgrade.py	2009-02-24 05:37:17 +0000
@@ -68,8 +68,8 @@
         # when up to date we should get a message to that effect
         (out, err) = self.run_bzr('upgrade current_format_branch', retcode=3)
         self.assertEqual("", out)
-        self.assertEqualDiff("bzr: ERROR: The branch format Bazaar-NG meta "
-                             "directory, format 1 is already at the most "
+        self.assertEqualDiff("bzr: ERROR: The branch format Meta "
+                             "directory format 1 is already at the most "
                              "recent format.\n", err)
 
     def test_upgrade_up_to_date_checkout_warns_branch_left_alone(self):
@@ -81,8 +81,8 @@
                          "upgraded separately.\n"
                          % get_transport(self.get_url('current_format_branch')).base,
                          out)
-        self.assertEqualDiff("bzr: ERROR: The branch format Bazaar-NG meta "
-                             "directory, format 1 is already at the most "
+        self.assertEqualDiff("bzr: ERROR: The branch format Meta "
+                             "directory format 1 is already at the most "
                              "recent format.\n", err)
 
     def test_upgrade_checkout(self):

=== modified file 'bzrlib/tests/branch_implementations/test_hooks.py'
--- a/bzrlib/tests/branch_implementations/test_hooks.py	2009-02-13 00:52:18 +0000
+++ b/bzrlib/tests/branch_implementations/test_hooks.py	2009-02-24 05:37:17 +0000
@@ -20,6 +20,7 @@
 from bzrlib.errors import HookFailed, TipChangeRejected
 from bzrlib.remote import RemoteBranch
 from bzrlib.revision import NULL_REVISION
+from bzrlib.smart import server
 from bzrlib.tests import TestCaseWithMemoryTransport
 
 
@@ -147,12 +148,17 @@
         b = self.make_branch('.')
         if isinstance(b, RemoteBranch):
             # RemoteBranch creation:
-            # - creates the branch via the VFS
+            # - creates the branch via the VFS (for older servers)
             # - does a branch open (by creating a RemoteBranch object)
-            # - this has the same behaviour as simple branch opening, with an
-            # additional VFS open at the front.
-            self.assertEqual(b._real_branch, self.hook_calls[0])
-            self.assertOpenedRemoteBranch(self.hook_calls[1:], b)
+            # - this has the nearly the same behaviour as simple branch opening
+            if (self.transport_readonly_server ==
+                server.ReadonlySmartTCPServer_for_testing_v2_only):
+                # Older servers:
+                self.assertEqual(b._real_branch, self.hook_calls[0])
+                self.assertOpenedRemoteBranch(self.hook_calls[1:], b)
+            else:
+                self.assertOpenedRemoteBranch(self.hook_calls, b,
+                    remote_first=True)
         else:
             self.assertEqual([b], self.hook_calls)
 
@@ -165,17 +171,31 @@
         else:
             self.assertEqual([b], self.hook_calls)
 
-    def assertOpenedRemoteBranch(self, hook_calls, b):
-        """Assert that the expected calls were recorded for opening 'b'."""
+    def assertOpenedRemoteBranch(self, hook_calls, b, remote_first=False):
+        """Assert that the expected calls were recorded for opening 'b'.
+
+        :param remote_first: If True expect the server side operation to open
+            the branch object first.
+        """
         # RemoteBranch open always opens the backing branch to get stacking
         # details. As that is done remotely we can't see the branch object
         # nor even compare base url's etc. So we just assert that the first
         # branch returned is the RemoteBranch, and that the second is a
         # Branch but not a RemoteBranch.
+        #
+        # RemoteBranch *creation* on the other hand creates the branch object
+        # on the server, and then creates the local proxy object in the client,
+        # so it sees the reverse order.
         self.assertEqual(2, len(hook_calls))
-        self.assertEqual(b, hook_calls[0])
-        self.assertIsInstance(hook_calls[1], Branch)
-        self.assertFalse(isinstance(hook_calls[1], RemoteBranch))
+        if remote_first:
+            real_index = 0
+            remote_index = 1
+        else:
+            real_index = 1
+            remote_index = 0
+        self.assertEqual(b, hook_calls[remote_index])
+        self.assertIsInstance(hook_calls[real_index], Branch)
+        self.assertFalse(isinstance(hook_calls[real_index], RemoteBranch))
 
 
 class TestPreChangeBranchTip(ChangeBranchTipTestCase):

=== modified file 'bzrlib/tests/branch_implementations/test_sprout.py'
--- a/bzrlib/tests/branch_implementations/test_sprout.py	2009-02-13 00:52:18 +0000
+++ b/bzrlib/tests/branch_implementations/test_sprout.py	2009-02-24 05:37:17 +0000
@@ -70,6 +70,9 @@
             # did the right thing.
             target._ensure_real()
             target = target._real_branch
+        if isinstance(result_format, remote.RemoteBranchFormat):
+            # Unwrap a parameterised RemoteBranchFormat for comparison.
+            result_format = result_format._custom_format
         self.assertIs(result_format.__class__, target._format.__class__)
 
     def test_sprout_partial(self):

=== modified file 'bzrlib/tests/test_errors.py'
--- a/bzrlib/tests/test_errors.py	2009-02-21 06:33:41 +0000
+++ b/bzrlib/tests/test_errors.py	2009-02-24 05:37:17 +0000
@@ -256,8 +256,8 @@
 
     def test_up_to_date(self):
         error = errors.UpToDateFormat(bzrdir.BzrDirFormat4())
-        self.assertEqualDiff("The branch format Bazaar-NG branch, "
-                             "format 0.0.4 is already at the most "
+        self.assertEqualDiff("The branch format All-in-one "
+                             "format 4 is already at the most "
                              "recent format.",
                              str(error))
 

=== modified file 'bzrlib/tests/test_remote.py'
--- a/bzrlib/tests/test_remote.py	2009-02-20 03:28:07 +0000
+++ b/bzrlib/tests/test_remote.py	2009-02-24 05:37:17 +0000
@@ -459,6 +459,42 @@
             RemoteBzrDirFormat.probe_transport, OldServerTransport())
 
 
+class TestBzrDirCreateBranch(TestRemote):
+
+    def test_backwards_compat(self):
+        self.setup_smart_server_with_call_log()
+        repo = self.make_repository('.')
+        self.reset_smart_call_log()
+        self.disable_verb('BzrDir.create_branch')
+        branch = repo.bzrdir.create_branch()
+        create_branch_call_count = len([call for call in self.hpss_calls if
+            call[0].method == 'BzrDir.create_branch'])
+        self.assertEqual(1, create_branch_call_count)
+
+    def test_current_server(self):
+        transport = self.get_transport('.')
+        transport = transport.clone('quack')
+        self.make_repository('quack')
+        client = FakeClient(transport.base)
+        reference_bzrdir_format = bzrdir.format_registry.get('default')()
+        reference_format = reference_bzrdir_format.get_branch_format()
+        network_name = reference_format.network_name()
+        reference_repo_fmt = reference_bzrdir_format.repository_format
+        reference_repo_name = reference_repo_fmt.network_name()
+        client.add_expected_call(
+            'BzrDir.create_branch', ('quack/', network_name),
+            'success', ('ok', network_name, '', 'no', 'no', 'yes',
+            reference_repo_name))
+        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
+            _client=client)
+        branch = a_bzrdir.create_branch()
+        # We should have got a remote branch
+        self.assertIsInstance(branch, remote.RemoteBranch)
+        # its format should have the settings from the response
+        format = branch._format
+        self.assertEqual(network_name, format.network_name())
+
+
 class TestBzrDirCreateRepository(TestRemote):
 
     def test_backwards_compat(self):
@@ -831,7 +867,6 @@
         branch = self.make_remote_branch(transport, client)
         branch._ensure_real = lambda: None
         branch.lock_write()
-        self.addCleanup(branch.unlock)
         # The 'TipChangeRejected' error response triggered by calling
         # set_revision_history causes a TipChangeRejected exception.
         err = self.assertRaises(




More information about the bazaar-commits mailing list