/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

  • Committer: Neil Martinsen-Burrell
  • Date: 2010-09-26 02:27:37 UTC
  • mfrom: (5424 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5461.
  • Revision ID: nmb@wartburg.edu-20100926022737-cj2qvebm2mhpjzak
mergeĀ fromĀ trunk

Show diffs side-by-side

added added

removed removed

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