~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

  • Committer: Robert Collins
  • Date: 2010-04-08 04:34:03 UTC
  • mfrom: (5138 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5139.
  • Revision ID: robertc@robertcollins.net-20100408043403-56z0d07vdqrx7f3t
Update bugfix for 528114 to trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
273
270
    def create_workingtree(self, revision_id=None, from_branch=None):
274
271
        raise errors.NotLocalUrl(self.transport.base)
275
272
 
276
 
    def find_branch_format(self, name=None):
 
273
    def find_branch_format(self):
277
274
        """Find the branch 'format' for this bzrdir.
278
275
 
279
276
        This might be a synthetic object for e.g. RemoteBranch and SVN.
280
277
        """
281
 
        b = self.open_branch(name=name)
 
278
        b = self.open_branch()
282
279
        return b._format
283
280
 
284
 
    def get_branch_reference(self, name=None):
 
281
    def get_branch_reference(self):
285
282
        """See BzrDir.get_branch_reference()."""
286
 
        if name is not None:
287
 
            # XXX JRV20100304: Support opening colocated branches
288
 
            raise errors.NoColocatedBranchSupport(self)
289
283
        response = self._get_branch_reference()
290
284
        if response[0] == 'ref':
291
285
            return response[1]
322
316
            raise errors.UnexpectedSmartServerResponse(response)
323
317
        return response
324
318
 
325
 
    def _get_tree_branch(self, name=None):
 
319
    def _get_tree_branch(self):
326
320
        """See BzrDir._get_tree_branch()."""
327
 
        return None, self.open_branch(name=name)
 
321
        return None, self.open_branch()
328
322
 
329
323
    def open_branch(self, name=None, unsupported=False,
330
324
                    ignore_fallbacks=False):
647
641
        return self._custom_format._serializer
648
642
 
649
643
 
650
 
class RemoteRepository(_RpcHelper, lock._RelockDebugMixin,
651
 
    bzrdir.ControlComponent):
 
644
class RemoteRepository(_RpcHelper, lock._RelockDebugMixin):
652
645
    """Repository accessed over rpc.
653
646
 
654
647
    For the moment most operations are performed using local transport-backed
697
690
        # Additional places to query for data.
698
691
        self._fallback_repositories = []
699
692
 
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
693
    def __str__(self):
712
694
        return "%s(%s)" % (self.__class__.__name__, self.base)
713
695
 
899
881
    def _has_same_fallbacks(self, other_repo):
900
882
        """Returns true if the repositories have the same fallbacks."""
901
883
        # XXX: copied from Repository; it should be unified into a base class
902
 
        # <https://bugs.launchpad.net/bzr/+bug/401622>
 
884
        # <https://bugs.edge.launchpad.net/bzr/+bug/401622>
903
885
        my_fb = self._fallback_repositories
904
886
        other_fb = other_repo._fallback_repositories
905
887
        if len(my_fb) != len(other_fb):
921
903
        parents_provider = self._make_parents_provider(other_repository)
922
904
        return graph.Graph(parents_provider)
923
905
 
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
906
    def gather_stats(self, revid=None, committers=None):
934
907
        """See Repository.gather_stats()."""
935
908
        path = self.bzrdir._path_for_remote_call(self._client)
1001
974
        pass
1002
975
 
1003
976
    def lock_read(self):
1004
 
        """Lock the repository for read operations.
1005
 
 
1006
 
        :return: A bzrlib.lock.LogicalLockResult.
1007
 
        """
1008
977
        # wrong eventually - want a local lock cache context
1009
978
        if not self._lock_mode:
1010
979
            self._note_lock('r')
1017
986
                repo.lock_read()
1018
987
        else:
1019
988
            self._lock_count += 1
1020
 
        return lock.LogicalLockResult(self.unlock)
1021
989
 
1022
990
    def _remote_lock_write(self, token):
1023
991
        path = self.bzrdir._path_for_remote_call(self._client)
1063
1031
            raise errors.ReadOnlyError(self)
1064
1032
        else:
1065
1033
            self._lock_count += 1
1066
 
        return RepositoryWriteLockResult(self.unlock, self._lock_token or None)
 
1034
        return self._lock_token or None
1067
1035
 
1068
1036
    def leave_lock_in_place(self):
1069
1037
        if not self._lock_token:
1249
1217
            # state, so always add a lock here. If a caller passes us a locked
1250
1218
            # repository, they are responsible for unlocking it later.
1251
1219
            repository.lock_read()
1252
 
        self._check_fallback_repository(repository)
1253
1220
        self._fallback_repositories.append(repository)
1254
1221
        # If self._real_repository was parameterised already (e.g. because a
1255
1222
        # _real_branch had its get_stacked_on_url method called), then the
1256
1223
        # repository to be added may already be in the _real_repositories list.
1257
1224
        if self._real_repository is not None:
1258
 
            fallback_locations = [repo.user_url for repo in
 
1225
            fallback_locations = [repo.bzrdir.root_transport.base for repo in
1259
1226
                self._real_repository._fallback_repositories]
1260
 
            if repository.user_url not in fallback_locations:
 
1227
            if repository.bzrdir.root_transport.base not in fallback_locations:
1261
1228
                self._real_repository.add_fallback_repository(repository)
1262
1229
 
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
1230
    def add_inventory(self, revid, inv, parents):
1274
1231
        self._ensure_real()
1275
1232
        return self._real_repository.add_inventory(revid, inv, parents)
1315
1272
        return self._real_repository.make_working_trees()
1316
1273
 
1317
1274
    def refresh_data(self):
1318
 
        """Re-read any data needed to synchronise with disk.
 
1275
        """Re-read any data needed to to synchronise with disk.
1319
1276
 
1320
1277
        This method is intended to be called after another repository instance
1321
1278
        (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.
 
1279
        repository. It may not be called during a write group, but may be
 
1280
        called at any other time.
1327
1281
        """
 
1282
        if self.is_in_write_group():
 
1283
            raise errors.InternalBzrError(
 
1284
                "May not refresh_data while in a write group.")
1328
1285
        if self._real_repository is not None:
1329
1286
            self._real_repository.refresh_data()
1330
1287
 
1628
1585
        return self._real_repository.inventories
1629
1586
 
1630
1587
    @needs_write_lock
1631
 
    def pack(self, hint=None, clean_obsolete_packs=False):
 
1588
    def pack(self, hint=None):
1632
1589
        """Compress the data within the repository.
1633
1590
 
1634
1591
        This is not currently implemented within the smart server.
1635
1592
        """
1636
1593
        self._ensure_real()
1637
 
        return self._real_repository.pack(hint=hint, clean_obsolete_packs=clean_obsolete_packs)
 
1594
        return self._real_repository.pack(hint=hint)
1638
1595
 
1639
1596
    @property
1640
1597
    def revisions(self):
1980
1937
        if response_tuple[0] != 'ok':
1981
1938
            raise errors.UnexpectedSmartServerResponse(response_tuple)
1982
1939
        byte_stream = response_handler.read_streamed_body()
1983
 
        src_format, stream = smart_repo._byte_stream_to_stream(byte_stream,
1984
 
            self._record_counter)
 
1940
        src_format, stream = smart_repo._byte_stream_to_stream(byte_stream)
1985
1941
        if src_format.network_name() != repo._format.network_name():
1986
1942
            raise AssertionError(
1987
1943
                "Mismatched RemoteRepository and stream src %r, %r" % (
2203
2159
            self._real_branch = None
2204
2160
        # Fill out expected attributes of branch for bzrlib API users.
2205
2161
        self._clear_cached_state()
2206
 
        # TODO: deprecate self.base in favor of user_url
2207
 
        self.base = self.bzrdir.user_url
 
2162
        self.base = self.bzrdir.root_transport.base
2208
2163
        self._name = name
2209
2164
        self._control_files = None
2210
2165
        self._lock_mode = None
2397
2352
            self._vfs_set_tags_bytes(bytes)
2398
2353
 
2399
2354
    def lock_read(self):
2400
 
        """Lock the branch for read operations.
2401
 
 
2402
 
        :return: A bzrlib.lock.LogicalLockResult.
2403
 
        """
2404
2355
        self.repository.lock_read()
2405
2356
        if not self._lock_mode:
2406
2357
            self._note_lock('r')
2410
2361
                self._real_branch.lock_read()
2411
2362
        else:
2412
2363
            self._lock_count += 1
2413
 
        return lock.LogicalLockResult(self.unlock)
2414
2364
 
2415
2365
    def _remote_lock_write(self, token):
2416
2366
        if token is None:
2417
2367
            branch_token = repo_token = ''
2418
2368
        else:
2419
2369
            branch_token = token
2420
 
            repo_token = self.repository.lock_write().repository_token
 
2370
            repo_token = self.repository.lock_write()
2421
2371
            self.repository.unlock()
2422
2372
        err_context = {'token': token}
2423
 
        try:
2424
 
            response = self._call(
2425
 
                'Branch.lock_write', self._remote_path(), branch_token,
2426
 
                repo_token or '', **err_context)
2427
 
        except errors.LockContention, e:
2428
 
            # The LockContention from the server doesn't have any
2429
 
            # information about the lock_url. We re-raise LockContention
2430
 
            # with valid lock_url.
2431
 
            raise errors.LockContention('(remote lock)',
2432
 
                self.repository.base.split('.bzr/')[0])
 
2373
        response = self._call(
 
2374
            'Branch.lock_write', self._remote_path(), branch_token,
 
2375
            repo_token or '', **err_context)
2433
2376
        if response[0] != 'ok':
2434
2377
            raise errors.UnexpectedSmartServerResponse(response)
2435
2378
        ok, branch_token, repo_token = response
2456
2399
            self._lock_mode = 'w'
2457
2400
            self._lock_count = 1
2458
2401
        elif self._lock_mode == 'r':
2459
 
            raise errors.ReadOnlyError(self)
 
2402
            raise errors.ReadOnlyTransaction
2460
2403
        else:
2461
2404
            if token is not None:
2462
2405
                # A token was given to lock_write, and we're relocking, so
2467
2410
            self._lock_count += 1
2468
2411
            # Re-lock the repository too.
2469
2412
            self.repository.lock_write(self._repo_lock_token)
2470
 
        return BranchWriteLockResult(self.unlock, self._lock_token or None)
 
2413
        return self._lock_token or None
2471
2414
 
2472
2415
    def _unlock(self, branch_token, repo_token):
2473
2416
        err_context = {'token': str((branch_token, repo_token))}
2796
2739
        medium = self._branch._client._medium
2797
2740
        if medium._is_remote_before((1, 14)):
2798
2741
            return self._vfs_set_option(value, name, section)
2799
 
        if isinstance(value, dict):
2800
 
            if medium._is_remote_before((2, 2)):
2801
 
                return self._vfs_set_option(value, name, section)
2802
 
            return self._set_config_option_dict(value, name, section)
2803
 
        else:
2804
 
            return self._set_config_option(value, name, section)
2805
 
 
2806
 
    def _set_config_option(self, value, name, section):
2807
2742
        try:
2808
2743
            path = self._branch._remote_path()
2809
2744
            response = self._branch._client.call('Branch.set_config_option',
2810
2745
                path, self._branch._lock_token, self._branch._repo_lock_token,
2811
2746
                value.encode('utf8'), name, section or '')
2812
2747
        except errors.UnknownSmartMethod:
2813
 
            medium = self._branch._client._medium
2814
2748
            medium._remember_remote_is_before((1, 14))
2815
2749
            return self._vfs_set_option(value, name, section)
2816
2750
        if response != ():
2817
2751
            raise errors.UnexpectedSmartServerResponse(response)
2818
2752
 
2819
 
    def _serialize_option_dict(self, option_dict):
2820
 
        utf8_dict = {}
2821
 
        for key, value in option_dict.items():
2822
 
            if isinstance(key, unicode):
2823
 
                key = key.encode('utf8')
2824
 
            if isinstance(value, unicode):
2825
 
                value = value.encode('utf8')
2826
 
            utf8_dict[key] = value
2827
 
        return bencode.bencode(utf8_dict)
2828
 
 
2829
 
    def _set_config_option_dict(self, value, name, section):
2830
 
        try:
2831
 
            path = self._branch._remote_path()
2832
 
            serialised_dict = self._serialize_option_dict(value)
2833
 
            response = self._branch._client.call(
2834
 
                'Branch.set_config_option_dict',
2835
 
                path, self._branch._lock_token, self._branch._repo_lock_token,
2836
 
                serialised_dict, name, section or '')
2837
 
        except errors.UnknownSmartMethod:
2838
 
            medium = self._branch._client._medium
2839
 
            medium._remember_remote_is_before((2, 2))
2840
 
            return self._vfs_set_option(value, name, section)
2841
 
        if response != ():
2842
 
            raise errors.UnexpectedSmartServerResponse(response)
2843
 
 
2844
2753
    def _real_object(self):
2845
2754
        self._branch._ensure_real()
2846
2755
        return self._branch._real_branch