/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: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2011 Canonical Ltd
 
1
# Copyright (C) 2006-2010 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,
33
32
    revision as _mod_revision,
34
33
    static_tuple,
35
34
    symbol_versioning,
36
 
    urlutils,
37
35
)
38
 
from bzrlib.branch import BranchReferenceFormat, BranchWriteLockResult
 
36
from bzrlib.branch import BranchReferenceFormat
39
37
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
40
38
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
41
39
from bzrlib.errors import (
45
43
from bzrlib.lockable_files import LockableFiles
46
44
from bzrlib.smart import client, vfs, repository as smart_repo
47
45
from bzrlib.revision import ensure_null, NULL_REVISION
48
 
from bzrlib.repository import RepositoryWriteLockResult
49
46
from bzrlib.trace import mutter, note, warning
50
47
 
51
48
 
215
212
        if len(branch_info) != 2:
216
213
            raise errors.UnexpectedSmartServerResponse(response)
217
214
        branch_ref, branch_name = branch_info
218
 
        format = controldir.network_format_registry.get(control_name)
 
215
        format = bzrdir.network_format_registry.get(control_name)
219
216
        if repo_name:
220
217
            format.repository_format = repository.network_format_registry.get(
221
218
                repo_name)
247
244
        self._ensure_real()
248
245
        self._real_bzrdir.destroy_repository()
249
246
 
250
 
    def create_branch(self, name=None, repository=None):
 
247
    def create_branch(self, name=None):
251
248
        # as per meta1 formats - just delegate to the format object which may
252
249
        # be parameterised.
253
250
        real_branch = self._format.get_branch_format().initialize(self,
254
 
            name=name, repository=repository)
 
251
            name=name)
255
252
        if not isinstance(real_branch, RemoteBranch):
256
 
            if not isinstance(repository, RemoteRepository):
257
 
                raise AssertionError(
258
 
                    'need a RemoteRepository to use with RemoteBranch, got %r'
259
 
                    % (repository,))
260
 
            result = RemoteBranch(self, repository, real_branch, name=name)
 
253
            result = RemoteBranch(self, self.find_repository(), real_branch,
 
254
                                  name=name)
261
255
        else:
262
256
            result = real_branch
263
257
        # BzrDir.clone_on_transport() uses the result of create_branch but does
275
269
        self._real_bzrdir.destroy_branch(name=name)
276
270
        self._next_open_branch_result = None
277
271
 
278
 
    def create_workingtree(self, revision_id=None, from_branch=None,
279
 
        accelerator_tree=None, hardlink=False):
 
272
    def create_workingtree(self, revision_id=None, from_branch=None):
280
273
        raise errors.NotLocalUrl(self.transport.base)
281
274
 
282
 
    def find_branch_format(self, name=None):
 
275
    def find_branch_format(self):
283
276
        """Find the branch 'format' for this bzrdir.
284
277
 
285
278
        This might be a synthetic object for e.g. RemoteBranch and SVN.
286
279
        """
287
 
        b = self.open_branch(name=name)
 
280
        b = self.open_branch()
288
281
        return b._format
289
282
 
290
 
    def get_branch_reference(self, name=None):
 
283
    def get_branch_reference(self):
291
284
        """See BzrDir.get_branch_reference()."""
292
 
        if name is not None:
293
 
            # XXX JRV20100304: Support opening colocated branches
294
 
            raise errors.NoColocatedBranchSupport(self)
295
285
        response = self._get_branch_reference()
296
286
        if response[0] == 'ref':
297
287
            return response[1]
328
318
            raise errors.UnexpectedSmartServerResponse(response)
329
319
        return response
330
320
 
331
 
    def _get_tree_branch(self, name=None):
 
321
    def _get_tree_branch(self):
332
322
        """See BzrDir._get_tree_branch()."""
333
 
        return None, self.open_branch(name=name)
 
323
        return None, self.open_branch()
334
324
 
335
325
    def open_branch(self, name=None, unsupported=False,
336
326
                    ignore_fallbacks=False):
654
644
 
655
645
 
656
646
class RemoteRepository(_RpcHelper, lock._RelockDebugMixin,
657
 
    controldir.ControlComponent):
 
647
    bzrdir.ControlComponent):
658
648
    """Repository accessed over rpc.
659
649
 
660
650
    For the moment most operations are performed using local transport-backed
905
895
    def _has_same_fallbacks(self, other_repo):
906
896
        """Returns true if the repositories have the same fallbacks."""
907
897
        # XXX: copied from Repository; it should be unified into a base class
908
 
        # <https://bugs.launchpad.net/bzr/+bug/401622>
 
898
        # <https://bugs.edge.launchpad.net/bzr/+bug/401622>
909
899
        my_fb = self._fallback_repositories
910
900
        other_fb = other_repo._fallback_repositories
911
901
        if len(my_fb) != len(other_fb):
1007
997
        pass
1008
998
 
1009
999
    def lock_read(self):
1010
 
        """Lock the repository for read operations.
1011
 
 
1012
 
        :return: A bzrlib.lock.LogicalLockResult.
1013
 
        """
1014
1000
        # wrong eventually - want a local lock cache context
1015
1001
        if not self._lock_mode:
1016
1002
            self._note_lock('r')
1023
1009
                repo.lock_read()
1024
1010
        else:
1025
1011
            self._lock_count += 1
1026
 
        return lock.LogicalLockResult(self.unlock)
1027
1012
 
1028
1013
    def _remote_lock_write(self, token):
1029
1014
        path = self.bzrdir._path_for_remote_call(self._client)
1069
1054
            raise errors.ReadOnlyError(self)
1070
1055
        else:
1071
1056
            self._lock_count += 1
1072
 
        return RepositoryWriteLockResult(self.unlock, self._lock_token or None)
 
1057
        return self._lock_token or None
1073
1058
 
1074
1059
    def leave_lock_in_place(self):
1075
1060
        if not self._lock_token:
1321
1306
        return self._real_repository.make_working_trees()
1322
1307
 
1323
1308
    def refresh_data(self):
1324
 
        """Re-read any data needed to synchronise with disk.
 
1309
        """Re-read any data needed to to synchronise with disk.
1325
1310
 
1326
1311
        This method is intended to be called after another repository instance
1327
1312
        (such as one used by a smart server) has inserted data into the
1328
 
        repository. On all repositories this will work outside of write groups.
1329
 
        Some repository formats (pack and newer for bzrlib native formats)
1330
 
        support refresh_data inside write groups. If called inside a write
1331
 
        group on a repository that does not support refreshing in a write group
1332
 
        IsInWriteGroupError will be raised.
 
1313
        repository. It may not be called during a write group, but may be
 
1314
        called at any other time.
1333
1315
        """
 
1316
        if self.is_in_write_group():
 
1317
            raise errors.InternalBzrError(
 
1318
                "May not refresh_data while in a write group.")
1334
1319
        if self._real_repository is not None:
1335
1320
            self._real_repository.refresh_data()
1336
1321
 
1348
1333
        return result
1349
1334
 
1350
1335
    @needs_read_lock
1351
 
    def search_missing_revision_ids(self, other,
1352
 
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
1353
 
            find_ghosts=True, revision_ids=None, if_present_ids=None):
 
1336
    def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
1354
1337
        """Return the revision ids that other has that this does not.
1355
1338
 
1356
1339
        These are returned in topological order.
1357
1340
 
1358
1341
        revision_id: only return revision ids included by revision_id.
1359
1342
        """
1360
 
        if symbol_versioning.deprecated_passed(revision_id):
1361
 
            symbol_versioning.warn(
1362
 
                'search_missing_revision_ids(revision_id=...) was '
1363
 
                'deprecated in 2.4.  Use revision_ids=[...] instead.',
1364
 
                DeprecationWarning, stacklevel=2)
1365
 
            if revision_ids is not None:
1366
 
                raise AssertionError(
1367
 
                    'revision_ids is mutually exclusive with revision_id')
1368
 
            if revision_id is not None:
1369
 
                revision_ids = [revision_id]
1370
 
        inter_repo = repository.InterRepository.get(other, self)
1371
 
        return inter_repo.search_missing_revision_ids(
1372
 
            find_ghosts=find_ghosts, revision_ids=revision_ids,
1373
 
            if_present_ids=if_present_ids)
 
1343
        return repository.InterRepository.get(
 
1344
            other, self).search_missing_revision_ids(revision_id, find_ghosts)
1374
1345
 
1375
1346
    def fetch(self, source, revision_id=None, pb=None, find_ghosts=False,
1376
1347
            fetch_spec=None):
1777
1748
        return '\n'.join((start_keys, stop_keys, count))
1778
1749
 
1779
1750
    def _serialise_search_result(self, search_result):
1780
 
        parts = search_result.get_network_struct()
 
1751
        if isinstance(search_result, graph.PendingAncestryResult):
 
1752
            parts = ['ancestry-of']
 
1753
            parts.extend(search_result.heads)
 
1754
        else:
 
1755
            recipe = search_result.get_recipe()
 
1756
            parts = [recipe[0], self._serialise_search_recipe(recipe)]
1781
1757
        return '\n'.join(parts)
1782
1758
 
1783
1759
    def autopack(self):
1977
1953
        candidate_verbs = [
1978
1954
            ('Repository.get_stream_1.19', (1, 19)),
1979
1955
            ('Repository.get_stream', (1, 13))]
1980
 
 
1981
1956
        found_verb = False
1982
1957
        for verb, version in candidate_verbs:
1983
1958
            if medium._is_remote_before(version):
1987
1962
                    verb, args, search_bytes)
1988
1963
            except errors.UnknownSmartMethod:
1989
1964
                medium._remember_remote_is_before(version)
1990
 
            except errors.UnknownErrorFromSmartServer, e:
1991
 
                if isinstance(search, graph.EverythingResult):
1992
 
                    error_verb = e.error_from_smart_server.error_verb
1993
 
                    if error_verb == 'BadSearch':
1994
 
                        # Pre-2.4 servers don't support this sort of search.
1995
 
                        # XXX: perhaps falling back to VFS on BadSearch is a
1996
 
                        # good idea in general?  It might provide a little bit
1997
 
                        # of protection against client-side bugs.
1998
 
                        medium._remember_remote_is_before((2, 4))
1999
 
                        break
2000
 
                raise
2001
1965
            else:
2002
1966
                response_tuple, response_handler = response
2003
1967
                found_verb = True
2007
1971
        if response_tuple[0] != 'ok':
2008
1972
            raise errors.UnexpectedSmartServerResponse(response_tuple)
2009
1973
        byte_stream = response_handler.read_streamed_body()
2010
 
        src_format, stream = smart_repo._byte_stream_to_stream(byte_stream,
2011
 
            self._record_counter)
 
1974
        src_format, stream = smart_repo._byte_stream_to_stream(byte_stream)
2012
1975
        if src_format.network_name() != repo._format.network_name():
2013
1976
            raise AssertionError(
2014
1977
                "Mismatched RemoteRepository and stream src %r, %r" % (
2118
2081
                                  name=name)
2119
2082
        return result
2120
2083
 
2121
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2084
    def initialize(self, a_bzrdir, name=None):
2122
2085
        # 1) get the network name to use.
2123
2086
        if self._custom_format:
2124
2087
            network_name = self._custom_format.network_name()
2152
2115
        # Turn the response into a RemoteRepository object.
2153
2116
        format = RemoteBranchFormat(network_name=response[1])
2154
2117
        repo_format = response_tuple_to_repo_format(response[3:])
2155
 
        repo_path = response[2]
2156
 
        if repository is not None:
2157
 
            remote_repo_url = urlutils.join(medium.base, repo_path)
2158
 
            url_diff = urlutils.relative_url(repository.user_url,
2159
 
                    remote_repo_url)
2160
 
            if url_diff != '.':
2161
 
                raise AssertionError(
2162
 
                    'repository.user_url %r does not match URL from server '
2163
 
                    'response (%r + %r)'
2164
 
                    % (repository.user_url, medium.base, repo_path))
2165
 
            remote_repo = repository
 
2118
        if response[2] == '':
 
2119
            repo_bzrdir = a_bzrdir
2166
2120
        else:
2167
 
            if repo_path == '':
2168
 
                repo_bzrdir = a_bzrdir
2169
 
            else:
2170
 
                repo_bzrdir = RemoteBzrDir(
2171
 
                    a_bzrdir.root_transport.clone(repo_path), a_bzrdir._format,
2172
 
                    a_bzrdir._client)
2173
 
            remote_repo = RemoteRepository(repo_bzrdir, repo_format)
 
2121
            repo_bzrdir = RemoteBzrDir(
 
2122
                a_bzrdir.root_transport.clone(response[2]), a_bzrdir._format,
 
2123
                a_bzrdir._client)
 
2124
        remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2174
2125
        remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2175
2126
            format=format, setup_stacking=False, name=name)
2176
2127
        # XXX: We know this is a new branch, so it must have revno 0, revid
2406
2357
        self._ensure_real()
2407
2358
        return self._real_branch._get_tags_bytes()
2408
2359
 
2409
 
    @needs_read_lock
2410
2360
    def _get_tags_bytes(self):
2411
 
        if self._tags_bytes is None:
2412
 
            self._tags_bytes = self._get_tags_bytes_via_hpss()
2413
 
        return self._tags_bytes
2414
 
 
2415
 
    def _get_tags_bytes_via_hpss(self):
2416
2361
        medium = self._client._medium
2417
2362
        if medium._is_remote_before((1, 13)):
2418
2363
            return self._vfs_get_tags_bytes()
2428
2373
        return self._real_branch._set_tags_bytes(bytes)
2429
2374
 
2430
2375
    def _set_tags_bytes(self, bytes):
2431
 
        if self.is_locked():
2432
 
            self._tags_bytes = bytes
2433
2376
        medium = self._client._medium
2434
2377
        if medium._is_remote_before((1, 18)):
2435
2378
            self._vfs_set_tags_bytes(bytes)
2444
2387
            self._vfs_set_tags_bytes(bytes)
2445
2388
 
2446
2389
    def lock_read(self):
2447
 
        """Lock the branch for read operations.
2448
 
 
2449
 
        :return: A bzrlib.lock.LogicalLockResult.
2450
 
        """
2451
2390
        self.repository.lock_read()
2452
2391
        if not self._lock_mode:
2453
2392
            self._note_lock('r')
2457
2396
                self._real_branch.lock_read()
2458
2397
        else:
2459
2398
            self._lock_count += 1
2460
 
        return lock.LogicalLockResult(self.unlock)
2461
2399
 
2462
2400
    def _remote_lock_write(self, token):
2463
2401
        if token is None:
2464
2402
            branch_token = repo_token = ''
2465
2403
        else:
2466
2404
            branch_token = token
2467
 
            repo_token = self.repository.lock_write().repository_token
 
2405
            repo_token = self.repository.lock_write()
2468
2406
            self.repository.unlock()
2469
2407
        err_context = {'token': token}
2470
 
        try:
2471
 
            response = self._call(
2472
 
                'Branch.lock_write', self._remote_path(), branch_token,
2473
 
                repo_token or '', **err_context)
2474
 
        except errors.LockContention, e:
2475
 
            # The LockContention from the server doesn't have any
2476
 
            # information about the lock_url. We re-raise LockContention
2477
 
            # with valid lock_url.
2478
 
            raise errors.LockContention('(remote lock)',
2479
 
                self.repository.base.split('.bzr/')[0])
 
2408
        response = self._call(
 
2409
            'Branch.lock_write', self._remote_path(), branch_token,
 
2410
            repo_token or '', **err_context)
2480
2411
        if response[0] != 'ok':
2481
2412
            raise errors.UnexpectedSmartServerResponse(response)
2482
2413
        ok, branch_token, repo_token = response
2503
2434
            self._lock_mode = 'w'
2504
2435
            self._lock_count = 1
2505
2436
        elif self._lock_mode == 'r':
2506
 
            raise errors.ReadOnlyError(self)
 
2437
            raise errors.ReadOnlyTransaction
2507
2438
        else:
2508
2439
            if token is not None:
2509
2440
                # A token was given to lock_write, and we're relocking, so
2514
2445
            self._lock_count += 1
2515
2446
            # Re-lock the repository too.
2516
2447
            self.repository.lock_write(self._repo_lock_token)
2517
 
        return BranchWriteLockResult(self.unlock, self._lock_token or None)
 
2448
        return self._lock_token or None
2518
2449
 
2519
2450
    def _unlock(self, branch_token, repo_token):
2520
2451
        err_context = {'token': str((branch_token, repo_token))}
2843
2774
        medium = self._branch._client._medium
2844
2775
        if medium._is_remote_before((1, 14)):
2845
2776
            return self._vfs_set_option(value, name, section)
2846
 
        if isinstance(value, dict):
2847
 
            if medium._is_remote_before((2, 2)):
2848
 
                return self._vfs_set_option(value, name, section)
2849
 
            return self._set_config_option_dict(value, name, section)
2850
 
        else:
2851
 
            return self._set_config_option(value, name, section)
2852
 
 
2853
 
    def _set_config_option(self, value, name, section):
2854
2777
        try:
2855
2778
            path = self._branch._remote_path()
2856
2779
            response = self._branch._client.call('Branch.set_config_option',
2857
2780
                path, self._branch._lock_token, self._branch._repo_lock_token,
2858
2781
                value.encode('utf8'), name, section or '')
2859
2782
        except errors.UnknownSmartMethod:
2860
 
            medium = self._branch._client._medium
2861
2783
            medium._remember_remote_is_before((1, 14))
2862
2784
            return self._vfs_set_option(value, name, section)
2863
2785
        if response != ():
2864
2786
            raise errors.UnexpectedSmartServerResponse(response)
2865
2787
 
2866
 
    def _serialize_option_dict(self, option_dict):
2867
 
        utf8_dict = {}
2868
 
        for key, value in option_dict.items():
2869
 
            if isinstance(key, unicode):
2870
 
                key = key.encode('utf8')
2871
 
            if isinstance(value, unicode):
2872
 
                value = value.encode('utf8')
2873
 
            utf8_dict[key] = value
2874
 
        return bencode.bencode(utf8_dict)
2875
 
 
2876
 
    def _set_config_option_dict(self, value, name, section):
2877
 
        try:
2878
 
            path = self._branch._remote_path()
2879
 
            serialised_dict = self._serialize_option_dict(value)
2880
 
            response = self._branch._client.call(
2881
 
                'Branch.set_config_option_dict',
2882
 
                path, self._branch._lock_token, self._branch._repo_lock_token,
2883
 
                serialised_dict, name, section or '')
2884
 
        except errors.UnknownSmartMethod:
2885
 
            medium = self._branch._client._medium
2886
 
            medium._remember_remote_is_before((2, 2))
2887
 
            return self._vfs_set_option(value, name, section)
2888
 
        if response != ():
2889
 
            raise errors.UnexpectedSmartServerResponse(response)
2890
 
 
2891
2788
    def _real_object(self):
2892
2789
        self._branch._ensure_real()
2893
2790
        return self._branch._real_branch