~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

  • Committer: John Arbash Meinel
  • Date: 2010-08-23 19:10:35 UTC
  • mto: This revision was merged to the branch mainline in revision 5390.
  • Revision ID: john@arbash-meinel.com-20100823191035-57bojnmqw54nutsz
switch 'x += 1' to 'x = x + 1' to deal with brain-damaged old versions of pyrex.

Show diffs side-by-side

added added

removed removed

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