/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

Merge repository-format-deprecation branch.

Show diffs side-by-side

added added

removed removed

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