~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

  • Committer: Martin Pool
  • Date: 2010-03-01 05:15:11 UTC
  • mto: (4797.2.24 2.1)
  • mto: This revision was merged to the branch mainline in revision 5069.
  • Revision ID: mbp@canonical.com-20100301051511-rl4w81u1s4kjh7r1
Fix link to plugin guide

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
    branch,
22
22
    bzrdir,
23
23
    config,
24
 
    controldir,
25
24
    debug,
26
25
    errors,
27
26
    graph,
28
27
    lock,
29
28
    lockdir,
30
29
    repository,
31
 
    repository as _mod_repository,
32
30
    revision,
33
31
    revision as _mod_revision,
34
 
    static_tuple,
35
32
    symbol_versioning,
36
33
)
37
 
from bzrlib.branch import BranchReferenceFormat, BranchWriteLockResult
 
34
from bzrlib.branch import BranchReferenceFormat
38
35
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
39
36
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
40
37
from bzrlib.errors import (
44
41
from bzrlib.lockable_files import LockableFiles
45
42
from bzrlib.smart import client, vfs, repository as smart_repo
46
43
from bzrlib.revision import ensure_null, NULL_REVISION
47
 
from bzrlib.repository import RepositoryWriteLockResult
48
44
from bzrlib.trace import mutter, note, warning
49
45
 
50
46
 
246
242
        self._ensure_real()
247
243
        self._real_bzrdir.destroy_repository()
248
244
 
249
 
    def create_branch(self, name=None):
 
245
    def create_branch(self):
250
246
        # as per meta1 formats - just delegate to the format object which may
251
247
        # be parameterised.
252
 
        real_branch = self._format.get_branch_format().initialize(self,
253
 
            name=name)
 
248
        real_branch = self._format.get_branch_format().initialize(self)
254
249
        if not isinstance(real_branch, RemoteBranch):
255
 
            result = RemoteBranch(self, self.find_repository(), real_branch,
256
 
                                  name=name)
 
250
            result = RemoteBranch(self, self.find_repository(), real_branch)
257
251
        else:
258
252
            result = real_branch
259
253
        # BzrDir.clone_on_transport() uses the result of create_branch but does
265
259
        self._next_open_branch_result = result
266
260
        return result
267
261
 
268
 
    def destroy_branch(self, name=None):
 
262
    def destroy_branch(self):
269
263
        """See BzrDir.destroy_branch"""
270
264
        self._ensure_real()
271
 
        self._real_bzrdir.destroy_branch(name=name)
 
265
        self._real_bzrdir.destroy_branch()
272
266
        self._next_open_branch_result = None
273
267
 
274
268
    def create_workingtree(self, revision_id=None, from_branch=None):
275
269
        raise errors.NotLocalUrl(self.transport.base)
276
270
 
277
 
    def find_branch_format(self, name=None):
 
271
    def find_branch_format(self):
278
272
        """Find the branch 'format' for this bzrdir.
279
273
 
280
274
        This might be a synthetic object for e.g. RemoteBranch and SVN.
281
275
        """
282
 
        b = self.open_branch(name=name)
 
276
        b = self.open_branch()
283
277
        return b._format
284
278
 
285
 
    def get_branch_reference(self, name=None):
 
279
    def get_branch_reference(self):
286
280
        """See BzrDir.get_branch_reference()."""
287
 
        if name is not None:
288
 
            # XXX JRV20100304: Support opening colocated branches
289
 
            raise errors.NoColocatedBranchSupport(self)
290
281
        response = self._get_branch_reference()
291
282
        if response[0] == 'ref':
292
283
            return response[1]
323
314
            raise errors.UnexpectedSmartServerResponse(response)
324
315
        return response
325
316
 
326
 
    def _get_tree_branch(self, name=None):
 
317
    def _get_tree_branch(self):
327
318
        """See BzrDir._get_tree_branch()."""
328
 
        return None, self.open_branch(name=name)
 
319
        return None, self.open_branch()
329
320
 
330
 
    def open_branch(self, name=None, unsupported=False,
331
 
                    ignore_fallbacks=False):
332
 
        if unsupported:
 
321
    def open_branch(self, _unsupported=False, ignore_fallbacks=False):
 
322
        if _unsupported:
333
323
            raise NotImplementedError('unsupported flag support not implemented yet.')
334
324
        if self._next_open_branch_result is not None:
335
325
            # See create_branch for details.
340
330
        if response[0] == 'ref':
341
331
            # a branch reference, use the existing BranchReference logic.
342
332
            format = BranchReferenceFormat()
343
 
            return format.open(self, name=name, _found=True,
344
 
                location=response[1], ignore_fallbacks=ignore_fallbacks)
 
333
            return format.open(self, _found=True, location=response[1],
 
334
                ignore_fallbacks=ignore_fallbacks)
345
335
        branch_format_name = response[1]
346
336
        if not branch_format_name:
347
337
            branch_format_name = None
348
338
        format = RemoteBranchFormat(network_name=branch_format_name)
349
339
        return RemoteBranch(self, self.find_repository(), format=format,
350
 
            setup_stacking=not ignore_fallbacks, name=name)
 
340
            setup_stacking=not ignore_fallbacks)
351
341
 
352
342
    def _open_repo_v1(self, path):
353
343
        verb = 'BzrDir.find_repository'
430
420
        """Return the path to be used for this bzrdir in a remote call."""
431
421
        return client.remote_path_from_transport(self.root_transport)
432
422
 
433
 
    def get_branch_transport(self, branch_format, name=None):
 
423
    def get_branch_transport(self, branch_format):
434
424
        self._ensure_real()
435
 
        return self._real_bzrdir.get_branch_transport(branch_format, name=name)
 
425
        return self._real_bzrdir.get_branch_transport(branch_format)
436
426
 
437
427
    def get_repository_transport(self, repository_format):
438
428
        self._ensure_real()
648
638
        return self._custom_format._serializer
649
639
 
650
640
 
651
 
class RemoteRepository(_RpcHelper, lock._RelockDebugMixin,
652
 
    controldir.ControlComponent):
 
641
class RemoteRepository(_RpcHelper, lock._RelockDebugMixin):
653
642
    """Repository accessed over rpc.
654
643
 
655
644
    For the moment most operations are performed using local transport-backed
698
687
        # Additional places to query for data.
699
688
        self._fallback_repositories = []
700
689
 
701
 
    @property
702
 
    def user_transport(self):
703
 
        return self.bzrdir.user_transport
704
 
 
705
 
    @property
706
 
    def control_transport(self):
707
 
        # XXX: Normally you shouldn't directly get at the remote repository
708
 
        # transport, but I'm not sure it's worth making this method
709
 
        # optional -- mbp 2010-04-21
710
 
        return self.bzrdir.get_repository_transport(None)
711
 
        
712
690
    def __str__(self):
713
691
        return "%s(%s)" % (self.__class__.__name__, self.base)
714
692
 
900
878
    def _has_same_fallbacks(self, other_repo):
901
879
        """Returns true if the repositories have the same fallbacks."""
902
880
        # XXX: copied from Repository; it should be unified into a base class
903
 
        # <https://bugs.launchpad.net/bzr/+bug/401622>
 
881
        # <https://bugs.edge.launchpad.net/bzr/+bug/401622>
904
882
        my_fb = self._fallback_repositories
905
883
        other_fb = other_repo._fallback_repositories
906
884
        if len(my_fb) != len(other_fb):
922
900
        parents_provider = self._make_parents_provider(other_repository)
923
901
        return graph.Graph(parents_provider)
924
902
 
925
 
    @needs_read_lock
926
 
    def get_known_graph_ancestry(self, revision_ids):
927
 
        """Return the known graph for a set of revision ids and their ancestors.
928
 
        """
929
 
        st = static_tuple.StaticTuple
930
 
        revision_keys = [st(r_id).intern() for r_id in revision_ids]
931
 
        known_graph = self.revisions.get_known_graph_ancestry(revision_keys)
932
 
        return graph.GraphThunkIdsToKeys(known_graph)
933
 
 
934
903
    def gather_stats(self, revid=None, committers=None):
935
904
        """See Repository.gather_stats()."""
936
905
        path = self.bzrdir._path_for_remote_call(self._client)
1002
971
        pass
1003
972
 
1004
973
    def lock_read(self):
1005
 
        """Lock the repository for read operations.
1006
 
 
1007
 
        :return: A bzrlib.lock.LogicalLockResult.
1008
 
        """
1009
974
        # wrong eventually - want a local lock cache context
1010
975
        if not self._lock_mode:
1011
976
            self._note_lock('r')
1018
983
                repo.lock_read()
1019
984
        else:
1020
985
            self._lock_count += 1
1021
 
        return lock.LogicalLockResult(self.unlock)
1022
986
 
1023
987
    def _remote_lock_write(self, token):
1024
988
        path = self.bzrdir._path_for_remote_call(self._client)
1064
1028
            raise errors.ReadOnlyError(self)
1065
1029
        else:
1066
1030
            self._lock_count += 1
1067
 
        return RepositoryWriteLockResult(self.unlock, self._lock_token or None)
 
1031
        return self._lock_token or None
1068
1032
 
1069
1033
    def leave_lock_in_place(self):
1070
1034
        if not self._lock_token:
1250
1214
            # state, so always add a lock here. If a caller passes us a locked
1251
1215
            # repository, they are responsible for unlocking it later.
1252
1216
            repository.lock_read()
1253
 
        self._check_fallback_repository(repository)
1254
1217
        self._fallback_repositories.append(repository)
1255
1218
        # If self._real_repository was parameterised already (e.g. because a
1256
1219
        # _real_branch had its get_stacked_on_url method called), then the
1257
1220
        # repository to be added may already be in the _real_repositories list.
1258
1221
        if self._real_repository is not None:
1259
 
            fallback_locations = [repo.user_url for repo in
 
1222
            fallback_locations = [repo.bzrdir.root_transport.base for repo in
1260
1223
                self._real_repository._fallback_repositories]
1261
 
            if repository.user_url not in fallback_locations:
 
1224
            if repository.bzrdir.root_transport.base not in fallback_locations:
1262
1225
                self._real_repository.add_fallback_repository(repository)
1263
1226
 
1264
 
    def _check_fallback_repository(self, repository):
1265
 
        """Check that this repository can fallback to repository safely.
1266
 
 
1267
 
        Raise an error if not.
1268
 
 
1269
 
        :param repository: A repository to fallback to.
1270
 
        """
1271
 
        return _mod_repository.InterRepository._assert_same_model(
1272
 
            self, repository)
1273
 
 
1274
1227
    def add_inventory(self, revid, inv, parents):
1275
1228
        self._ensure_real()
1276
1229
        return self._real_repository.add_inventory(revid, inv, parents)
1277
1230
 
1278
1231
    def add_inventory_by_delta(self, basis_revision_id, delta, new_revision_id,
1279
 
            parents, basis_inv=None, propagate_caches=False):
 
1232
                               parents):
1280
1233
        self._ensure_real()
1281
1234
        return self._real_repository.add_inventory_by_delta(basis_revision_id,
1282
 
            delta, new_revision_id, parents, basis_inv=basis_inv,
1283
 
            propagate_caches=propagate_caches)
 
1235
            delta, new_revision_id, parents)
1284
1236
 
1285
1237
    def add_revision(self, rev_id, rev, inv=None, config=None):
1286
1238
        self._ensure_real()
1316
1268
        return self._real_repository.make_working_trees()
1317
1269
 
1318
1270
    def refresh_data(self):
1319
 
        """Re-read any data needed to synchronise with disk.
 
1271
        """Re-read any data needed to to synchronise with disk.
1320
1272
 
1321
1273
        This method is intended to be called after another repository instance
1322
1274
        (such as one used by a smart server) has inserted data into the
1323
 
        repository. On all repositories this will work outside of write groups.
1324
 
        Some repository formats (pack and newer for bzrlib native formats)
1325
 
        support refresh_data inside write groups. If called inside a write
1326
 
        group on a repository that does not support refreshing in a write group
1327
 
        IsInWriteGroupError will be raised.
 
1275
        repository. It may not be called during a write group, but may be
 
1276
        called at any other time.
1328
1277
        """
 
1278
        if self.is_in_write_group():
 
1279
            raise errors.InternalBzrError(
 
1280
                "May not refresh_data while in a write group.")
1329
1281
        if self._real_repository is not None:
1330
1282
            self._real_repository.refresh_data()
1331
1283
 
1545
1497
        return self._real_repository.get_signature_text(revision_id)
1546
1498
 
1547
1499
    @needs_read_lock
1548
 
    def _get_inventory_xml(self, revision_id):
1549
 
        self._ensure_real()
1550
 
        return self._real_repository._get_inventory_xml(revision_id)
 
1500
    def get_inventory_xml(self, revision_id):
 
1501
        self._ensure_real()
 
1502
        return self._real_repository.get_inventory_xml(revision_id)
 
1503
 
 
1504
    def deserialise_inventory(self, revision_id, xml):
 
1505
        self._ensure_real()
 
1506
        return self._real_repository.deserialise_inventory(revision_id, xml)
1551
1507
 
1552
1508
    def reconcile(self, other=None, thorough=False):
1553
1509
        self._ensure_real()
1629
1585
        return self._real_repository.inventories
1630
1586
 
1631
1587
    @needs_write_lock
1632
 
    def pack(self, hint=None, clean_obsolete_packs=False):
 
1588
    def pack(self, hint=None):
1633
1589
        """Compress the data within the repository.
1634
1590
 
1635
1591
        This is not currently implemented within the smart server.
1636
1592
        """
1637
1593
        self._ensure_real()
1638
 
        return self._real_repository.pack(hint=hint, clean_obsolete_packs=clean_obsolete_packs)
 
1594
        return self._real_repository.pack(hint=hint)
1639
1595
 
1640
1596
    @property
1641
1597
    def revisions(self):
1981
1937
        if response_tuple[0] != 'ok':
1982
1938
            raise errors.UnexpectedSmartServerResponse(response_tuple)
1983
1939
        byte_stream = response_handler.read_streamed_body()
1984
 
        src_format, stream = smart_repo._byte_stream_to_stream(byte_stream,
1985
 
            self._record_counter)
 
1940
        src_format, stream = smart_repo._byte_stream_to_stream(byte_stream)
1986
1941
        if src_format.network_name() != repo._format.network_name():
1987
1942
            raise AssertionError(
1988
1943
                "Mismatched RemoteRepository and stream src %r, %r" % (
2070
2025
    def network_name(self):
2071
2026
        return self._network_name
2072
2027
 
2073
 
    def open(self, a_bzrdir, name=None, ignore_fallbacks=False):
2074
 
        return a_bzrdir.open_branch(name=name, 
2075
 
            ignore_fallbacks=ignore_fallbacks)
 
2028
    def open(self, a_bzrdir, ignore_fallbacks=False):
 
2029
        return a_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks)
2076
2030
 
2077
 
    def _vfs_initialize(self, a_bzrdir, name):
 
2031
    def _vfs_initialize(self, a_bzrdir):
2078
2032
        # Initialisation when using a local bzrdir object, or a non-vfs init
2079
2033
        # method is not available on the server.
2080
2034
        # self._custom_format is always set - the start of initialize ensures
2081
2035
        # that.
2082
2036
        if isinstance(a_bzrdir, RemoteBzrDir):
2083
2037
            a_bzrdir._ensure_real()
2084
 
            result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
2085
 
                name)
 
2038
            result = self._custom_format.initialize(a_bzrdir._real_bzrdir)
2086
2039
        else:
2087
2040
            # We assume the bzrdir is parameterised; it may not be.
2088
 
            result = self._custom_format.initialize(a_bzrdir, name)
 
2041
            result = self._custom_format.initialize(a_bzrdir)
2089
2042
        if (isinstance(a_bzrdir, RemoteBzrDir) and
2090
2043
            not isinstance(result, RemoteBranch)):
2091
 
            result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result,
2092
 
                                  name=name)
 
2044
            result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result)
2093
2045
        return result
2094
2046
 
2095
 
    def initialize(self, a_bzrdir, name=None):
 
2047
    def initialize(self, a_bzrdir):
2096
2048
        # 1) get the network name to use.
2097
2049
        if self._custom_format:
2098
2050
            network_name = self._custom_format.network_name()
2104
2056
            network_name = reference_format.network_name()
2105
2057
        # Being asked to create on a non RemoteBzrDir:
2106
2058
        if not isinstance(a_bzrdir, RemoteBzrDir):
2107
 
            return self._vfs_initialize(a_bzrdir, name=name)
 
2059
            return self._vfs_initialize(a_bzrdir)
2108
2060
        medium = a_bzrdir._client._medium
2109
2061
        if medium._is_remote_before((1, 13)):
2110
 
            return self._vfs_initialize(a_bzrdir, name=name)
 
2062
            return self._vfs_initialize(a_bzrdir)
2111
2063
        # Creating on a remote bzr dir.
2112
2064
        # 2) try direct creation via RPC
2113
2065
        path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
2114
 
        if name is not None:
2115
 
            # XXX JRV20100304: Support creating colocated branches
2116
 
            raise errors.NoColocatedBranchSupport(self)
2117
2066
        verb = 'BzrDir.create_branch'
2118
2067
        try:
2119
2068
            response = a_bzrdir._call(verb, path, network_name)
2120
2069
        except errors.UnknownSmartMethod:
2121
2070
            # Fallback - use vfs methods
2122
2071
            medium._remember_remote_is_before((1, 13))
2123
 
            return self._vfs_initialize(a_bzrdir, name=name)
 
2072
            return self._vfs_initialize(a_bzrdir)
2124
2073
        if response[0] != 'ok':
2125
2074
            raise errors.UnexpectedSmartServerResponse(response)
2126
2075
        # Turn the response into a RemoteRepository object.
2134
2083
                a_bzrdir._client)
2135
2084
        remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2136
2085
        remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2137
 
            format=format, setup_stacking=False, name=name)
 
2086
            format=format, setup_stacking=False)
2138
2087
        # XXX: We know this is a new branch, so it must have revno 0, revid
2139
2088
        # NULL_REVISION. Creating the branch locked would make this be unable
2140
2089
        # to be wrong; here its simply very unlikely to be wrong. RBC 20090225
2167
2116
    """
2168
2117
 
2169
2118
    def __init__(self, remote_bzrdir, remote_repository, real_branch=None,
2170
 
        _client=None, format=None, setup_stacking=True, name=None):
 
2119
        _client=None, format=None, setup_stacking=True):
2171
2120
        """Create a RemoteBranch instance.
2172
2121
 
2173
2122
        :param real_branch: An optional local implementation of the branch
2179
2128
        :param setup_stacking: If True make an RPC call to determine the
2180
2129
            stacked (or not) status of the branch. If False assume the branch
2181
2130
            is not stacked.
2182
 
        :param name: Colocated branch name
2183
2131
        """
2184
2132
        # We intentionally don't call the parent class's __init__, because it
2185
2133
        # will try to assign to self.tags, which is a property in this subclass.
2204
2152
            self._real_branch = None
2205
2153
        # Fill out expected attributes of branch for bzrlib API users.
2206
2154
        self._clear_cached_state()
2207
 
        # TODO: deprecate self.base in favor of user_url
2208
 
        self.base = self.bzrdir.user_url
2209
 
        self._name = name
 
2155
        self.base = self.bzrdir.root_transport.base
2210
2156
        self._control_files = None
2211
2157
        self._lock_mode = None
2212
2158
        self._lock_token = None
2277
2223
                    'to use vfs implementation')
2278
2224
            self.bzrdir._ensure_real()
2279
2225
            self._real_branch = self.bzrdir._real_bzrdir.open_branch(
2280
 
                ignore_fallbacks=self._real_ignore_fallbacks, name=self._name)
 
2226
                ignore_fallbacks=self._real_ignore_fallbacks)
2281
2227
            if self.repository._real_repository is None:
2282
2228
                # Give the remote repository the matching real repo.
2283
2229
                real_repo = self._real_branch.repository
2398
2344
            self._vfs_set_tags_bytes(bytes)
2399
2345
 
2400
2346
    def lock_read(self):
2401
 
        """Lock the branch for read operations.
2402
 
 
2403
 
        :return: A bzrlib.lock.LogicalLockResult.
2404
 
        """
2405
2347
        self.repository.lock_read()
2406
2348
        if not self._lock_mode:
2407
2349
            self._note_lock('r')
2411
2353
                self._real_branch.lock_read()
2412
2354
        else:
2413
2355
            self._lock_count += 1
2414
 
        return lock.LogicalLockResult(self.unlock)
2415
2356
 
2416
2357
    def _remote_lock_write(self, token):
2417
2358
        if token is None:
2418
2359
            branch_token = repo_token = ''
2419
2360
        else:
2420
2361
            branch_token = token
2421
 
            repo_token = self.repository.lock_write().repository_token
 
2362
            repo_token = self.repository.lock_write()
2422
2363
            self.repository.unlock()
2423
2364
        err_context = {'token': token}
2424
 
        try:
2425
 
            response = self._call(
2426
 
                'Branch.lock_write', self._remote_path(), branch_token,
2427
 
                repo_token or '', **err_context)
2428
 
        except errors.LockContention, e:
2429
 
            # The LockContention from the server doesn't have any
2430
 
            # information about the lock_url. We re-raise LockContention
2431
 
            # with valid lock_url.
2432
 
            raise errors.LockContention('(remote lock)',
2433
 
                self.repository.base.split('.bzr/')[0])
 
2365
        response = self._call(
 
2366
            'Branch.lock_write', self._remote_path(), branch_token,
 
2367
            repo_token or '', **err_context)
2434
2368
        if response[0] != 'ok':
2435
2369
            raise errors.UnexpectedSmartServerResponse(response)
2436
2370
        ok, branch_token, repo_token = response
2457
2391
            self._lock_mode = 'w'
2458
2392
            self._lock_count = 1
2459
2393
        elif self._lock_mode == 'r':
2460
 
            raise errors.ReadOnlyError(self)
 
2394
            raise errors.ReadOnlyTransaction
2461
2395
        else:
2462
2396
            if token is not None:
2463
2397
                # A token was given to lock_write, and we're relocking, so
2468
2402
            self._lock_count += 1
2469
2403
            # Re-lock the repository too.
2470
2404
            self.repository.lock_write(self._repo_lock_token)
2471
 
        return BranchWriteLockResult(self.unlock, self._lock_token or None)
 
2405
        return self._lock_token or None
2472
2406
 
2473
2407
    def _unlock(self, branch_token, repo_token):
2474
2408
        err_context = {'token': str((branch_token, repo_token))}
2797
2731
        medium = self._branch._client._medium
2798
2732
        if medium._is_remote_before((1, 14)):
2799
2733
            return self._vfs_set_option(value, name, section)
2800
 
        if isinstance(value, dict):
2801
 
            if medium._is_remote_before((2, 2)):
2802
 
                return self._vfs_set_option(value, name, section)
2803
 
            return self._set_config_option_dict(value, name, section)
2804
 
        else:
2805
 
            return self._set_config_option(value, name, section)
2806
 
 
2807
 
    def _set_config_option(self, value, name, section):
2808
2734
        try:
2809
2735
            path = self._branch._remote_path()
2810
2736
            response = self._branch._client.call('Branch.set_config_option',
2811
2737
                path, self._branch._lock_token, self._branch._repo_lock_token,
2812
2738
                value.encode('utf8'), name, section or '')
2813
2739
        except errors.UnknownSmartMethod:
2814
 
            medium = self._branch._client._medium
2815
2740
            medium._remember_remote_is_before((1, 14))
2816
2741
            return self._vfs_set_option(value, name, section)
2817
2742
        if response != ():
2818
2743
            raise errors.UnexpectedSmartServerResponse(response)
2819
2744
 
2820
 
    def _serialize_option_dict(self, option_dict):
2821
 
        utf8_dict = {}
2822
 
        for key, value in option_dict.items():
2823
 
            if isinstance(key, unicode):
2824
 
                key = key.encode('utf8')
2825
 
            if isinstance(value, unicode):
2826
 
                value = value.encode('utf8')
2827
 
            utf8_dict[key] = value
2828
 
        return bencode.bencode(utf8_dict)
2829
 
 
2830
 
    def _set_config_option_dict(self, value, name, section):
2831
 
        try:
2832
 
            path = self._branch._remote_path()
2833
 
            serialised_dict = self._serialize_option_dict(value)
2834
 
            response = self._branch._client.call(
2835
 
                'Branch.set_config_option_dict',
2836
 
                path, self._branch._lock_token, self._branch._repo_lock_token,
2837
 
                serialised_dict, name, section or '')
2838
 
        except errors.UnknownSmartMethod:
2839
 
            medium = self._branch._client._medium
2840
 
            medium._remember_remote_is_before((2, 2))
2841
 
            return self._vfs_set_option(value, name, section)
2842
 
        if response != ():
2843
 
            raise errors.UnexpectedSmartServerResponse(response)
2844
 
 
2845
2745
    def _real_object(self):
2846
2746
        self._branch._ensure_real()
2847
2747
        return self._branch._real_branch