Rev 4085: Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects. in http://people.ubuntu.com/~robertc/baz2.0/branch.roundtrips

Robert Collins robertc at robertcollins.net
Fri Mar 6 03:55:31 GMT 2009


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

------------------------------------------------------------
revno: 4085
revision-id: robertc at robertcollins.net-20090306035527-sm1gsd3nh3f2mxpa
parent: pqm at pqm.ubuntu.com-20090306030219-enauehb3achqqq7c
committer: Robert Collins <robertc at robertcollins.net>
branch nick: branch.roundtrips
timestamp: Fri 2009-03-06 14:55:27 +1100
message:
  Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
=== modified file 'NEWS'
--- a/NEWS	2009-03-06 01:01:32 +0000
+++ b/NEWS	2009-03-06 03:55:27 +0000
@@ -155,6 +155,10 @@
 
   INTERNALS:
 
+    * Branching from a non-stacked branch on a smart protocol is now
+      free of virtual file system methods.
+      (Robert Collins, Andrew Bennetts)
+
     * 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)

=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2009-03-06 01:02:59 +0000
+++ b/bzrlib/branch.py	2009-03-06 03:55:27 +0000
@@ -83,12 +83,8 @@
     # - RBC 20060112
     base = None
 
-    # override this to set the strategy for storing tags
-    def _make_tags(self):
-        return DisabledTags(self)
-
     def __init__(self, *ignored, **ignored_too):
-        self.tags = self._make_tags()
+        self.tags = self._format.make_tags(self)
         self._revision_history_cache = None
         self._revision_id_to_revno_cache = None
         self._partial_revision_id_to_revno_cache = {}
@@ -155,11 +151,25 @@
         The default implementation returns False if this branch has no tags,
         and True the rest of the time.  Subclasses may override this.
         """
-        return self.tags.supports_tags() and self.tags.get_tag_dict()
+        return self.supports_tags() and self.tags.get_tag_dict()
 
     def get_config(self):
         return BranchConfig(self)
 
+    def _get_tags_bytes(self):
+        """Get the bytes of a serialised tags dict.
+
+        Note that not all branches support tags, nor do all use the same tags
+        logic: this method is specific to BasicTags. Other tag implementations
+        may use the same method name and behave differently, safely, because
+        of the double-dispatch via
+        format.make_tags->tags_instance->get_tags_dict.
+
+        :return: The bytes of the tags file.
+        :seealso: Branch._set_tags_bytes.
+        """
+        return self._transport.get_bytes('tags')
+
     def _get_nick(self, local=False, possible_transports=None):
         config = self.get_config()
         # explicit overrides master, but don't look for master if local is True
@@ -565,6 +575,17 @@
         """
         raise NotImplementedError(self.set_stacked_on_url)
 
+    def _set_tags_bytes(self, bytes):
+        """Mirror method for _get_tags_bytes.
+
+        :seealso: Branch._get_tags_bytes.
+        """
+        self.lock_write()
+        try:
+            self._transport.put_bytes('tags', bytes)
+        finally:
+            self.unlock()
+
     def _cache_revision_history(self, rev_history):
         """Set the cached revision history to rev_history.
 
@@ -1280,6 +1301,20 @@
         """
         return True
 
+    def make_tags(self, branch):
+        """Create a tags object for branch.
+
+        This method is on BranchFormat, because BranchFormats are reflected
+        over the wire via network_name(), whereas full Branch instances require
+        multiple VFS method calls to operate at all.
+
+        The default implementation returns a disabled-tags instance.
+
+        Note that it is normal for branch to be a RemoteBranch when using tags
+        on a RemoteBranch.
+        """
+        return DisabledTags(branch)
+
     def network_name(self):
         """A simple byte string uniquely identifying this format for RPC calls.
 
@@ -1609,6 +1644,11 @@
                       ]
         return self._initialize_helper(a_bzrdir, utf8_files)
 
+    def make_tags(self, branch):
+        """See bzrlib.branch.BranchFormat.make_tags()."""
+        return BasicTags(branch)
+
+
 
 class BzrBranchFormat7(BranchFormatMetadir):
     """Branch format with last-revision, tags, and a stacked location pointer.
@@ -1643,6 +1683,10 @@
         self._matchingbzrdir.repository_format = \
             RepositoryFormatKnitPack5RichRoot()
 
+    def make_tags(self, branch):
+        """See bzrlib.branch.BranchFormat.make_tags()."""
+        return BasicTags(branch)
+
     def supports_stacking(self):
         return True
 
@@ -2505,9 +2549,6 @@
         value = self.get_config().get_user_option('append_revisions_only')
         return value == 'True'
 
-    def _make_tags(self):
-        return BasicTags(self)
-
     @needs_write_lock
     def generate_revision_history(self, revision_id, last_rev=None,
                                   other_branch=None):

=== modified file 'bzrlib/remote.py'
--- a/bzrlib/remote.py	2009-03-06 02:21:00 +0000
+++ b/bzrlib/remote.py	2009-03-06 03:55:27 +0000
@@ -226,17 +226,30 @@
 
     def get_branch_reference(self):
         """See BzrDir.get_branch_reference()."""
+        response = self._get_branch_reference()
+        if response[0] == 'ref':
+            return response[1]
+        else:
+            return None
+
+    def _get_branch_reference(self):
         path = self._path_for_remote_call(self._client)
+        medium = self._client._medium
+        if not medium._is_remote_before((1, 13)):
+            try:
+                response = self._call('BzrDir.open_branchV2', path)
+                if response[0] not in ('ref', 'branch'):
+                    raise errors.UnexpectedSmartServerResponse(response)
+                return response
+            except errors.UnknownSmartMethod:
+                pass
         response = self._call('BzrDir.open_branch', path)
-        if response[0] == 'ok':
-            if response[1] == '':
-                # branch at this location.
-                return None
-            else:
-                # a branch reference, use the existing BranchReference logic.
-                return response[1]
+        if response[0] != 'ok':
+            raise errors.UnexpectedSmartServerResponse(response)
+        if response[1] != '':
+            return ('ref', response[1])
         else:
-            raise errors.UnexpectedSmartServerResponse(response)
+            return ('branch', '')
 
     def _get_tree_branch(self):
         """See BzrDir._get_tree_branch()."""
@@ -250,14 +263,16 @@
             result = self._next_open_branch_result
             self._next_open_branch_result = None
             return result
-        reference_url = self.get_branch_reference()
-        if reference_url is None:
-            # branch at this location.
-            return RemoteBranch(self, self.find_repository())
-        else:
+        response = self._get_branch_reference()
+        if response[0] == 'ref':
             # a branch reference, use the existing BranchReference logic.
             format = BranchReferenceFormat()
             return format.open(self, _found=True, location=reference_url)
+        branch_format_name = response[1]
+        if not branch_format_name:
+            branch_format_name = None
+        format = RemoteBranchFormat(network_name=branch_format_name)
+        return RemoteBranch(self, self.find_repository(), format=format)
 
     def _open_repo_v1(self, path):
         verb = 'BzrDir.find_repository'
@@ -1562,16 +1577,22 @@
 
 class RemoteBranchFormat(branch.BranchFormat):
 
-    def __init__(self):
+    def __init__(self, network_name=None):
         super(RemoteBranchFormat, self).__init__()
         self._matchingbzrdir = RemoteBzrDirFormat()
         self._matchingbzrdir.set_branch_format(self)
         self._custom_format = None
+        self._network_name = network_name
 
     def __eq__(self, other):
         return (isinstance(other, RemoteBranchFormat) and
             self.__dict__ == other.__dict__)
 
+    def _ensure_real(self):
+        if self._custom_format is None:
+            self._custom_format = branch.network_format_registry.get(
+                self._network_name)
+
     def get_format_description(self):
         return 'Remote BZR Branch'
 
@@ -1625,8 +1646,7 @@
         if response[0] != 'ok':
             raise errors.UnexpectedSmartServerResponse(response)
         # Turn the response into a RemoteRepository object.
-        format = RemoteBranchFormat()
-        format._network_name = response[1]
+        format = RemoteBranchFormat(network_name=response[1])
         repo_format = response_tuple_to_repo_format(response[3:])
         if response[2] == '':
             repo_bzrdir = a_bzrdir
@@ -1643,10 +1663,15 @@
         remote_branch._last_revision_info_cache = 0, NULL_REVISION
         return remote_branch
 
+    def make_tags(self, branch):
+        self._ensure_real()
+        return self._custom_format.make_tags(branch)
+
     def supports_tags(self):
         # Remote branches might support tags, but we won't know until we
         # access the real remote branch.
-        return True
+        self._ensure_real()
+        return self._custom_format.supports_tags()
 
 
 class RemoteBranch(branch.Branch, _RpcHelper):
@@ -1711,13 +1736,14 @@
             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:
             self._format = format
+        if not self._format._network_name:
+            # Did not get from open_branchV2 - old server.
+            self._ensure_real()
+            self._format._network_name = \
+                self._real_branch._format.network_name()
+        self.tags = self._format.make_tags(self)
         # The base class init is not called, so we duplicate this:
         hooks = branch.Branch.hooks['open']
         for hook in hooks:
@@ -1848,6 +1874,20 @@
             raise errors.UnexpectedSmartServerResponse(response)
         return response[1]
 
+    def _vfs_get_tags_bytes(self):
+        self._ensure_real()
+        return self._real_branch._get_tags_bytes()
+
+    def _get_tags_bytes(self):
+        medium = self._client._medium
+        if medium._is_remote_before((1, 13)):
+            return self._vfs_get_tags_bytes()
+        try:
+            response = self._call('Branch.get_tags_bytes', self._remote_path())
+        except errors.UnknownSmartMethod:
+            return self._vfs_get_tags_bytes()
+        return response[0]
+
     def lock_read(self):
         self.repository.lock_read()
         if not self._lock_mode:
@@ -1907,6 +1947,10 @@
             self.repository.lock_write(self._repo_lock_token)
         return self._lock_token or None
 
+    def _set_tags_bytes(self, bytes):
+        self._ensure_real()
+        return self._real_branch._set_tags_bytes(bytes)
+
     def _unlock(self, branch_token, repo_token):
         err_context = {'token': str((branch_token, repo_token))}
         response = self._call(
@@ -2150,11 +2194,6 @@
         self.set_revision_history(self._lefthand_history(revision_id,
             last_rev=last_rev,other_branch=other_branch))
 
-    @property
-    def tags(self):
-        self._ensure_real()
-        return self._real_branch.tags
-
     def set_push_location(self, location):
         self._ensure_real()
         return self._real_branch.set_push_location(location)

=== modified file 'bzrlib/smart/branch.py'
--- a/bzrlib/smart/branch.py	2009-03-06 01:38:43 +0000
+++ b/bzrlib/smart/branch.py	2009-03-06 03:55:27 +0000
@@ -100,6 +100,14 @@
         return SuccessfulSmartServerResponse((parent,))
 
 
+class SmartServerBranchGetTagsBytes(SmartServerBranchRequest):
+
+    def do_with_branch(self, branch):
+        """Return the _get_tags_bytes for a branch."""
+        bytes = branch._get_tags_bytes()
+        return SuccessfulSmartServerResponse((bytes,))
+
+
 class SmartServerBranchRequestGetStackedOnURL(SmartServerBranchRequest):
 
     def do_with_branch(self, branch):

=== modified file 'bzrlib/smart/bzrdir.py'
--- a/bzrlib/smart/bzrdir.py	2009-03-05 04:37:03 +0000
+++ b/bzrlib/smart/bzrdir.py	2009-03-06 03:55:27 +0000
@@ -55,8 +55,11 @@
 
     def do(self, path, *args):
         """Open a BzrDir at path, and return self.do_bzrdir_request(*args)."""
-        self._bzrdir = BzrDir.open_from_transport(
-            self.transport_from_client_path(path))
+        try:
+            self._bzrdir = BzrDir.open_from_transport(
+                self.transport_from_client_path(path))
+        except errors.NotBranchError:
+            return FailedSmartServerResponse(('nobranch', ))
         return self.do_bzrdir_request(*args)
 
     def _boolean_to_yes_no(self, a_boolean):
@@ -298,21 +301,30 @@
         return SuccessfulSmartServerResponse(('ok', ))
 
 
-class SmartServerRequestOpenBranch(SmartServerRequest):
-
-    def do(self, path):
-        """try to open a branch at path and return ok/nobranch.
-
-        If a bzrdir is not present, an exception is propogated
-        rather than 'no branch' because these are different conditions.
-        """
-        bzrdir = BzrDir.open_from_transport(
-            self.transport_from_client_path(path))
+class SmartServerRequestOpenBranch(SmartServerRequestBzrDir):
+
+    def do_bzrdir_request(self):
+        """open a branch at path and return the branch reference or branch."""
         try:
-            reference_url = bzrdir.get_branch_reference()
+            reference_url = self._bzrdir.get_branch_reference()
             if reference_url is None:
                 return SuccessfulSmartServerResponse(('ok', ''))
             else:
                 return SuccessfulSmartServerResponse(('ok', reference_url))
         except errors.NotBranchError:
             return FailedSmartServerResponse(('nobranch', ))
+
+
+class SmartServerRequestOpenBranchV2(SmartServerRequestBzrDir):
+
+    def do_bzrdir_request(self):
+        """open a branch at path and return the reference or format."""
+        try:
+            reference_url = self._bzrdir.get_branch_reference()
+            if reference_url is None:
+                format = self._bzrdir.open_branch()._format.network_name()
+                return SuccessfulSmartServerResponse(('branch', format))
+            else:
+                return SuccessfulSmartServerResponse(('ref', reference_url))
+        except errors.NotBranchError:
+            return FailedSmartServerResponse(('nobranch', ))

=== modified file 'bzrlib/smart/request.py'
--- a/bzrlib/smart/request.py	2009-03-05 05:26:24 +0000
+++ b/bzrlib/smart/request.py	2009-03-06 03:55:27 +0000
@@ -388,10 +388,14 @@
 request_handlers.register_lazy(
     'append', 'bzrlib.smart.vfs', 'AppendRequest')
 request_handlers.register_lazy(
-    'Branch.get_config_file', 'bzrlib.smart.branch', 'SmartServerBranchGetConfigFile')
+    'Branch.get_config_file', 'bzrlib.smart.branch',
+    'SmartServerBranchGetConfigFile')
 request_handlers.register_lazy(
     'Branch.get_parent', 'bzrlib.smart.branch', 'SmartServerBranchGetParent')
 request_handlers.register_lazy(
+    'Branch.get_tags_bytes', 'bzrlib.smart.branch',
+    'SmartServerBranchGetTagsBytes')
+request_handlers.register_lazy(
     'Branch.get_stacked_on_url', 'bzrlib.smart.branch', 'SmartServerBranchRequestGetStackedOnURL')
 request_handlers.register_lazy(
     'Branch.last_revision_info', 'bzrlib.smart.branch', 'SmartServerBranchRequestLastRevisionInfo')
@@ -413,19 +417,29 @@
     'BzrDir.cloning_metadir', 'bzrlib.smart.bzrdir',
     'SmartServerBzrDirRequestCloningMetaDir')
 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')
-request_handlers.register_lazy(
-    'BzrDir.find_repositoryV2', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV2')
-request_handlers.register_lazy(
-    'BzrDir.find_repositoryV3', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV3')
-request_handlers.register_lazy(
-    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir', 'SmartServerRequestInitializeBzrDir')
-request_handlers.register_lazy(
-    'BzrDir.open_branch', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBranch')
+    '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')
+request_handlers.register_lazy(
+    'BzrDir.find_repositoryV2', 'bzrlib.smart.bzrdir',
+    'SmartServerRequestFindRepositoryV2')
+request_handlers.register_lazy(
+    'BzrDir.find_repositoryV3', 'bzrlib.smart.bzrdir',
+    'SmartServerRequestFindRepositoryV3')
+request_handlers.register_lazy(
+    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir',
+    'SmartServerRequestInitializeBzrDir')
+request_handlers.register_lazy(
+    'BzrDir.open_branch', 'bzrlib.smart.bzrdir',
+    'SmartServerRequestOpenBranch')
+request_handlers.register_lazy(
+    'BzrDir.open_branchV2', 'bzrlib.smart.bzrdir',
+    'SmartServerRequestOpenBranchV2')
 request_handlers.register_lazy(
     'delete', 'bzrlib.smart.vfs', 'DeleteRequest')
 request_handlers.register_lazy(

=== modified file 'bzrlib/tag.py'
--- a/bzrlib/tag.py	2009-01-17 01:30:58 +0000
+++ b/bzrlib/tag.py	2009-03-06 03:55:27 +0000
@@ -57,9 +57,6 @@
     def _not_supported(self, *a, **k):
         raise errors.TagsNotSupported(self.branch)
 
-    def supports_tags(self):
-        return False
-
     set_tag = _not_supported
     get_tag_dict = _not_supported
     _set_tag_dict = _not_supported
@@ -79,9 +76,6 @@
     """Tag storage in an unversioned branch control file.
     """
 
-    def supports_tags(self):
-        return True
-
     def set_tag(self, tag_name, tag_target):
         """Add a tag definition to the branch.
 
@@ -111,7 +105,7 @@
         self.branch.lock_read()
         try:
             try:
-                tag_content = self.branch._transport.get_bytes('tags')
+                tag_content = self.branch._get_tags_bytes()
             except errors.NoSuchFile, e:
                 # ugly, but only abentley should see this :)
                 trace.warning('No branch/tags file in %s.  '
@@ -158,14 +152,12 @@
     def _set_tag_dict(self, new_dict):
         """Replace all tag definitions
 
+        WARNING: Calling this on an unlocked branch will lock it, and will
+        replace the tags without warning on conflicts.
+
         :param new_dict: Dictionary from tag name to target.
         """
-        self.branch.lock_write()
-        try:
-            self.branch._transport.put_bytes('tags',
-                self._serialize_tag_dict(new_dict))
-        finally:
-            self.branch.unlock()
+        return self.branch._set_tags_bytes(self._serialize_tag_dict(new_dict))
 
     def _serialize_tag_dict(self, tag_dict):
         td = dict((k.encode('utf-8'), v)
@@ -205,7 +197,7 @@
         """
         if self.branch == to_tags.branch:
             return
-        if not self.supports_tags():
+        if not self.branch.supports_tags():
             # obviously nothing to copy
             return
         source_dict = self.get_tag_dict()

=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	2009-03-04 06:56:23 +0000
+++ b/bzrlib/tests/__init__.py	2009-03-06 03:55:27 +0000
@@ -776,6 +776,11 @@
         TestCase._active_threads = threading.activeCount()
         self.addCleanup(self._check_leaked_threads)
 
+    def debug(self):
+        # debug a frame up.
+        import pdb
+        pdb.Pdb().set_trace(sys._getframe().f_back)
+
     def exc_info(self):
         absent_attr = object()
         exc_info = getattr(self, '_exc_info', absent_attr)

=== modified file 'bzrlib/tests/blackbox/test_branch.py'
--- a/bzrlib/tests/blackbox/test_branch.py	2009-03-03 05:50:55 +0000
+++ b/bzrlib/tests/blackbox/test_branch.py	2009-03-06 03:55:27 +0000
@@ -273,7 +273,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(71, rpc_count)
+        self.assertEqual(65, rpc_count)
 
     def test_branch_from_trivial_branch_streaming_acceptance(self):
         self.setup_smart_server_with_call_log()
@@ -289,7 +289,8 @@
         # 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(17, rpc_count)
+        self.debug()
+        self.assertEqual(11, rpc_count)
 
 
 class TestRemoteBranch(TestCaseWithSFTPServer):

=== modified file 'bzrlib/tests/branch_implementations/test_push.py'
--- a/bzrlib/tests/branch_implementations/test_push.py	2009-03-03 06:29:28 +0000
+++ b/bzrlib/tests/branch_implementations/test_push.py	2009-03-06 03:55:27 +0000
@@ -418,7 +418,7 @@
         self.empty_branch.push(target)
         self.assertEqual(
             ['BzrDir.open',
-             'BzrDir.open_branch',
+             'BzrDir.open_branchV2',
              'BzrDir.find_repositoryV3',
              'Branch.get_stacked_on_url',
              'Branch.lock_write',

=== modified file 'bzrlib/tests/branch_implementations/test_tags.py'
--- a/bzrlib/tests/branch_implementations/test_tags.py	2009-01-17 01:30:58 +0000
+++ b/bzrlib/tests/branch_implementations/test_tags.py	2009-03-06 03:55:27 +0000
@@ -38,16 +38,12 @@
 class TestBranchTags(TestCaseWithBranch):
 
     def setUp(self):
+        TestCaseWithBranch.setUp(self)
         # formats that don't support tags can skip the rest of these
         # tests...
-        fmt = self.branch_format
-        f = getattr(fmt, 'supports_tags')
-        if f is None:
-            raise TestSkipped("format %s doesn't declare whether it "
-                "supports tags, assuming not" % fmt)
-        if not f():
-            raise TestSkipped("format %s doesn't support tags" % fmt)
-        TestCaseWithBranch.setUp(self)
+        branch = self.make_branch('probe')
+        if not branch._format.supports_tags():
+            raise TestSkipped("format %s doesn't support tags" % branch._format)
 
     def test_tags_initially_empty(self):
         b = self.make_branch('b')
@@ -156,17 +152,12 @@
     """Formats that don't support tags should give reasonable errors."""
 
     def setUp(self):
-        fmt = self.branch_format
-        supported = getattr(fmt, 'supports_tags')
-        if supported is None:
-            warn("Format %s doesn't declare whether it supports tags or not"
-                 % fmt)
-            raise TestSkipped('No tag support at all')
-        if supported():
+        TestCaseWithBranch.setUp(self)
+        branch = self.make_branch('probe')
+        if branch._format.supports_tags():
             raise TestSkipped("Format %s declares that tags are supported"
-                              % fmt)
+                              % branch._format)
             # it's covered by TestBranchTags
-        TestCaseWithBranch.setUp(self)
 
     def test_tag_methods_raise(self):
         b = self.make_branch('b')

=== modified file 'bzrlib/tests/test_remote.py'
--- a/bzrlib/tests/test_remote.py	2009-03-06 02:23:20 +0000
+++ b/bzrlib/tests/test_remote.py	2009-03-06 03:55:27 +0000
@@ -42,6 +42,7 @@
 from bzrlib.bzrdir import BzrDir, BzrDirFormat
 from bzrlib.remote import (
     RemoteBranch,
+    RemoteBranchFormat,
     RemoteBzrDir,
     RemoteBzrDirFormat,
     RemoteRepository,
@@ -262,6 +263,10 @@
 
 class TestRemote(tests.TestCaseWithMemoryTransport):
 
+    def get_branch_format(self):
+        reference_bzrdir_format = bzrdir.format_registry.get('default')()
+        return reference_bzrdir_format.get_branch_format()
+
     def get_repo_format(self):
         reference_bzrdir_format = bzrdir.format_registry.get('default')()
         return reference_bzrdir_format.repository_format
@@ -386,16 +391,29 @@
 
 class TestBzrDirOpenBranch(TestRemote):
 
+    def test_backwards_compat(self):
+        self.setup_smart_server_with_call_log()
+        self.make_branch('.')
+        a_dir = BzrDir.open(self.get_url('.'))
+        self.reset_smart_call_log()
+        verb = 'BzrDir.open_branchV2'
+        self.disable_verb(verb)
+        format = a_dir.open_branch()
+        call_count = len([call for call in self.hpss_calls if
+            call.call.method == verb])
+        self.assertEqual(1, call_count)
+
     def test_branch_present(self):
         reference_format = self.get_repo_format()
         network_name = reference_format.network_name()
+        branch_network_name = self.get_branch_format().network_name()
         transport = MemoryTransport()
         transport.mkdir('quack')
         transport = transport.clone('quack')
         client = FakeClient(transport.base)
         client.add_expected_call(
-            'BzrDir.open_branch', ('quack/',),
-            'success', ('ok', ''))
+            'BzrDir.open_branchV2', ('quack/',),
+            'success', ('branch', branch_network_name))
         client.add_expected_call(
             'BzrDir.find_repositoryV3', ('quack/',),
             'success', ('ok', '', 'no', 'no', 'no', network_name))
@@ -419,7 +437,7 @@
             _client=client)
         self.assertRaises(errors.NotBranchError, bzrdir.open_branch)
         self.assertEqual(
-            [('call', 'BzrDir.open_branch', ('quack/',))],
+            [('call', 'BzrDir.open_branchV2', ('quack/',))],
             client._calls)
 
     def test__get_tree_branch(self):
@@ -447,9 +465,10 @@
         client = FakeClient(transport.base)
         reference_format = self.get_repo_format()
         network_name = reference_format.network_name()
+        branch_network_name = self.get_branch_format().network_name()
         client.add_expected_call(
-            'BzrDir.open_branch', ('~hello/',),
-            'success', ('ok', ''))
+            'BzrDir.open_branchV2', ('~hello/',),
+            'success', ('branch', branch_network_name))
         client.add_expected_call(
             'BzrDir.find_repositoryV3', ('~hello/',),
             'success', ('ok', '', 'no', 'no', 'no', network_name))
@@ -687,7 +706,7 @@
         return OldSmartClient()
 
 
-class RemoteBranchTestCase(tests.TestCase):
+class RemoteBranchTestCase(TestRemote):
 
     def make_remote_branch(self, transport, client):
         """Make a RemoteBranch using 'client' as its _SmartClient.
@@ -701,7 +720,9 @@
         bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
             _client=False)
         repo = RemoteRepository(bzrdir, None, _client=client)
-        return RemoteBranch(bzrdir, repo, _client=client)
+        branch_format = self.get_branch_format()
+        format = RemoteBranchFormat(network_name=branch_format.network_name())
+        return RemoteBranch(bzrdir, repo, _client=client, format=format)
 
 
 class TestBranchGetParent(RemoteBranchTestCase):
@@ -754,6 +775,36 @@
         self.assertEqual('http://foo/', result)
 
 
+class TestBranchGetTagsBytes(RemoteBranchTestCase):
+
+    def test_backwards_compat(self):
+        self.setup_smart_server_with_call_log()
+        branch = self.make_branch('.')
+        self.reset_smart_call_log()
+        verb = 'Branch.get_tags_bytes'
+        self.disable_verb(verb)
+        branch.tags.get_tag_dict()
+        call_count = len([call for call in self.hpss_calls if
+            call.call.method == verb])
+        self.assertEqual(1, call_count)
+
+    def test_trivial(self):
+        transport = MemoryTransport()
+        client = FakeClient(transport.base)
+        client.add_expected_call(
+            'Branch.get_stacked_on_url', ('quack/',),
+            'error', ('NotStacked',))
+        client.add_expected_call(
+            'Branch.get_tags_bytes', ('quack/',),
+            'success', ('',))
+        transport.mkdir('quack')
+        transport = transport.clone('quack')
+        branch = self.make_remote_branch(transport, client)
+        result = branch.tags.get_tag_dict()
+        client.finished_test()
+        self.assertEqual({}, result)
+
+
 class TestBranchLastRevisionInfo(RemoteBranchTestCase):
 
     def test_empty_branch(self):
@@ -827,9 +878,10 @@
         stacked_branch = self.make_branch('stacked', format='1.6')
         stacked_branch.set_stacked_on_url('../base')
         client = FakeClient(self.get_url())
+        branch_network_name = self.get_branch_format().network_name()
         client.add_expected_call(
-            'BzrDir.open_branch', ('stacked/',),
-            'success', ('ok', ''))
+            'BzrDir.open_branchV2', ('stacked/',),
+            'success', ('branch', branch_network_name))
         client.add_expected_call(
             'BzrDir.find_repositoryV3', ('stacked/',),
             'success', ('ok', '', 'no', 'no', 'no',
@@ -862,9 +914,10 @@
         reference_format = self.get_repo_format()
         network_name = reference_format.network_name()
         client = FakeClient(self.get_url())
+        branch_network_name = self.get_branch_format().network_name()
         client.add_expected_call(
-            'BzrDir.open_branch', ('stacked/',),
-            'success', ('ok', ''))
+            'BzrDir.open_branchV2', ('stacked/',),
+            'success', ('branch', branch_network_name))
         client.add_expected_call(
             'BzrDir.find_repositoryV3', ('stacked/',),
             'success', ('ok', '', 'no', 'no', 'no', network_name))

=== modified file 'bzrlib/tests/test_smart.py'
--- a/bzrlib/tests/test_smart.py	2009-03-06 02:23:20 +0000
+++ b/bzrlib/tests/test_smart.py	2009-03-06 03:55:27 +0000
@@ -364,6 +364,36 @@
             request.execute('reference'))
 
 
+class TestSmartServerRequestOpenBranchV2(TestCaseWithChrootedTransport):
+
+    def test_no_branch(self):
+        """When there is no branch, ('nobranch', ) is returned."""
+        backing = self.get_transport()
+        self.make_bzrdir('.')
+        request = smart.bzrdir.SmartServerRequestOpenBranchV2(backing)
+        self.assertEqual(SmartServerResponse(('nobranch', )),
+            request.execute(''))
+
+    def test_branch(self):
+        """When there is a branch, 'ok' is returned."""
+        backing = self.get_transport()
+        expected = self.make_branch('.')._format.network_name()
+        request = smart.bzrdir.SmartServerRequestOpenBranchV2(backing)
+        self.assertEqual(SuccessfulSmartServerResponse(('branch', expected)),
+            request.execute(''))
+
+    def test_branch_reference(self):
+        """When there is a branch reference, the reference URL is returned."""
+        backing = self.get_transport()
+        request = smart.bzrdir.SmartServerRequestOpenBranchV2(backing)
+        branch = self.make_branch('branch')
+        checkout = branch.create_checkout('reference',lightweight=True)
+        reference_url = BranchReferenceFormat().get_reference(checkout.bzrdir)
+        self.assertFileEqual(reference_url, 'reference/.bzr/branch/location')
+        self.assertEqual(SuccessfulSmartServerResponse(('ref', reference_url)),
+            request.execute('reference'))
+
+
 class TestSmartServerRequestRevisionHistory(tests.TestCaseWithMemoryTransport):
 
     def test_empty(self):
@@ -696,6 +726,19 @@
             response)
 
 
+class TestSmartServerBranchRequestGetTagsBytes(tests.TestCaseWithMemoryTransport):
+# Only called when the branch format and tags match [yay factory
+# methods] so only need to test straight forward cases.
+
+    def test_get_bytes(self):
+        base_branch = self.make_branch('base')
+        request = smart.branch.SmartServerBranchGetTagsBytes(
+            self.get_transport())
+        response = request.execute('base')
+        self.assertEquals(
+            SuccessfulSmartServerResponse(('',)), response)
+
+
 class TestSmartServerBranchRequestGetStackedOnURL(tests.TestCaseWithMemoryTransport):
 
     def test_get_stacked_on_url(self):
@@ -1209,6 +1252,9 @@
             smart.request.request_handlers.get('Branch.get_parent'),
             smart.branch.SmartServerBranchGetParent)
         self.assertEqual(
+            smart.request.request_handlers.get('Branch.get_tags_bytes'),
+            smart.branch.SmartServerBranchGetTagsBytes)
+        self.assertEqual(
             smart.request.request_handlers.get('Branch.lock_write'),
             smart.branch.SmartServerBranchRequestLockWrite)
         self.assertEqual(
@@ -1242,6 +1288,9 @@
             smart.request.request_handlers.get('BzrDir.open_branch'),
             smart.bzrdir.SmartServerRequestOpenBranch)
         self.assertEqual(
+            smart.request.request_handlers.get('BzrDir.open_branchV2'),
+            smart.bzrdir.SmartServerRequestOpenBranchV2)
+        self.assertEqual(
             smart.request.request_handlers.get('PackRepository.autopack'),
             smart.packrepository.SmartServerPackRepositoryAutopack)
         self.assertEqual(

=== modified file 'bzrlib/tests/test_tag.py'
--- a/bzrlib/tests/test_tag.py	2009-01-17 01:30:58 +0000
+++ b/bzrlib/tests/test_tag.py	2009-03-06 03:55:27 +0000
@@ -161,9 +161,6 @@
         branch = self.make_branch('.')
         self.tags = DisabledTags(branch)
 
-    def test_supports_tags(self):
-        self.assertEqual(self.tags.supports_tags(), False)
-
     def test_set_tag(self):
         self.assertRaises(errors.TagsNotSupported, self.tags.set_tag)
 




More information about the bazaar-commits mailing list