/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

Don't add a new verb; instead just teach the client to fallback if it gets a BadSearch error.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
    branch,
22
22
    bzrdir,
23
23
    config,
 
24
    controldir,
24
25
    debug,
25
26
    errors,
26
27
    graph,
33
34
    static_tuple,
34
35
    symbol_versioning,
35
36
)
36
 
from bzrlib.branch import BranchReferenceFormat
 
37
from bzrlib.branch import BranchReferenceFormat, BranchWriteLockResult
37
38
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
38
39
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
39
40
from bzrlib.errors import (
43
44
from bzrlib.lockable_files import LockableFiles
44
45
from bzrlib.smart import client, vfs, repository as smart_repo
45
46
from bzrlib.revision import ensure_null, NULL_REVISION
 
47
from bzrlib.repository import RepositoryWriteLockResult
46
48
from bzrlib.trace import mutter, note, warning
47
49
 
48
50
 
212
214
        if len(branch_info) != 2:
213
215
            raise errors.UnexpectedSmartServerResponse(response)
214
216
        branch_ref, branch_name = branch_info
215
 
        format = bzrdir.network_format_registry.get(control_name)
 
217
        format = controldir.network_format_registry.get(control_name)
216
218
        if repo_name:
217
219
            format.repository_format = repository.network_format_registry.get(
218
220
                repo_name)
269
271
        self._real_bzrdir.destroy_branch(name=name)
270
272
        self._next_open_branch_result = None
271
273
 
272
 
    def create_workingtree(self, revision_id=None, from_branch=None):
 
274
    def create_workingtree(self, revision_id=None, from_branch=None,
 
275
        accelerator_tree=None, hardlink=False):
273
276
        raise errors.NotLocalUrl(self.transport.base)
274
277
 
275
 
    def find_branch_format(self):
 
278
    def find_branch_format(self, name=None):
276
279
        """Find the branch 'format' for this bzrdir.
277
280
 
278
281
        This might be a synthetic object for e.g. RemoteBranch and SVN.
279
282
        """
280
 
        b = self.open_branch()
 
283
        b = self.open_branch(name=name)
281
284
        return b._format
282
285
 
283
 
    def get_branch_reference(self):
 
286
    def get_branch_reference(self, name=None):
284
287
        """See BzrDir.get_branch_reference()."""
 
288
        if name is not None:
 
289
            # XXX JRV20100304: Support opening colocated branches
 
290
            raise errors.NoColocatedBranchSupport(self)
285
291
        response = self._get_branch_reference()
286
292
        if response[0] == 'ref':
287
293
            return response[1]
318
324
            raise errors.UnexpectedSmartServerResponse(response)
319
325
        return response
320
326
 
321
 
    def _get_tree_branch(self):
 
327
    def _get_tree_branch(self, name=None):
322
328
        """See BzrDir._get_tree_branch()."""
323
 
        return None, self.open_branch()
 
329
        return None, self.open_branch(name=name)
324
330
 
325
331
    def open_branch(self, name=None, unsupported=False,
326
332
                    ignore_fallbacks=False):
644
650
 
645
651
 
646
652
class RemoteRepository(_RpcHelper, lock._RelockDebugMixin,
647
 
    bzrdir.ControlComponent):
 
653
    controldir.ControlComponent):
648
654
    """Repository accessed over rpc.
649
655
 
650
656
    For the moment most operations are performed using local transport-backed
895
901
    def _has_same_fallbacks(self, other_repo):
896
902
        """Returns true if the repositories have the same fallbacks."""
897
903
        # XXX: copied from Repository; it should be unified into a base class
898
 
        # <https://bugs.edge.launchpad.net/bzr/+bug/401622>
 
904
        # <https://bugs.launchpad.net/bzr/+bug/401622>
899
905
        my_fb = self._fallback_repositories
900
906
        other_fb = other_repo._fallback_repositories
901
907
        if len(my_fb) != len(other_fb):
997
1003
        pass
998
1004
 
999
1005
    def lock_read(self):
 
1006
        """Lock the repository for read operations.
 
1007
 
 
1008
        :return: A bzrlib.lock.LogicalLockResult.
 
1009
        """
1000
1010
        # wrong eventually - want a local lock cache context
1001
1011
        if not self._lock_mode:
1002
1012
            self._note_lock('r')
1009
1019
                repo.lock_read()
1010
1020
        else:
1011
1021
            self._lock_count += 1
 
1022
        return lock.LogicalLockResult(self.unlock)
1012
1023
 
1013
1024
    def _remote_lock_write(self, token):
1014
1025
        path = self.bzrdir._path_for_remote_call(self._client)
1054
1065
            raise errors.ReadOnlyError(self)
1055
1066
        else:
1056
1067
            self._lock_count += 1
1057
 
        return self._lock_token or None
 
1068
        return RepositoryWriteLockResult(self.unlock, self._lock_token or None)
1058
1069
 
1059
1070
    def leave_lock_in_place(self):
1060
1071
        if not self._lock_token:
1306
1317
        return self._real_repository.make_working_trees()
1307
1318
 
1308
1319
    def refresh_data(self):
1309
 
        """Re-read any data needed to to synchronise with disk.
 
1320
        """Re-read any data needed to synchronise with disk.
1310
1321
 
1311
1322
        This method is intended to be called after another repository instance
1312
1323
        (such as one used by a smart server) has inserted data into the
1313
 
        repository. It may not be called during a write group, but may be
1314
 
        called at any other time.
 
1324
        repository. On all repositories this will work outside of write groups.
 
1325
        Some repository formats (pack and newer for bzrlib native formats)
 
1326
        support refresh_data inside write groups. If called inside a write
 
1327
        group on a repository that does not support refreshing in a write group
 
1328
        IsInWriteGroupError will be raised.
1315
1329
        """
1316
 
        if self.is_in_write_group():
1317
 
            raise errors.InternalBzrError(
1318
 
                "May not refresh_data while in a write group.")
1319
1330
        if self._real_repository is not None:
1320
1331
            self._real_repository.refresh_data()
1321
1332
 
1333
1344
        return result
1334
1345
 
1335
1346
    @needs_read_lock
1336
 
    def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
 
1347
    def search_missing_revision_ids(self, other,
 
1348
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
 
1349
            find_ghosts=True, revision_ids=None):
1337
1350
        """Return the revision ids that other has that this does not.
1338
1351
 
1339
1352
        These are returned in topological order.
1340
1353
 
1341
1354
        revision_id: only return revision ids included by revision_id.
1342
1355
        """
1343
 
        return repository.InterRepository.get(
1344
 
            other, self).search_missing_revision_ids(revision_id, find_ghosts)
 
1356
        if symbol_versioning.deprecated_passed(revision_id):
 
1357
            symbol_versioning.warn(
 
1358
                'search_missing_revision_ids(revision_id=...) was '
 
1359
                'deprecated in 2.3.  Use revision_ids=[...] instead.',
 
1360
                DeprecationWarning, stacklevel=2)
 
1361
            if revision_ids is not None:
 
1362
                raise AssertionError(
 
1363
                    'revision_ids is mutually exclusive with revision_id')
 
1364
            if revision_id is not None:
 
1365
                revision_ids = [revision_id]
 
1366
        inter_repo = repository.InterRepository.get(other, self)
 
1367
        return inter_repo.search_missing_revision_ids(
 
1368
            find_ghosts=find_ghosts, revision_ids=revision_ids)
1345
1369
 
1346
1370
    def fetch(self, source, revision_id=None, pb=None, find_ghosts=False,
1347
1371
            fetch_spec=None):
1748
1772
        return '\n'.join((start_keys, stop_keys, count))
1749
1773
 
1750
1774
    def _serialise_search_result(self, search_result):
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)]
 
1775
        parts = search_result.get_network_struct()
1757
1776
        return '\n'.join(parts)
1758
1777
 
1759
1778
    def autopack(self):
1953
1972
        candidate_verbs = [
1954
1973
            ('Repository.get_stream_1.19', (1, 19)),
1955
1974
            ('Repository.get_stream', (1, 13))]
 
1975
 
1956
1976
        found_verb = False
1957
1977
        for verb, version in candidate_verbs:
1958
1978
            if medium._is_remote_before(version):
1962
1982
                    verb, args, search_bytes)
1963
1983
            except errors.UnknownSmartMethod:
1964
1984
                medium._remember_remote_is_before(version)
 
1985
            except errors.UnknownErrorFromSmartServer, e:
 
1986
                if isinstance(search, graph.EverythingResult):
 
1987
                    error_verb = e.error_from_smart_server.error_verb
 
1988
                    if error_verb == 'BadSearch':
 
1989
                        # Pre-2.3 servers don't support this sort of search.
 
1990
                        # XXX: perhaps falling back to VFS on BadSearch is a
 
1991
                        # good idea in general?  It might provide a little bit
 
1992
                        # of protection against client-side bugs.
 
1993
                        medium._remember_remote_is_before((2, 3))
 
1994
                        break
 
1995
                raise
1965
1996
            else:
1966
1997
                response_tuple, response_handler = response
1967
1998
                found_verb = True
1971
2002
        if response_tuple[0] != 'ok':
1972
2003
            raise errors.UnexpectedSmartServerResponse(response_tuple)
1973
2004
        byte_stream = response_handler.read_streamed_body()
1974
 
        src_format, stream = smart_repo._byte_stream_to_stream(byte_stream)
 
2005
        src_format, stream = smart_repo._byte_stream_to_stream(byte_stream,
 
2006
            self._record_counter)
1975
2007
        if src_format.network_name() != repo._format.network_name():
1976
2008
            raise AssertionError(
1977
2009
                "Mismatched RemoteRepository and stream src %r, %r" % (
2357
2389
        self._ensure_real()
2358
2390
        return self._real_branch._get_tags_bytes()
2359
2391
 
 
2392
    @needs_read_lock
2360
2393
    def _get_tags_bytes(self):
 
2394
        if self._tags_bytes is None:
 
2395
            self._tags_bytes = self._get_tags_bytes_via_hpss()
 
2396
        return self._tags_bytes
 
2397
 
 
2398
    def _get_tags_bytes_via_hpss(self):
2361
2399
        medium = self._client._medium
2362
2400
        if medium._is_remote_before((1, 13)):
2363
2401
            return self._vfs_get_tags_bytes()
2373
2411
        return self._real_branch._set_tags_bytes(bytes)
2374
2412
 
2375
2413
    def _set_tags_bytes(self, bytes):
 
2414
        if self.is_locked():
 
2415
            self._tags_bytes = bytes
2376
2416
        medium = self._client._medium
2377
2417
        if medium._is_remote_before((1, 18)):
2378
2418
            self._vfs_set_tags_bytes(bytes)
2387
2427
            self._vfs_set_tags_bytes(bytes)
2388
2428
 
2389
2429
    def lock_read(self):
 
2430
        """Lock the branch for read operations.
 
2431
 
 
2432
        :return: A bzrlib.lock.LogicalLockResult.
 
2433
        """
2390
2434
        self.repository.lock_read()
2391
2435
        if not self._lock_mode:
2392
2436
            self._note_lock('r')
2396
2440
                self._real_branch.lock_read()
2397
2441
        else:
2398
2442
            self._lock_count += 1
 
2443
        return lock.LogicalLockResult(self.unlock)
2399
2444
 
2400
2445
    def _remote_lock_write(self, token):
2401
2446
        if token is None:
2402
2447
            branch_token = repo_token = ''
2403
2448
        else:
2404
2449
            branch_token = token
2405
 
            repo_token = self.repository.lock_write()
 
2450
            repo_token = self.repository.lock_write().repository_token
2406
2451
            self.repository.unlock()
2407
2452
        err_context = {'token': token}
2408
 
        response = self._call(
2409
 
            'Branch.lock_write', self._remote_path(), branch_token,
2410
 
            repo_token or '', **err_context)
 
2453
        try:
 
2454
            response = self._call(
 
2455
                'Branch.lock_write', self._remote_path(), branch_token,
 
2456
                repo_token or '', **err_context)
 
2457
        except errors.LockContention, e:
 
2458
            # The LockContention from the server doesn't have any
 
2459
            # information about the lock_url. We re-raise LockContention
 
2460
            # with valid lock_url.
 
2461
            raise errors.LockContention('(remote lock)',
 
2462
                self.repository.base.split('.bzr/')[0])
2411
2463
        if response[0] != 'ok':
2412
2464
            raise errors.UnexpectedSmartServerResponse(response)
2413
2465
        ok, branch_token, repo_token = response
2434
2486
            self._lock_mode = 'w'
2435
2487
            self._lock_count = 1
2436
2488
        elif self._lock_mode == 'r':
2437
 
            raise errors.ReadOnlyTransaction
 
2489
            raise errors.ReadOnlyError(self)
2438
2490
        else:
2439
2491
            if token is not None:
2440
2492
                # A token was given to lock_write, and we're relocking, so
2445
2497
            self._lock_count += 1
2446
2498
            # Re-lock the repository too.
2447
2499
            self.repository.lock_write(self._repo_lock_token)
2448
 
        return self._lock_token or None
 
2500
        return BranchWriteLockResult(self.unlock, self._lock_token or None)
2449
2501
 
2450
2502
    def _unlock(self, branch_token, repo_token):
2451
2503
        err_context = {'token': str((branch_token, repo_token))}
2774
2826
        medium = self._branch._client._medium
2775
2827
        if medium._is_remote_before((1, 14)):
2776
2828
            return self._vfs_set_option(value, name, section)
 
2829
        if isinstance(value, dict):
 
2830
            if medium._is_remote_before((2, 2)):
 
2831
                return self._vfs_set_option(value, name, section)
 
2832
            return self._set_config_option_dict(value, name, section)
 
2833
        else:
 
2834
            return self._set_config_option(value, name, section)
 
2835
 
 
2836
    def _set_config_option(self, value, name, section):
2777
2837
        try:
2778
2838
            path = self._branch._remote_path()
2779
2839
            response = self._branch._client.call('Branch.set_config_option',
2780
2840
                path, self._branch._lock_token, self._branch._repo_lock_token,
2781
2841
                value.encode('utf8'), name, section or '')
2782
2842
        except errors.UnknownSmartMethod:
 
2843
            medium = self._branch._client._medium
2783
2844
            medium._remember_remote_is_before((1, 14))
2784
2845
            return self._vfs_set_option(value, name, section)
2785
2846
        if response != ():
2786
2847
            raise errors.UnexpectedSmartServerResponse(response)
2787
2848
 
 
2849
    def _serialize_option_dict(self, option_dict):
 
2850
        utf8_dict = {}
 
2851
        for key, value in option_dict.items():
 
2852
            if isinstance(key, unicode):
 
2853
                key = key.encode('utf8')
 
2854
            if isinstance(value, unicode):
 
2855
                value = value.encode('utf8')
 
2856
            utf8_dict[key] = value
 
2857
        return bencode.bencode(utf8_dict)
 
2858
 
 
2859
    def _set_config_option_dict(self, value, name, section):
 
2860
        try:
 
2861
            path = self._branch._remote_path()
 
2862
            serialised_dict = self._serialize_option_dict(value)
 
2863
            response = self._branch._client.call(
 
2864
                'Branch.set_config_option_dict',
 
2865
                path, self._branch._lock_token, self._branch._repo_lock_token,
 
2866
                serialised_dict, name, section or '')
 
2867
        except errors.UnknownSmartMethod:
 
2868
            medium = self._branch._client._medium
 
2869
            medium._remember_remote_is_before((2, 2))
 
2870
            return self._vfs_set_option(value, name, section)
 
2871
        if response != ():
 
2872
            raise errors.UnexpectedSmartServerResponse(response)
 
2873
 
2788
2874
    def _real_object(self):
2789
2875
        self._branch._ensure_real()
2790
2876
        return self._branch._real_branch