~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

  • Committer: Martin Pool
  • Date: 2010-01-29 14:09:05 UTC
  • mto: This revision was merged to the branch mainline in revision 4992.
  • Revision ID: mbp@sourcefrog.net-20100129140905-2uiarb6p8di1ywsr
Correction to url

from review: https://code.edge.launchpad.net/~mbp/bzr/doc/+merge/18250

Show diffs side-by-side

added added

removed removed

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