~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

  • Committer: John Arbash Meinel
  • Date: 2009-10-12 18:14:21 UTC
  • mto: This revision was merged to the branch mainline in revision 4736.
  • Revision ID: john@arbash-meinel.com-20091012181421-6s3yxopo9s40wqjr
NEWS entry for StaticTuple class.

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
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
 
118
114
 
119
115
        self._probe_bzrdir()
120
116
 
121
 
    def __repr__(self):
122
 
        return '%s(%r)' % (self.__class__.__name__, self._client)
123
 
 
124
117
    def _probe_bzrdir(self):
125
118
        medium = self._client._medium
126
119
        path = self._path_for_remote_call(self._client)
161
154
        Used before calls to self._real_bzrdir.
162
155
        """
163
156
        if not self._real_bzrdir:
164
 
            if 'hpssvfs' in debug.debug_flags:
165
 
                import traceback
166
 
                warning('VFS BzrDir access triggered\n%s',
167
 
                    ''.join(traceback.format_stack()))
168
157
            self._real_bzrdir = BzrDir.open_from_transport(
169
158
                self.root_transport, _server_formats=False)
170
159
            self._format._network_name = \
246
235
        self._ensure_real()
247
236
        self._real_bzrdir.destroy_repository()
248
237
 
249
 
    def create_branch(self, name=None):
 
238
    def create_branch(self):
250
239
        # as per meta1 formats - just delegate to the format object which may
251
240
        # be parameterised.
252
 
        real_branch = self._format.get_branch_format().initialize(self,
253
 
            name=name)
 
241
        real_branch = self._format.get_branch_format().initialize(self)
254
242
        if not isinstance(real_branch, RemoteBranch):
255
 
            result = RemoteBranch(self, self.find_repository(), real_branch,
256
 
                                  name=name)
 
243
            result = RemoteBranch(self, self.find_repository(), real_branch)
257
244
        else:
258
245
            result = real_branch
259
246
        # BzrDir.clone_on_transport() uses the result of create_branch but does
265
252
        self._next_open_branch_result = result
266
253
        return result
267
254
 
268
 
    def destroy_branch(self, name=None):
 
255
    def destroy_branch(self):
269
256
        """See BzrDir.destroy_branch"""
270
257
        self._ensure_real()
271
 
        self._real_bzrdir.destroy_branch(name=name)
 
258
        self._real_bzrdir.destroy_branch()
272
259
        self._next_open_branch_result = None
273
260
 
274
261
    def create_workingtree(self, revision_id=None, from_branch=None):
275
262
        raise errors.NotLocalUrl(self.transport.base)
276
263
 
277
 
    def find_branch_format(self, name=None):
 
264
    def find_branch_format(self):
278
265
        """Find the branch 'format' for this bzrdir.
279
266
 
280
267
        This might be a synthetic object for e.g. RemoteBranch and SVN.
281
268
        """
282
 
        b = self.open_branch(name=name)
 
269
        b = self.open_branch()
283
270
        return b._format
284
271
 
285
 
    def get_branch_reference(self, name=None):
 
272
    def get_branch_reference(self):
286
273
        """See BzrDir.get_branch_reference()."""
287
 
        if name is not None:
288
 
            # XXX JRV20100304: Support opening colocated branches
289
 
            raise errors.NoColocatedBranchSupport(self)
290
274
        response = self._get_branch_reference()
291
275
        if response[0] == 'ref':
292
276
            return response[1]
296
280
    def _get_branch_reference(self):
297
281
        path = self._path_for_remote_call(self._client)
298
282
        medium = self._client._medium
299
 
        candidate_calls = [
300
 
            ('BzrDir.open_branchV3', (2, 1)),
301
 
            ('BzrDir.open_branchV2', (1, 13)),
302
 
            ('BzrDir.open_branch', None),
303
 
            ]
304
 
        for verb, required_version in candidate_calls:
305
 
            if required_version and medium._is_remote_before(required_version):
306
 
                continue
 
283
        if not medium._is_remote_before((1, 13)):
307
284
            try:
308
 
                response = self._call(verb, path)
 
285
                response = self._call('BzrDir.open_branchV2', path)
 
286
                if response[0] not in ('ref', 'branch'):
 
287
                    raise errors.UnexpectedSmartServerResponse(response)
 
288
                return response
309
289
            except errors.UnknownSmartMethod:
310
 
                if required_version is None:
311
 
                    raise
312
 
                medium._remember_remote_is_before(required_version)
313
 
            else:
314
 
                break
315
 
        if verb == 'BzrDir.open_branch':
316
 
            if response[0] != 'ok':
317
 
                raise errors.UnexpectedSmartServerResponse(response)
318
 
            if response[1] != '':
319
 
                return ('ref', response[1])
320
 
            else:
321
 
                return ('branch', '')
322
 
        if response[0] not in ('ref', 'branch'):
 
290
                medium._remember_remote_is_before((1, 13))
 
291
        response = self._call('BzrDir.open_branch', path)
 
292
        if response[0] != 'ok':
323
293
            raise errors.UnexpectedSmartServerResponse(response)
324
 
        return response
 
294
        if response[1] != '':
 
295
            return ('ref', response[1])
 
296
        else:
 
297
            return ('branch', '')
325
298
 
326
 
    def _get_tree_branch(self, name=None):
 
299
    def _get_tree_branch(self):
327
300
        """See BzrDir._get_tree_branch()."""
328
 
        return None, self.open_branch(name=name)
 
301
        return None, self.open_branch()
329
302
 
330
 
    def open_branch(self, name=None, unsupported=False,
331
 
                    ignore_fallbacks=False):
332
 
        if unsupported:
 
303
    def open_branch(self, _unsupported=False, ignore_fallbacks=False):
 
304
        if _unsupported:
333
305
            raise NotImplementedError('unsupported flag support not implemented yet.')
334
306
        if self._next_open_branch_result is not None:
335
307
            # See create_branch for details.
340
312
        if response[0] == 'ref':
341
313
            # a branch reference, use the existing BranchReference logic.
342
314
            format = BranchReferenceFormat()
343
 
            return format.open(self, name=name, _found=True,
344
 
                location=response[1], ignore_fallbacks=ignore_fallbacks)
 
315
            return format.open(self, _found=True, location=response[1],
 
316
                ignore_fallbacks=ignore_fallbacks)
345
317
        branch_format_name = response[1]
346
318
        if not branch_format_name:
347
319
            branch_format_name = None
348
320
        format = RemoteBranchFormat(network_name=branch_format_name)
349
321
        return RemoteBranch(self, self.find_repository(), format=format,
350
 
            setup_stacking=not ignore_fallbacks, name=name)
 
322
            setup_stacking=not ignore_fallbacks)
351
323
 
352
324
    def _open_repo_v1(self, path):
353
325
        verb = 'BzrDir.find_repository'
430
402
        """Return the path to be used for this bzrdir in a remote call."""
431
403
        return client.remote_path_from_transport(self.root_transport)
432
404
 
433
 
    def get_branch_transport(self, branch_format, name=None):
 
405
    def get_branch_transport(self, branch_format):
434
406
        self._ensure_real()
435
 
        return self._real_bzrdir.get_branch_transport(branch_format, name=name)
 
407
        return self._real_bzrdir.get_branch_transport(branch_format)
436
408
 
437
409
    def get_repository_transport(self, repository_format):
438
410
        self._ensure_real()
625
597
        return self._custom_format._fetch_reconcile
626
598
 
627
599
    def get_format_description(self):
628
 
        self._ensure_real()
629
 
        return 'Remote: ' + self._custom_format.get_format_description()
 
600
        return 'bzr remote repository'
630
601
 
631
602
    def __eq__(self, other):
632
603
        return self.__class__ is other.__class__
648
619
        return self._custom_format._serializer
649
620
 
650
621
 
651
 
class RemoteRepository(_RpcHelper, lock._RelockDebugMixin,
652
 
    controldir.ControlComponent):
 
622
class RemoteRepository(_RpcHelper, lock._RelockDebugMixin):
653
623
    """Repository accessed over rpc.
654
624
 
655
625
    For the moment most operations are performed using local transport-backed
698
668
        # Additional places to query for data.
699
669
        self._fallback_repositories = []
700
670
 
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
671
    def __str__(self):
713
672
        return "%s(%s)" % (self.__class__.__name__, self.base)
714
673
 
900
859
    def _has_same_fallbacks(self, other_repo):
901
860
        """Returns true if the repositories have the same fallbacks."""
902
861
        # XXX: copied from Repository; it should be unified into a base class
903
 
        # <https://bugs.launchpad.net/bzr/+bug/401622>
 
862
        # <https://bugs.edge.launchpad.net/bzr/+bug/401622>
904
863
        my_fb = self._fallback_repositories
905
864
        other_fb = other_repo._fallback_repositories
906
865
        if len(my_fb) != len(other_fb):
922
881
        parents_provider = self._make_parents_provider(other_repository)
923
882
        return graph.Graph(parents_provider)
924
883
 
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
884
    def gather_stats(self, revid=None, committers=None):
935
885
        """See Repository.gather_stats()."""
936
886
        path = self.bzrdir._path_for_remote_call(self._client)
996
946
    def is_write_locked(self):
997
947
        return self._lock_mode == 'w'
998
948
 
999
 
    def _warn_if_deprecated(self, branch=None):
1000
 
        # If we have a real repository, the check will be done there, if we
1001
 
        # don't the check will be done remotely.
1002
 
        pass
1003
 
 
1004
949
    def lock_read(self):
1005
 
        """Lock the repository for read operations.
1006
 
 
1007
 
        :return: A bzrlib.lock.LogicalLockResult.
1008
 
        """
1009
950
        # wrong eventually - want a local lock cache context
1010
951
        if not self._lock_mode:
1011
952
            self._note_lock('r')
1018
959
                repo.lock_read()
1019
960
        else:
1020
961
            self._lock_count += 1
1021
 
        return lock.LogicalLockResult(self.unlock)
1022
962
 
1023
963
    def _remote_lock_write(self, token):
1024
964
        path = self.bzrdir._path_for_remote_call(self._client)
1064
1004
            raise errors.ReadOnlyError(self)
1065
1005
        else:
1066
1006
            self._lock_count += 1
1067
 
        return RepositoryWriteLockResult(self.unlock, self._lock_token or None)
 
1007
        return self._lock_token or None
1068
1008
 
1069
1009
    def leave_lock_in_place(self):
1070
1010
        if not self._lock_token:
1250
1190
            # state, so always add a lock here. If a caller passes us a locked
1251
1191
            # repository, they are responsible for unlocking it later.
1252
1192
            repository.lock_read()
1253
 
        self._check_fallback_repository(repository)
1254
1193
        self._fallback_repositories.append(repository)
1255
1194
        # If self._real_repository was parameterised already (e.g. because a
1256
1195
        # _real_branch had its get_stacked_on_url method called), then the
1257
1196
        # repository to be added may already be in the _real_repositories list.
1258
1197
        if self._real_repository is not None:
1259
 
            fallback_locations = [repo.user_url for repo in
 
1198
            fallback_locations = [repo.bzrdir.root_transport.base for repo in
1260
1199
                self._real_repository._fallback_repositories]
1261
 
            if repository.user_url not in fallback_locations:
 
1200
            if repository.bzrdir.root_transport.base not in fallback_locations:
1262
1201
                self._real_repository.add_fallback_repository(repository)
1263
1202
 
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
1203
    def add_inventory(self, revid, inv, parents):
1275
1204
        self._ensure_real()
1276
1205
        return self._real_repository.add_inventory(revid, inv, parents)
1277
1206
 
1278
1207
    def add_inventory_by_delta(self, basis_revision_id, delta, new_revision_id,
1279
 
            parents, basis_inv=None, propagate_caches=False):
 
1208
                               parents):
1280
1209
        self._ensure_real()
1281
1210
        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)
 
1211
            delta, new_revision_id, parents)
1284
1212
 
1285
1213
    def add_revision(self, rev_id, rev, inv=None, config=None):
1286
1214
        self._ensure_real()
1316
1244
        return self._real_repository.make_working_trees()
1317
1245
 
1318
1246
    def refresh_data(self):
1319
 
        """Re-read any data needed to synchronise with disk.
 
1247
        """Re-read any data needed to to synchronise with disk.
1320
1248
 
1321
1249
        This method is intended to be called after another repository instance
1322
1250
        (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.
 
1251
        repository. It may not be called during a write group, but may be
 
1252
        called at any other time.
1328
1253
        """
 
1254
        if self.is_in_write_group():
 
1255
            raise errors.InternalBzrError(
 
1256
                "May not refresh_data while in a write group.")
1329
1257
        if self._real_repository is not None:
1330
1258
            self._real_repository.refresh_data()
1331
1259
 
1545
1473
        return self._real_repository.get_signature_text(revision_id)
1546
1474
 
1547
1475
    @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)
 
1476
    def get_inventory_xml(self, revision_id):
 
1477
        self._ensure_real()
 
1478
        return self._real_repository.get_inventory_xml(revision_id)
 
1479
 
 
1480
    def deserialise_inventory(self, revision_id, xml):
 
1481
        self._ensure_real()
 
1482
        return self._real_repository.deserialise_inventory(revision_id, xml)
1551
1483
 
1552
1484
    def reconcile(self, other=None, thorough=False):
1553
1485
        self._ensure_real()
1629
1561
        return self._real_repository.inventories
1630
1562
 
1631
1563
    @needs_write_lock
1632
 
    def pack(self, hint=None, clean_obsolete_packs=False):
 
1564
    def pack(self, hint=None):
1633
1565
        """Compress the data within the repository.
1634
1566
 
1635
1567
        This is not currently implemented within the smart server.
1636
1568
        """
1637
1569
        self._ensure_real()
1638
 
        return self._real_repository.pack(hint=hint, clean_obsolete_packs=clean_obsolete_packs)
 
1570
        return self._real_repository.pack(hint=hint)
1639
1571
 
1640
1572
    @property
1641
1573
    def revisions(self):
1981
1913
        if response_tuple[0] != 'ok':
1982
1914
            raise errors.UnexpectedSmartServerResponse(response_tuple)
1983
1915
        byte_stream = response_handler.read_streamed_body()
1984
 
        src_format, stream = smart_repo._byte_stream_to_stream(byte_stream,
1985
 
            self._record_counter)
 
1916
        src_format, stream = smart_repo._byte_stream_to_stream(byte_stream)
1986
1917
        if src_format.network_name() != repo._format.network_name():
1987
1918
            raise AssertionError(
1988
1919
                "Mismatched RemoteRepository and stream src %r, %r" % (
2064
1995
                self._network_name)
2065
1996
 
2066
1997
    def get_format_description(self):
2067
 
        self._ensure_real()
2068
 
        return 'Remote: ' + self._custom_format.get_format_description()
 
1998
        return 'Remote BZR Branch'
2069
1999
 
2070
2000
    def network_name(self):
2071
2001
        return self._network_name
2072
2002
 
2073
 
    def open(self, a_bzrdir, name=None, ignore_fallbacks=False):
2074
 
        return a_bzrdir.open_branch(name=name, 
2075
 
            ignore_fallbacks=ignore_fallbacks)
 
2003
    def open(self, a_bzrdir, ignore_fallbacks=False):
 
2004
        return a_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks)
2076
2005
 
2077
 
    def _vfs_initialize(self, a_bzrdir, name):
 
2006
    def _vfs_initialize(self, a_bzrdir):
2078
2007
        # Initialisation when using a local bzrdir object, or a non-vfs init
2079
2008
        # method is not available on the server.
2080
2009
        # self._custom_format is always set - the start of initialize ensures
2081
2010
        # that.
2082
2011
        if isinstance(a_bzrdir, RemoteBzrDir):
2083
2012
            a_bzrdir._ensure_real()
2084
 
            result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
2085
 
                name)
 
2013
            result = self._custom_format.initialize(a_bzrdir._real_bzrdir)
2086
2014
        else:
2087
2015
            # We assume the bzrdir is parameterised; it may not be.
2088
 
            result = self._custom_format.initialize(a_bzrdir, name)
 
2016
            result = self._custom_format.initialize(a_bzrdir)
2089
2017
        if (isinstance(a_bzrdir, RemoteBzrDir) and
2090
2018
            not isinstance(result, RemoteBranch)):
2091
 
            result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result,
2092
 
                                  name=name)
 
2019
            result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result)
2093
2020
        return result
2094
2021
 
2095
 
    def initialize(self, a_bzrdir, name=None):
 
2022
    def initialize(self, a_bzrdir):
2096
2023
        # 1) get the network name to use.
2097
2024
        if self._custom_format:
2098
2025
            network_name = self._custom_format.network_name()
2104
2031
            network_name = reference_format.network_name()
2105
2032
        # Being asked to create on a non RemoteBzrDir:
2106
2033
        if not isinstance(a_bzrdir, RemoteBzrDir):
2107
 
            return self._vfs_initialize(a_bzrdir, name=name)
 
2034
            return self._vfs_initialize(a_bzrdir)
2108
2035
        medium = a_bzrdir._client._medium
2109
2036
        if medium._is_remote_before((1, 13)):
2110
 
            return self._vfs_initialize(a_bzrdir, name=name)
 
2037
            return self._vfs_initialize(a_bzrdir)
2111
2038
        # Creating on a remote bzr dir.
2112
2039
        # 2) try direct creation via RPC
2113
2040
        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
2041
        verb = 'BzrDir.create_branch'
2118
2042
        try:
2119
2043
            response = a_bzrdir._call(verb, path, network_name)
2120
2044
        except errors.UnknownSmartMethod:
2121
2045
            # Fallback - use vfs methods
2122
2046
            medium._remember_remote_is_before((1, 13))
2123
 
            return self._vfs_initialize(a_bzrdir, name=name)
 
2047
            return self._vfs_initialize(a_bzrdir)
2124
2048
        if response[0] != 'ok':
2125
2049
            raise errors.UnexpectedSmartServerResponse(response)
2126
2050
        # Turn the response into a RemoteRepository object.
2134
2058
                a_bzrdir._client)
2135
2059
        remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2136
2060
        remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2137
 
            format=format, setup_stacking=False, name=name)
 
2061
            format=format, setup_stacking=False)
2138
2062
        # XXX: We know this is a new branch, so it must have revno 0, revid
2139
2063
        # NULL_REVISION. Creating the branch locked would make this be unable
2140
2064
        # to be wrong; here its simply very unlikely to be wrong. RBC 20090225
2167
2091
    """
2168
2092
 
2169
2093
    def __init__(self, remote_bzrdir, remote_repository, real_branch=None,
2170
 
        _client=None, format=None, setup_stacking=True, name=None):
 
2094
        _client=None, format=None, setup_stacking=True):
2171
2095
        """Create a RemoteBranch instance.
2172
2096
 
2173
2097
        :param real_branch: An optional local implementation of the branch
2179
2103
        :param setup_stacking: If True make an RPC call to determine the
2180
2104
            stacked (or not) status of the branch. If False assume the branch
2181
2105
            is not stacked.
2182
 
        :param name: Colocated branch name
2183
2106
        """
2184
2107
        # We intentionally don't call the parent class's __init__, because it
2185
2108
        # will try to assign to self.tags, which is a property in this subclass.
2204
2127
            self._real_branch = None
2205
2128
        # Fill out expected attributes of branch for bzrlib API users.
2206
2129
        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
 
2130
        self.base = self.bzrdir.root_transport.base
2210
2131
        self._control_files = None
2211
2132
        self._lock_mode = None
2212
2133
        self._lock_token = None
2277
2198
                    'to use vfs implementation')
2278
2199
            self.bzrdir._ensure_real()
2279
2200
            self._real_branch = self.bzrdir._real_bzrdir.open_branch(
2280
 
                ignore_fallbacks=self._real_ignore_fallbacks, name=self._name)
 
2201
                ignore_fallbacks=self._real_ignore_fallbacks)
2281
2202
            if self.repository._real_repository is None:
2282
2203
                # Give the remote repository the matching real repo.
2283
2204
                real_repo = self._real_branch.repository
2398
2319
            self._vfs_set_tags_bytes(bytes)
2399
2320
 
2400
2321
    def lock_read(self):
2401
 
        """Lock the branch for read operations.
2402
 
 
2403
 
        :return: A bzrlib.lock.LogicalLockResult.
2404
 
        """
2405
2322
        self.repository.lock_read()
2406
2323
        if not self._lock_mode:
2407
2324
            self._note_lock('r')
2411
2328
                self._real_branch.lock_read()
2412
2329
        else:
2413
2330
            self._lock_count += 1
2414
 
        return lock.LogicalLockResult(self.unlock)
2415
2331
 
2416
2332
    def _remote_lock_write(self, token):
2417
2333
        if token is None:
2418
2334
            branch_token = repo_token = ''
2419
2335
        else:
2420
2336
            branch_token = token
2421
 
            repo_token = self.repository.lock_write().repository_token
 
2337
            repo_token = self.repository.lock_write()
2422
2338
            self.repository.unlock()
2423
2339
        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])
 
2340
        response = self._call(
 
2341
            'Branch.lock_write', self._remote_path(), branch_token,
 
2342
            repo_token or '', **err_context)
2434
2343
        if response[0] != 'ok':
2435
2344
            raise errors.UnexpectedSmartServerResponse(response)
2436
2345
        ok, branch_token, repo_token = response
2457
2366
            self._lock_mode = 'w'
2458
2367
            self._lock_count = 1
2459
2368
        elif self._lock_mode == 'r':
2460
 
            raise errors.ReadOnlyError(self)
 
2369
            raise errors.ReadOnlyTransaction
2461
2370
        else:
2462
2371
            if token is not None:
2463
2372
                # A token was given to lock_write, and we're relocking, so
2468
2377
            self._lock_count += 1
2469
2378
            # Re-lock the repository too.
2470
2379
            self.repository.lock_write(self._repo_lock_token)
2471
 
        return BranchWriteLockResult(self.unlock, self._lock_token or None)
 
2380
        return self._lock_token or None
2472
2381
 
2473
2382
    def _unlock(self, branch_token, repo_token):
2474
2383
        err_context = {'token': str((branch_token, repo_token))}
2525
2434
            raise NotImplementedError(self.dont_leave_lock_in_place)
2526
2435
        self._leave_lock = False
2527
2436
 
2528
 
    @needs_read_lock
2529
2437
    def get_rev_id(self, revno, history=None):
2530
2438
        if revno == 0:
2531
2439
            return _mod_revision.NULL_REVISION
2797
2705
        medium = self._branch._client._medium
2798
2706
        if medium._is_remote_before((1, 14)):
2799
2707
            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
2708
        try:
2809
2709
            path = self._branch._remote_path()
2810
2710
            response = self._branch._client.call('Branch.set_config_option',
2811
2711
                path, self._branch._lock_token, self._branch._repo_lock_token,
2812
2712
                value.encode('utf8'), name, section or '')
2813
2713
        except errors.UnknownSmartMethod:
2814
 
            medium = self._branch._client._medium
2815
2714
            medium._remember_remote_is_before((1, 14))
2816
2715
            return self._vfs_set_option(value, name, section)
2817
2716
        if response != ():
2818
2717
            raise errors.UnexpectedSmartServerResponse(response)
2819
2718
 
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
2719
    def _real_object(self):
2846
2720
        self._branch._ensure_real()
2847
2721
        return self._branch._real_branch
2937
2811
        raise NoSuchRevision(find('branch'), err.error_args[0])
2938
2812
    elif err.error_verb == 'nosuchrevision':
2939
2813
        raise NoSuchRevision(find('repository'), err.error_args[0])
2940
 
    elif err.error_verb == 'nobranch':
2941
 
        if len(err.error_args) >= 1:
2942
 
            extra = err.error_args[0]
2943
 
        else:
2944
 
            extra = None
2945
 
        raise errors.NotBranchError(path=find('bzrdir').root_transport.base,
2946
 
            detail=extra)
 
2814
    elif err.error_tuple == ('nobranch',):
 
2815
        raise errors.NotBranchError(path=find('bzrdir').root_transport.base)
2947
2816
    elif err.error_verb == 'norepository':
2948
2817
        raise errors.NoRepositoryPresent(find('bzrdir'))
2949
2818
    elif err.error_verb == 'LockContention':