/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: Vincent Ladeuil
  • Date: 2009-10-06 14:40:37 UTC
  • mto: (4728.1.2 integration)
  • mto: This revision was merged to the branch mainline in revision 4731.
  • Revision ID: v.ladeuil+lp@free.fr-20091006144037-o76rgosv9hj3td0y
Simplify mutable_tree.has_changes() and update call sites.

* bzrlib/workingtree.py:
(WorkingTree.merge_from_branch): Add a force parameter. Replace
the check_basis() call by the corresponding code, taken the new
'force' parameter into account.

* bzrlib/tests/test_status.py:
(TestStatus.make_multiple_pending_tree): Add force=True on
supplementary merges.

* bzrlib/tests/test_reconfigure.py:
(TestReconfigure): Add a test for pending merges.

* bzrlib/tests/test_msgeditor.py:
(MsgEditorTest.make_multiple_pending_tree): Add force=True on
supplementary merges.

* bzrlib/tests/blackbox/test_uncommit.py:
(TestUncommit.test_uncommit_octopus_merge): Add force=True on
supplementary merges.

* bzrlib/send.py:
(send): Use the simplified has_changes(). Fix typo in comment too.

* bzrlib/reconfigure.py:
(Reconfigure._check): Use the simplified has_changes().

* bzrlib/mutabletree.py:
(MutableTree.has_changes): Make the tree parameter optional but
retain it for tests. Add a pending merges check.

* bzrlib/merge.py:
(Merger.ensure_revision_trees, Merger.file_revisions,
Merger.check_basis, Merger.compare_basis): Deprecate.

* bzrlib/bundle/apply_bundle.py:
(merge_bundle): Replace the check_basis() call by the
corresponding code.

* bzrlib/builtins.py:
(cmd_remove_tree.run, cmd_push.run, cmd_merge.run): Use the
simplified has_changes().
(cmd_merge.run): Replace the check_basis call() by the corresponding
code (minus the alredy done has_changes() check).

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
 
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
 
36
from bzrlib.decorators import needs_read_lock, needs_write_lock
39
37
from bzrlib.errors import (
40
38
    NoSuchRevision,
41
39
    SmartProtocolError,
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
 
117
114
 
118
115
        self._probe_bzrdir()
119
116
 
120
 
    def __repr__(self):
121
 
        return '%s(%r)' % (self.__class__.__name__, self._client)
122
 
 
123
117
    def _probe_bzrdir(self):
124
118
        medium = self._client._medium
125
119
        path = self._path_for_remote_call(self._client)
160
154
        Used before calls to self._real_bzrdir.
161
155
        """
162
156
        if not self._real_bzrdir:
163
 
            if 'hpssvfs' in debug.debug_flags:
164
 
                import traceback
165
 
                warning('VFS BzrDir access triggered\n%s',
166
 
                    ''.join(traceback.format_stack()))
167
157
            self._real_bzrdir = BzrDir.open_from_transport(
168
158
                self.root_transport, _server_formats=False)
169
159
            self._format._network_name = \
245
235
        self._ensure_real()
246
236
        self._real_bzrdir.destroy_repository()
247
237
 
248
 
    def create_branch(self, name=None):
 
238
    def create_branch(self):
249
239
        # as per meta1 formats - just delegate to the format object which may
250
240
        # be parameterised.
251
 
        real_branch = self._format.get_branch_format().initialize(self,
252
 
            name=name)
 
241
        real_branch = self._format.get_branch_format().initialize(self)
253
242
        if not isinstance(real_branch, RemoteBranch):
254
 
            result = RemoteBranch(self, self.find_repository(), real_branch,
255
 
                                  name=name)
 
243
            result = RemoteBranch(self, self.find_repository(), real_branch)
256
244
        else:
257
245
            result = real_branch
258
246
        # BzrDir.clone_on_transport() uses the result of create_branch but does
264
252
        self._next_open_branch_result = result
265
253
        return result
266
254
 
267
 
    def destroy_branch(self, name=None):
 
255
    def destroy_branch(self):
268
256
        """See BzrDir.destroy_branch"""
269
257
        self._ensure_real()
270
 
        self._real_bzrdir.destroy_branch(name=name)
 
258
        self._real_bzrdir.destroy_branch()
271
259
        self._next_open_branch_result = None
272
260
 
273
261
    def create_workingtree(self, revision_id=None, from_branch=None):
274
262
        raise errors.NotLocalUrl(self.transport.base)
275
263
 
276
 
    def find_branch_format(self, name=None):
 
264
    def find_branch_format(self):
277
265
        """Find the branch 'format' for this bzrdir.
278
266
 
279
267
        This might be a synthetic object for e.g. RemoteBranch and SVN.
280
268
        """
281
 
        b = self.open_branch(name=name)
 
269
        b = self.open_branch()
282
270
        return b._format
283
271
 
284
 
    def get_branch_reference(self, name=None):
 
272
    def get_branch_reference(self):
285
273
        """See BzrDir.get_branch_reference()."""
286
 
        if name is not None:
287
 
            # XXX JRV20100304: Support opening colocated branches
288
 
            raise errors.NoColocatedBranchSupport(self)
289
274
        response = self._get_branch_reference()
290
275
        if response[0] == 'ref':
291
276
            return response[1]
295
280
    def _get_branch_reference(self):
296
281
        path = self._path_for_remote_call(self._client)
297
282
        medium = self._client._medium
298
 
        candidate_calls = [
299
 
            ('BzrDir.open_branchV3', (2, 1)),
300
 
            ('BzrDir.open_branchV2', (1, 13)),
301
 
            ('BzrDir.open_branch', None),
302
 
            ]
303
 
        for verb, required_version in candidate_calls:
304
 
            if required_version and medium._is_remote_before(required_version):
305
 
                continue
 
283
        if not medium._is_remote_before((1, 13)):
306
284
            try:
307
 
                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
308
289
            except errors.UnknownSmartMethod:
309
 
                if required_version is None:
310
 
                    raise
311
 
                medium._remember_remote_is_before(required_version)
312
 
            else:
313
 
                break
314
 
        if verb == 'BzrDir.open_branch':
315
 
            if response[0] != 'ok':
316
 
                raise errors.UnexpectedSmartServerResponse(response)
317
 
            if response[1] != '':
318
 
                return ('ref', response[1])
319
 
            else:
320
 
                return ('branch', '')
321
 
        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':
322
293
            raise errors.UnexpectedSmartServerResponse(response)
323
 
        return response
 
294
        if response[1] != '':
 
295
            return ('ref', response[1])
 
296
        else:
 
297
            return ('branch', '')
324
298
 
325
 
    def _get_tree_branch(self, name=None):
 
299
    def _get_tree_branch(self):
326
300
        """See BzrDir._get_tree_branch()."""
327
 
        return None, self.open_branch(name=name)
 
301
        return None, self.open_branch()
328
302
 
329
 
    def open_branch(self, name=None, unsupported=False,
330
 
                    ignore_fallbacks=False):
331
 
        if unsupported:
 
303
    def open_branch(self, _unsupported=False, ignore_fallbacks=False):
 
304
        if _unsupported:
332
305
            raise NotImplementedError('unsupported flag support not implemented yet.')
333
306
        if self._next_open_branch_result is not None:
334
307
            # See create_branch for details.
339
312
        if response[0] == 'ref':
340
313
            # a branch reference, use the existing BranchReference logic.
341
314
            format = BranchReferenceFormat()
342
 
            return format.open(self, name=name, _found=True,
343
 
                location=response[1], ignore_fallbacks=ignore_fallbacks)
 
315
            return format.open(self, _found=True, location=response[1],
 
316
                ignore_fallbacks=ignore_fallbacks)
344
317
        branch_format_name = response[1]
345
318
        if not branch_format_name:
346
319
            branch_format_name = None
347
320
        format = RemoteBranchFormat(network_name=branch_format_name)
348
321
        return RemoteBranch(self, self.find_repository(), format=format,
349
 
            setup_stacking=not ignore_fallbacks, name=name)
 
322
            setup_stacking=not ignore_fallbacks)
350
323
 
351
324
    def _open_repo_v1(self, path):
352
325
        verb = 'BzrDir.find_repository'
429
402
        """Return the path to be used for this bzrdir in a remote call."""
430
403
        return client.remote_path_from_transport(self.root_transport)
431
404
 
432
 
    def get_branch_transport(self, branch_format, name=None):
 
405
    def get_branch_transport(self, branch_format):
433
406
        self._ensure_real()
434
 
        return self._real_bzrdir.get_branch_transport(branch_format, name=name)
 
407
        return self._real_bzrdir.get_branch_transport(branch_format)
435
408
 
436
409
    def get_repository_transport(self, repository_format):
437
410
        self._ensure_real()
624
597
        return self._custom_format._fetch_reconcile
625
598
 
626
599
    def get_format_description(self):
627
 
        self._ensure_real()
628
 
        return 'Remote: ' + self._custom_format.get_format_description()
 
600
        return 'bzr remote repository'
629
601
 
630
602
    def __eq__(self, other):
631
603
        return self.__class__ is other.__class__
647
619
        return self._custom_format._serializer
648
620
 
649
621
 
650
 
class RemoteRepository(_RpcHelper, lock._RelockDebugMixin,
651
 
    bzrdir.ControlComponent):
 
622
class RemoteRepository(_RpcHelper):
652
623
    """Repository accessed over rpc.
653
624
 
654
625
    For the moment most operations are performed using local transport-backed
697
668
        # Additional places to query for data.
698
669
        self._fallback_repositories = []
699
670
 
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
671
    def __str__(self):
712
672
        return "%s(%s)" % (self.__class__.__name__, self.base)
713
673
 
921
881
        parents_provider = self._make_parents_provider(other_repository)
922
882
        return graph.Graph(parents_provider)
923
883
 
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
884
    def gather_stats(self, revid=None, committers=None):
934
885
        """See Repository.gather_stats()."""
935
886
        path = self.bzrdir._path_for_remote_call(self._client)
995
946
    def is_write_locked(self):
996
947
        return self._lock_mode == 'w'
997
948
 
998
 
    def _warn_if_deprecated(self, branch=None):
999
 
        # If we have a real repository, the check will be done there, if we
1000
 
        # don't the check will be done remotely.
1001
 
        pass
1002
 
 
1003
949
    def lock_read(self):
1004
 
        """Lock the repository for read operations.
1005
 
 
1006
 
        :return: A bzrlib.lock.LogicalLockResult.
1007
 
        """
1008
950
        # wrong eventually - want a local lock cache context
1009
951
        if not self._lock_mode:
1010
 
            self._note_lock('r')
1011
952
            self._lock_mode = 'r'
1012
953
            self._lock_count = 1
1013
954
            self._unstacked_provider.enable_cache(cache_misses=True)
1017
958
                repo.lock_read()
1018
959
        else:
1019
960
            self._lock_count += 1
1020
 
        return lock.LogicalLockResult(self.unlock)
1021
961
 
1022
962
    def _remote_lock_write(self, token):
1023
963
        path = self.bzrdir._path_for_remote_call(self._client)
1034
974
 
1035
975
    def lock_write(self, token=None, _skip_rpc=False):
1036
976
        if not self._lock_mode:
1037
 
            self._note_lock('w')
1038
977
            if _skip_rpc:
1039
978
                if self._lock_token is not None:
1040
979
                    if token != self._lock_token:
1063
1002
            raise errors.ReadOnlyError(self)
1064
1003
        else:
1065
1004
            self._lock_count += 1
1066
 
        return RepositoryWriteLockResult(self.unlock, self._lock_token or None)
 
1005
        return self._lock_token or None
1067
1006
 
1068
1007
    def leave_lock_in_place(self):
1069
1008
        if not self._lock_token:
1143
1082
        else:
1144
1083
            raise errors.UnexpectedSmartServerResponse(response)
1145
1084
 
1146
 
    @only_raises(errors.LockNotHeld, errors.LockBroken)
1147
1085
    def unlock(self):
1148
1086
        if not self._lock_count:
1149
1087
            return lock.cant_unlock_not_held(self)
1249
1187
            # state, so always add a lock here. If a caller passes us a locked
1250
1188
            # repository, they are responsible for unlocking it later.
1251
1189
            repository.lock_read()
1252
 
        self._check_fallback_repository(repository)
1253
1190
        self._fallback_repositories.append(repository)
1254
1191
        # If self._real_repository was parameterised already (e.g. because a
1255
1192
        # _real_branch had its get_stacked_on_url method called), then the
1256
1193
        # repository to be added may already be in the _real_repositories list.
1257
1194
        if self._real_repository is not None:
1258
 
            fallback_locations = [repo.user_url for repo in
 
1195
            fallback_locations = [repo.bzrdir.root_transport.base for repo in
1259
1196
                self._real_repository._fallback_repositories]
1260
 
            if repository.user_url not in fallback_locations:
 
1197
            if repository.bzrdir.root_transport.base not in fallback_locations:
1261
1198
                self._real_repository.add_fallback_repository(repository)
1262
1199
 
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
1200
    def add_inventory(self, revid, inv, parents):
1274
1201
        self._ensure_real()
1275
1202
        return self._real_repository.add_inventory(revid, inv, parents)
1276
1203
 
1277
1204
    def add_inventory_by_delta(self, basis_revision_id, delta, new_revision_id,
1278
 
            parents, basis_inv=None, propagate_caches=False):
 
1205
                               parents):
1279
1206
        self._ensure_real()
1280
1207
        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)
 
1208
            delta, new_revision_id, parents)
1283
1209
 
1284
1210
    def add_revision(self, rev_id, rev, inv=None, config=None):
1285
1211
        self._ensure_real()
1315
1241
        return self._real_repository.make_working_trees()
1316
1242
 
1317
1243
    def refresh_data(self):
1318
 
        """Re-read any data needed to synchronise with disk.
 
1244
        """Re-read any data needed to to synchronise with disk.
1319
1245
 
1320
1246
        This method is intended to be called after another repository instance
1321
1247
        (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.
 
1248
        repository. It may not be called during a write group, but may be
 
1249
        called at any other time.
1327
1250
        """
 
1251
        if self.is_in_write_group():
 
1252
            raise errors.InternalBzrError(
 
1253
                "May not refresh_data while in a write group.")
1328
1254
        if self._real_repository is not None:
1329
1255
            self._real_repository.refresh_data()
1330
1256
 
1544
1470
        return self._real_repository.get_signature_text(revision_id)
1545
1471
 
1546
1472
    @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)
 
1473
    def get_inventory_xml(self, revision_id):
 
1474
        self._ensure_real()
 
1475
        return self._real_repository.get_inventory_xml(revision_id)
 
1476
 
 
1477
    def deserialise_inventory(self, revision_id, xml):
 
1478
        self._ensure_real()
 
1479
        return self._real_repository.deserialise_inventory(revision_id, xml)
1550
1480
 
1551
1481
    def reconcile(self, other=None, thorough=False):
1552
1482
        self._ensure_real()
1628
1558
        return self._real_repository.inventories
1629
1559
 
1630
1560
    @needs_write_lock
1631
 
    def pack(self, hint=None, clean_obsolete_packs=False):
 
1561
    def pack(self, hint=None):
1632
1562
        """Compress the data within the repository.
1633
1563
 
1634
1564
        This is not currently implemented within the smart server.
1635
1565
        """
1636
1566
        self._ensure_real()
1637
 
        return self._real_repository.pack(hint=hint, clean_obsolete_packs=clean_obsolete_packs)
 
1567
        return self._real_repository.pack(hint=hint)
1638
1568
 
1639
1569
    @property
1640
1570
    def revisions(self):
2062
1992
                self._network_name)
2063
1993
 
2064
1994
    def get_format_description(self):
2065
 
        self._ensure_real()
2066
 
        return 'Remote: ' + self._custom_format.get_format_description()
 
1995
        return 'Remote BZR Branch'
2067
1996
 
2068
1997
    def network_name(self):
2069
1998
        return self._network_name
2070
1999
 
2071
 
    def open(self, a_bzrdir, name=None, ignore_fallbacks=False):
2072
 
        return a_bzrdir.open_branch(name=name, 
2073
 
            ignore_fallbacks=ignore_fallbacks)
 
2000
    def open(self, a_bzrdir, ignore_fallbacks=False):
 
2001
        return a_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks)
2074
2002
 
2075
 
    def _vfs_initialize(self, a_bzrdir, name):
 
2003
    def _vfs_initialize(self, a_bzrdir):
2076
2004
        # Initialisation when using a local bzrdir object, or a non-vfs init
2077
2005
        # method is not available on the server.
2078
2006
        # self._custom_format is always set - the start of initialize ensures
2079
2007
        # that.
2080
2008
        if isinstance(a_bzrdir, RemoteBzrDir):
2081
2009
            a_bzrdir._ensure_real()
2082
 
            result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
2083
 
                name)
 
2010
            result = self._custom_format.initialize(a_bzrdir._real_bzrdir)
2084
2011
        else:
2085
2012
            # We assume the bzrdir is parameterised; it may not be.
2086
 
            result = self._custom_format.initialize(a_bzrdir, name)
 
2013
            result = self._custom_format.initialize(a_bzrdir)
2087
2014
        if (isinstance(a_bzrdir, RemoteBzrDir) and
2088
2015
            not isinstance(result, RemoteBranch)):
2089
 
            result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result,
2090
 
                                  name=name)
 
2016
            result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result)
2091
2017
        return result
2092
2018
 
2093
 
    def initialize(self, a_bzrdir, name=None):
 
2019
    def initialize(self, a_bzrdir):
2094
2020
        # 1) get the network name to use.
2095
2021
        if self._custom_format:
2096
2022
            network_name = self._custom_format.network_name()
2102
2028
            network_name = reference_format.network_name()
2103
2029
        # Being asked to create on a non RemoteBzrDir:
2104
2030
        if not isinstance(a_bzrdir, RemoteBzrDir):
2105
 
            return self._vfs_initialize(a_bzrdir, name=name)
 
2031
            return self._vfs_initialize(a_bzrdir)
2106
2032
        medium = a_bzrdir._client._medium
2107
2033
        if medium._is_remote_before((1, 13)):
2108
 
            return self._vfs_initialize(a_bzrdir, name=name)
 
2034
            return self._vfs_initialize(a_bzrdir)
2109
2035
        # Creating on a remote bzr dir.
2110
2036
        # 2) try direct creation via RPC
2111
2037
        path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
2112
 
        if name is not None:
2113
 
            # XXX JRV20100304: Support creating colocated branches
2114
 
            raise errors.NoColocatedBranchSupport(self)
2115
2038
        verb = 'BzrDir.create_branch'
2116
2039
        try:
2117
2040
            response = a_bzrdir._call(verb, path, network_name)
2118
2041
        except errors.UnknownSmartMethod:
2119
2042
            # Fallback - use vfs methods
2120
2043
            medium._remember_remote_is_before((1, 13))
2121
 
            return self._vfs_initialize(a_bzrdir, name=name)
 
2044
            return self._vfs_initialize(a_bzrdir)
2122
2045
        if response[0] != 'ok':
2123
2046
            raise errors.UnexpectedSmartServerResponse(response)
2124
2047
        # Turn the response into a RemoteRepository object.
2132
2055
                a_bzrdir._client)
2133
2056
        remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2134
2057
        remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2135
 
            format=format, setup_stacking=False, name=name)
 
2058
            format=format, setup_stacking=False)
2136
2059
        # XXX: We know this is a new branch, so it must have revno 0, revid
2137
2060
        # NULL_REVISION. Creating the branch locked would make this be unable
2138
2061
        # to be wrong; here its simply very unlikely to be wrong. RBC 20090225
2158
2081
        return self._custom_format.supports_set_append_revisions_only()
2159
2082
 
2160
2083
 
2161
 
class RemoteBranch(branch.Branch, _RpcHelper, lock._RelockDebugMixin):
 
2084
class RemoteBranch(branch.Branch, _RpcHelper):
2162
2085
    """Branch stored on a server accessed by HPSS RPC.
2163
2086
 
2164
2087
    At the moment most operations are mapped down to simple file operations.
2165
2088
    """
2166
2089
 
2167
2090
    def __init__(self, remote_bzrdir, remote_repository, real_branch=None,
2168
 
        _client=None, format=None, setup_stacking=True, name=None):
 
2091
        _client=None, format=None, setup_stacking=True):
2169
2092
        """Create a RemoteBranch instance.
2170
2093
 
2171
2094
        :param real_branch: An optional local implementation of the branch
2177
2100
        :param setup_stacking: If True make an RPC call to determine the
2178
2101
            stacked (or not) status of the branch. If False assume the branch
2179
2102
            is not stacked.
2180
 
        :param name: Colocated branch name
2181
2103
        """
2182
2104
        # We intentionally don't call the parent class's __init__, because it
2183
2105
        # will try to assign to self.tags, which is a property in this subclass.
2202
2124
            self._real_branch = None
2203
2125
        # Fill out expected attributes of branch for bzrlib API users.
2204
2126
        self._clear_cached_state()
2205
 
        # TODO: deprecate self.base in favor of user_url
2206
 
        self.base = self.bzrdir.user_url
2207
 
        self._name = name
 
2127
        self.base = self.bzrdir.root_transport.base
2208
2128
        self._control_files = None
2209
2129
        self._lock_mode = None
2210
2130
        self._lock_token = None
2275
2195
                    'to use vfs implementation')
2276
2196
            self.bzrdir._ensure_real()
2277
2197
            self._real_branch = self.bzrdir._real_bzrdir.open_branch(
2278
 
                ignore_fallbacks=self._real_ignore_fallbacks, name=self._name)
 
2198
                ignore_fallbacks=self._real_ignore_fallbacks)
2279
2199
            if self.repository._real_repository is None:
2280
2200
                # Give the remote repository the matching real repo.
2281
2201
                real_repo = self._real_branch.repository
2396
2316
            self._vfs_set_tags_bytes(bytes)
2397
2317
 
2398
2318
    def lock_read(self):
2399
 
        """Lock the branch for read operations.
2400
 
 
2401
 
        :return: A bzrlib.lock.LogicalLockResult.
2402
 
        """
2403
2319
        self.repository.lock_read()
2404
2320
        if not self._lock_mode:
2405
 
            self._note_lock('r')
2406
2321
            self._lock_mode = 'r'
2407
2322
            self._lock_count = 1
2408
2323
            if self._real_branch is not None:
2409
2324
                self._real_branch.lock_read()
2410
2325
        else:
2411
2326
            self._lock_count += 1
2412
 
        return lock.LogicalLockResult(self.unlock)
2413
2327
 
2414
2328
    def _remote_lock_write(self, token):
2415
2329
        if token is None:
2416
2330
            branch_token = repo_token = ''
2417
2331
        else:
2418
2332
            branch_token = token
2419
 
            repo_token = self.repository.lock_write().repository_token
 
2333
            repo_token = self.repository.lock_write()
2420
2334
            self.repository.unlock()
2421
2335
        err_context = {'token': token}
2422
2336
        response = self._call(
2429
2343
 
2430
2344
    def lock_write(self, token=None):
2431
2345
        if not self._lock_mode:
2432
 
            self._note_lock('w')
2433
2346
            # Lock the branch and repo in one remote call.
2434
2347
            remote_tokens = self._remote_lock_write(token)
2435
2348
            self._lock_token, self._repo_lock_token = remote_tokens
2459
2372
            self._lock_count += 1
2460
2373
            # Re-lock the repository too.
2461
2374
            self.repository.lock_write(self._repo_lock_token)
2462
 
        return BranchWriteLockResult(self.unlock, self._lock_token or None)
 
2375
        return self._lock_token or None
2463
2376
 
2464
2377
    def _unlock(self, branch_token, repo_token):
2465
2378
        err_context = {'token': str((branch_token, repo_token))}
2470
2383
            return
2471
2384
        raise errors.UnexpectedSmartServerResponse(response)
2472
2385
 
2473
 
    @only_raises(errors.LockNotHeld, errors.LockBroken)
2474
2386
    def unlock(self):
2475
2387
        try:
2476
2388
            self._lock_count -= 1
2516
2428
            raise NotImplementedError(self.dont_leave_lock_in_place)
2517
2429
        self._leave_lock = False
2518
2430
 
2519
 
    @needs_read_lock
2520
2431
    def get_rev_id(self, revno, history=None):
2521
2432
        if revno == 0:
2522
2433
            return _mod_revision.NULL_REVISION
2894
2805
        raise NoSuchRevision(find('branch'), err.error_args[0])
2895
2806
    elif err.error_verb == 'nosuchrevision':
2896
2807
        raise NoSuchRevision(find('repository'), err.error_args[0])
2897
 
    elif err.error_verb == 'nobranch':
2898
 
        if len(err.error_args) >= 1:
2899
 
            extra = err.error_args[0]
2900
 
        else:
2901
 
            extra = None
2902
 
        raise errors.NotBranchError(path=find('bzrdir').root_transport.base,
2903
 
            detail=extra)
 
2808
    elif err.error_tuple == ('nobranch',):
 
2809
        raise errors.NotBranchError(path=find('bzrdir').root_transport.base)
2904
2810
    elif err.error_verb == 'norepository':
2905
2811
        raise errors.NoRepositoryPresent(find('bzrdir'))
2906
2812
    elif err.error_verb == 'LockContention':