/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: Andrew Bennetts
  • Date: 2009-10-21 11:13:40 UTC
  • mto: This revision was merged to the branch mainline in revision 4762.
  • Revision ID: andrew.bennetts@canonical.com-20091021111340-w7x4d5yf83qwjncc
Add test that WSGI glue allows request handlers to access paths above that request's. backing transport, so long as it is within the WSGI app's backing transport.

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
 
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):
292
280
    def _get_branch_reference(self):
293
281
        path = self._path_for_remote_call(self._client)
294
282
        medium = self._client._medium
295
 
        candidate_calls = [
296
 
            ('BzrDir.open_branchV3', (2, 1)),
297
 
            ('BzrDir.open_branchV2', (1, 13)),
298
 
            ('BzrDir.open_branch', None),
299
 
            ]
300
 
        for verb, required_version in candidate_calls:
301
 
            if required_version and medium._is_remote_before(required_version):
302
 
                continue
 
283
        if not medium._is_remote_before((1, 13)):
303
284
            try:
304
 
                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
305
289
            except errors.UnknownSmartMethod:
306
 
                if required_version is None:
307
 
                    raise
308
 
                medium._remember_remote_is_before(required_version)
309
 
            else:
310
 
                break
311
 
        if verb == 'BzrDir.open_branch':
312
 
            if response[0] != 'ok':
313
 
                raise errors.UnexpectedSmartServerResponse(response)
314
 
            if response[1] != '':
315
 
                return ('ref', response[1])
316
 
            else:
317
 
                return ('branch', '')
318
 
        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':
319
293
            raise errors.UnexpectedSmartServerResponse(response)
320
 
        return response
 
294
        if response[1] != '':
 
295
            return ('ref', response[1])
 
296
        else:
 
297
            return ('branch', '')
321
298
 
322
299
    def _get_tree_branch(self):
323
300
        """See BzrDir._get_tree_branch()."""
324
301
        return None, self.open_branch()
325
302
 
326
 
    def open_branch(self, name=None, unsupported=False,
327
 
                    ignore_fallbacks=False):
328
 
        if unsupported:
 
303
    def open_branch(self, _unsupported=False, ignore_fallbacks=False):
 
304
        if _unsupported:
329
305
            raise NotImplementedError('unsupported flag support not implemented yet.')
330
306
        if self._next_open_branch_result is not None:
331
307
            # See create_branch for details.
336
312
        if response[0] == 'ref':
337
313
            # a branch reference, use the existing BranchReference logic.
338
314
            format = BranchReferenceFormat()
339
 
            return format.open(self, name=name, _found=True,
340
 
                location=response[1], ignore_fallbacks=ignore_fallbacks)
 
315
            return format.open(self, _found=True, location=response[1],
 
316
                ignore_fallbacks=ignore_fallbacks)
341
317
        branch_format_name = response[1]
342
318
        if not branch_format_name:
343
319
            branch_format_name = None
344
320
        format = RemoteBranchFormat(network_name=branch_format_name)
345
321
        return RemoteBranch(self, self.find_repository(), format=format,
346
 
            setup_stacking=not ignore_fallbacks, name=name)
 
322
            setup_stacking=not ignore_fallbacks)
347
323
 
348
324
    def _open_repo_v1(self, path):
349
325
        verb = 'BzrDir.find_repository'
426
402
        """Return the path to be used for this bzrdir in a remote call."""
427
403
        return client.remote_path_from_transport(self.root_transport)
428
404
 
429
 
    def get_branch_transport(self, branch_format, name=None):
 
405
    def get_branch_transport(self, branch_format):
430
406
        self._ensure_real()
431
 
        return self._real_bzrdir.get_branch_transport(branch_format, name=name)
 
407
        return self._real_bzrdir.get_branch_transport(branch_format)
432
408
 
433
409
    def get_repository_transport(self, repository_format):
434
410
        self._ensure_real()
621
597
        return self._custom_format._fetch_reconcile
622
598
 
623
599
    def get_format_description(self):
624
 
        self._ensure_real()
625
 
        return 'Remote: ' + self._custom_format.get_format_description()
 
600
        return 'bzr remote repository'
626
601
 
627
602
    def __eq__(self, other):
628
603
        return self.__class__ is other.__class__
644
619
        return self._custom_format._serializer
645
620
 
646
621
 
647
 
class RemoteRepository(_RpcHelper, lock._RelockDebugMixin,
648
 
    bzrdir.ControlComponent):
 
622
class RemoteRepository(_RpcHelper, lock._RelockDebugMixin):
649
623
    """Repository accessed over rpc.
650
624
 
651
625
    For the moment most operations are performed using local transport-backed
694
668
        # Additional places to query for data.
695
669
        self._fallback_repositories = []
696
670
 
697
 
    @property
698
 
    def user_transport(self):
699
 
        return self.bzrdir.user_transport
700
 
 
701
 
    @property
702
 
    def control_transport(self):
703
 
        # XXX: Normally you shouldn't directly get at the remote repository
704
 
        # transport, but I'm not sure it's worth making this method
705
 
        # optional -- mbp 2010-04-21
706
 
        return self.bzrdir.get_repository_transport(None)
707
 
        
708
671
    def __str__(self):
709
672
        return "%s(%s)" % (self.__class__.__name__, self.base)
710
673
 
918
881
        parents_provider = self._make_parents_provider(other_repository)
919
882
        return graph.Graph(parents_provider)
920
883
 
921
 
    @needs_read_lock
922
 
    def get_known_graph_ancestry(self, revision_ids):
923
 
        """Return the known graph for a set of revision ids and their ancestors.
924
 
        """
925
 
        st = static_tuple.StaticTuple
926
 
        revision_keys = [st(r_id).intern() for r_id in revision_ids]
927
 
        known_graph = self.revisions.get_known_graph_ancestry(revision_keys)
928
 
        return graph.GraphThunkIdsToKeys(known_graph)
929
 
 
930
884
    def gather_stats(self, revid=None, committers=None):
931
885
        """See Repository.gather_stats()."""
932
886
        path = self.bzrdir._path_for_remote_call(self._client)
992
946
    def is_write_locked(self):
993
947
        return self._lock_mode == 'w'
994
948
 
995
 
    def _warn_if_deprecated(self, branch=None):
996
 
        # If we have a real repository, the check will be done there, if we
997
 
        # don't the check will be done remotely.
998
 
        pass
999
 
 
1000
949
    def lock_read(self):
1001
 
        """Lock the repository for read operations.
1002
 
 
1003
 
        :return: An object with an unlock method which will release the lock
1004
 
            obtained.
1005
 
        """
1006
950
        # wrong eventually - want a local lock cache context
1007
951
        if not self._lock_mode:
1008
952
            self._note_lock('r')
1015
959
                repo.lock_read()
1016
960
        else:
1017
961
            self._lock_count += 1
1018
 
        return self
1019
962
 
1020
963
    def _remote_lock_write(self, token):
1021
964
        path = self.bzrdir._path_for_remote_call(self._client)
1061
1004
            raise errors.ReadOnlyError(self)
1062
1005
        else:
1063
1006
            self._lock_count += 1
1064
 
        return RepositoryWriteLockResult(self.unlock, self._lock_token or None)
 
1007
        return self._lock_token or None
1065
1008
 
1066
1009
    def leave_lock_in_place(self):
1067
1010
        if not self._lock_token:
1247
1190
            # state, so always add a lock here. If a caller passes us a locked
1248
1191
            # repository, they are responsible for unlocking it later.
1249
1192
            repository.lock_read()
1250
 
        self._check_fallback_repository(repository)
1251
1193
        self._fallback_repositories.append(repository)
1252
1194
        # If self._real_repository was parameterised already (e.g. because a
1253
1195
        # _real_branch had its get_stacked_on_url method called), then the
1254
1196
        # repository to be added may already be in the _real_repositories list.
1255
1197
        if self._real_repository is not None:
1256
 
            fallback_locations = [repo.user_url for repo in
 
1198
            fallback_locations = [repo.bzrdir.root_transport.base for repo in
1257
1199
                self._real_repository._fallback_repositories]
1258
 
            if repository.user_url not in fallback_locations:
 
1200
            if repository.bzrdir.root_transport.base not in fallback_locations:
1259
1201
                self._real_repository.add_fallback_repository(repository)
1260
1202
 
1261
 
    def _check_fallback_repository(self, repository):
1262
 
        """Check that this repository can fallback to repository safely.
1263
 
 
1264
 
        Raise an error if not.
1265
 
 
1266
 
        :param repository: A repository to fallback to.
1267
 
        """
1268
 
        return _mod_repository.InterRepository._assert_same_model(
1269
 
            self, repository)
1270
 
 
1271
1203
    def add_inventory(self, revid, inv, parents):
1272
1204
        self._ensure_real()
1273
1205
        return self._real_repository.add_inventory(revid, inv, parents)
1274
1206
 
1275
1207
    def add_inventory_by_delta(self, basis_revision_id, delta, new_revision_id,
1276
 
            parents, basis_inv=None, propagate_caches=False):
 
1208
                               parents):
1277
1209
        self._ensure_real()
1278
1210
        return self._real_repository.add_inventory_by_delta(basis_revision_id,
1279
 
            delta, new_revision_id, parents, basis_inv=basis_inv,
1280
 
            propagate_caches=propagate_caches)
 
1211
            delta, new_revision_id, parents)
1281
1212
 
1282
1213
    def add_revision(self, rev_id, rev, inv=None, config=None):
1283
1214
        self._ensure_real()
1542
1473
        return self._real_repository.get_signature_text(revision_id)
1543
1474
 
1544
1475
    @needs_read_lock
1545
 
    def _get_inventory_xml(self, revision_id):
1546
 
        self._ensure_real()
1547
 
        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)
1548
1483
 
1549
1484
    def reconcile(self, other=None, thorough=False):
1550
1485
        self._ensure_real()
1626
1561
        return self._real_repository.inventories
1627
1562
 
1628
1563
    @needs_write_lock
1629
 
    def pack(self, hint=None, clean_obsolete_packs=False):
 
1564
    def pack(self, hint=None):
1630
1565
        """Compress the data within the repository.
1631
1566
 
1632
1567
        This is not currently implemented within the smart server.
1633
1568
        """
1634
1569
        self._ensure_real()
1635
 
        return self._real_repository.pack(hint=hint, clean_obsolete_packs=clean_obsolete_packs)
 
1570
        return self._real_repository.pack(hint=hint)
1636
1571
 
1637
1572
    @property
1638
1573
    def revisions(self):
2060
1995
                self._network_name)
2061
1996
 
2062
1997
    def get_format_description(self):
2063
 
        self._ensure_real()
2064
 
        return 'Remote: ' + self._custom_format.get_format_description()
 
1998
        return 'Remote BZR Branch'
2065
1999
 
2066
2000
    def network_name(self):
2067
2001
        return self._network_name
2068
2002
 
2069
 
    def open(self, a_bzrdir, name=None, ignore_fallbacks=False):
2070
 
        return a_bzrdir.open_branch(name=name, 
2071
 
            ignore_fallbacks=ignore_fallbacks)
 
2003
    def open(self, a_bzrdir, ignore_fallbacks=False):
 
2004
        return a_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks)
2072
2005
 
2073
 
    def _vfs_initialize(self, a_bzrdir, name):
 
2006
    def _vfs_initialize(self, a_bzrdir):
2074
2007
        # Initialisation when using a local bzrdir object, or a non-vfs init
2075
2008
        # method is not available on the server.
2076
2009
        # self._custom_format is always set - the start of initialize ensures
2077
2010
        # that.
2078
2011
        if isinstance(a_bzrdir, RemoteBzrDir):
2079
2012
            a_bzrdir._ensure_real()
2080
 
            result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
2081
 
                name)
 
2013
            result = self._custom_format.initialize(a_bzrdir._real_bzrdir)
2082
2014
        else:
2083
2015
            # We assume the bzrdir is parameterised; it may not be.
2084
 
            result = self._custom_format.initialize(a_bzrdir, name)
 
2016
            result = self._custom_format.initialize(a_bzrdir)
2085
2017
        if (isinstance(a_bzrdir, RemoteBzrDir) and
2086
2018
            not isinstance(result, RemoteBranch)):
2087
 
            result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result,
2088
 
                                  name=name)
 
2019
            result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result)
2089
2020
        return result
2090
2021
 
2091
 
    def initialize(self, a_bzrdir, name=None):
 
2022
    def initialize(self, a_bzrdir):
2092
2023
        # 1) get the network name to use.
2093
2024
        if self._custom_format:
2094
2025
            network_name = self._custom_format.network_name()
2100
2031
            network_name = reference_format.network_name()
2101
2032
        # Being asked to create on a non RemoteBzrDir:
2102
2033
        if not isinstance(a_bzrdir, RemoteBzrDir):
2103
 
            return self._vfs_initialize(a_bzrdir, name=name)
 
2034
            return self._vfs_initialize(a_bzrdir)
2104
2035
        medium = a_bzrdir._client._medium
2105
2036
        if medium._is_remote_before((1, 13)):
2106
 
            return self._vfs_initialize(a_bzrdir, name=name)
 
2037
            return self._vfs_initialize(a_bzrdir)
2107
2038
        # Creating on a remote bzr dir.
2108
2039
        # 2) try direct creation via RPC
2109
2040
        path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
2110
 
        if name is not None:
2111
 
            # XXX JRV20100304: Support creating colocated branches
2112
 
            raise errors.NoColocatedBranchSupport(self)
2113
2041
        verb = 'BzrDir.create_branch'
2114
2042
        try:
2115
2043
            response = a_bzrdir._call(verb, path, network_name)
2116
2044
        except errors.UnknownSmartMethod:
2117
2045
            # Fallback - use vfs methods
2118
2046
            medium._remember_remote_is_before((1, 13))
2119
 
            return self._vfs_initialize(a_bzrdir, name=name)
 
2047
            return self._vfs_initialize(a_bzrdir)
2120
2048
        if response[0] != 'ok':
2121
2049
            raise errors.UnexpectedSmartServerResponse(response)
2122
2050
        # Turn the response into a RemoteRepository object.
2130
2058
                a_bzrdir._client)
2131
2059
        remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2132
2060
        remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2133
 
            format=format, setup_stacking=False, name=name)
 
2061
            format=format, setup_stacking=False)
2134
2062
        # XXX: We know this is a new branch, so it must have revno 0, revid
2135
2063
        # NULL_REVISION. Creating the branch locked would make this be unable
2136
2064
        # to be wrong; here its simply very unlikely to be wrong. RBC 20090225
2163
2091
    """
2164
2092
 
2165
2093
    def __init__(self, remote_bzrdir, remote_repository, real_branch=None,
2166
 
        _client=None, format=None, setup_stacking=True, name=None):
 
2094
        _client=None, format=None, setup_stacking=True):
2167
2095
        """Create a RemoteBranch instance.
2168
2096
 
2169
2097
        :param real_branch: An optional local implementation of the branch
2175
2103
        :param setup_stacking: If True make an RPC call to determine the
2176
2104
            stacked (or not) status of the branch. If False assume the branch
2177
2105
            is not stacked.
2178
 
        :param name: Colocated branch name
2179
2106
        """
2180
2107
        # We intentionally don't call the parent class's __init__, because it
2181
2108
        # will try to assign to self.tags, which is a property in this subclass.
2200
2127
            self._real_branch = None
2201
2128
        # Fill out expected attributes of branch for bzrlib API users.
2202
2129
        self._clear_cached_state()
2203
 
        # TODO: deprecate self.base in favor of user_url
2204
 
        self.base = self.bzrdir.user_url
2205
 
        self._name = name
 
2130
        self.base = self.bzrdir.root_transport.base
2206
2131
        self._control_files = None
2207
2132
        self._lock_mode = None
2208
2133
        self._lock_token = None
2273
2198
                    'to use vfs implementation')
2274
2199
            self.bzrdir._ensure_real()
2275
2200
            self._real_branch = self.bzrdir._real_bzrdir.open_branch(
2276
 
                ignore_fallbacks=self._real_ignore_fallbacks, name=self._name)
 
2201
                ignore_fallbacks=self._real_ignore_fallbacks)
2277
2202
            if self.repository._real_repository is None:
2278
2203
                # Give the remote repository the matching real repo.
2279
2204
                real_repo = self._real_branch.repository
2394
2319
            self._vfs_set_tags_bytes(bytes)
2395
2320
 
2396
2321
    def lock_read(self):
2397
 
        """Lock the branch for read operations.
2398
 
 
2399
 
        :return: An object with an unlock method which will release the lock
2400
 
            obtained.
2401
 
        """
2402
2322
        self.repository.lock_read()
2403
2323
        if not self._lock_mode:
2404
2324
            self._note_lock('r')
2408
2328
                self._real_branch.lock_read()
2409
2329
        else:
2410
2330
            self._lock_count += 1
2411
 
        return self
2412
2331
 
2413
2332
    def _remote_lock_write(self, token):
2414
2333
        if token is None:
2415
2334
            branch_token = repo_token = ''
2416
2335
        else:
2417
2336
            branch_token = token
2418
 
            repo_token = self.repository.lock_write().repository_token
 
2337
            repo_token = self.repository.lock_write()
2419
2338
            self.repository.unlock()
2420
2339
        err_context = {'token': token}
2421
2340
        response = self._call(
2458
2377
            self._lock_count += 1
2459
2378
            # Re-lock the repository too.
2460
2379
            self.repository.lock_write(self._repo_lock_token)
2461
 
        return BranchWriteLockResult(self.unlock, self._lock_token or None)
 
2380
        return self._lock_token or None
2462
2381
 
2463
2382
    def _unlock(self, branch_token, repo_token):
2464
2383
        err_context = {'token': str((branch_token, repo_token))}
2893
2812
        raise NoSuchRevision(find('branch'), err.error_args[0])
2894
2813
    elif err.error_verb == 'nosuchrevision':
2895
2814
        raise NoSuchRevision(find('repository'), err.error_args[0])
2896
 
    elif err.error_verb == 'nobranch':
2897
 
        if len(err.error_args) >= 1:
2898
 
            extra = err.error_args[0]
2899
 
        else:
2900
 
            extra = None
2901
 
        raise errors.NotBranchError(path=find('bzrdir').root_transport.base,
2902
 
            detail=extra)
 
2815
    elif err.error_tuple == ('nobranch',):
 
2816
        raise errors.NotBranchError(path=find('bzrdir').root_transport.base)
2903
2817
    elif err.error_verb == 'norepository':
2904
2818
        raise errors.NoRepositoryPresent(find('bzrdir'))
2905
2819
    elif err.error_verb == 'LockContention':