~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-09-01 08:02:42 UTC
  • mfrom: (5390.3.3 faster-revert-593560)
  • Revision ID: pqm@pqm.ubuntu.com-20100901080242-esg62ody4frwmy66
(spiv) Avoid repeatedly calling self.target.all_file_ids() in
 InterTree.iter_changes. (Andrew Bennetts)

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
19
19
from bzrlib import (
20
20
    bencode,
21
21
    branch,
22
 
    bzrdir as _mod_bzrdir,
 
22
    bzrdir,
23
23
    config,
24
24
    controldir,
25
25
    debug,
27
27
    graph,
28
28
    lock,
29
29
    lockdir,
 
30
    repository,
30
31
    repository as _mod_repository,
 
32
    revision,
31
33
    revision as _mod_revision,
32
34
    static_tuple,
33
35
    symbol_versioning,
34
 
    urlutils,
35
36
)
36
37
from bzrlib.branch import BranchReferenceFormat, BranchWriteLockResult
 
38
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
37
39
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
38
40
from bzrlib.errors import (
39
41
    NoSuchRevision,
41
43
    )
42
44
from bzrlib.lockable_files import LockableFiles
43
45
from bzrlib.smart import client, vfs, repository as smart_repo
44
 
from bzrlib.smart.client import _SmartClient
45
 
from bzrlib.revision import NULL_REVISION
 
46
from bzrlib.revision import ensure_null, NULL_REVISION
46
47
from bzrlib.repository import RepositoryWriteLockResult
47
48
from bzrlib.trace import mutter, note, warning
48
49
 
87
88
    return format
88
89
 
89
90
 
90
 
# Note that RemoteBzrDirProber lives in bzrlib.bzrdir so bzrlib.remote
91
 
# does not have to be imported unless a remote format is involved.
92
 
 
93
 
class RemoteBzrDirFormat(_mod_bzrdir.BzrDirMetaFormat1):
94
 
    """Format representing bzrdirs accessed via a smart server"""
95
 
 
96
 
    supports_workingtrees = False
97
 
 
98
 
    def __init__(self):
99
 
        _mod_bzrdir.BzrDirMetaFormat1.__init__(self)
100
 
        # XXX: It's a bit ugly that the network name is here, because we'd
101
 
        # like to believe that format objects are stateless or at least
102
 
        # immutable,  However, we do at least avoid mutating the name after
103
 
        # it's returned.  See <https://bugs.launchpad.net/bzr/+bug/504102>
104
 
        self._network_name = None
105
 
 
106
 
    def __repr__(self):
107
 
        return "%s(_network_name=%r)" % (self.__class__.__name__,
108
 
            self._network_name)
109
 
 
110
 
    def get_format_description(self):
111
 
        if self._network_name:
112
 
            real_format = controldir.network_format_registry.get(self._network_name)
113
 
            return 'Remote: ' + real_format.get_format_description()
114
 
        return 'bzr remote bzrdir'
115
 
 
116
 
    def get_format_string(self):
117
 
        raise NotImplementedError(self.get_format_string)
118
 
 
119
 
    def network_name(self):
120
 
        if self._network_name:
121
 
            return self._network_name
122
 
        else:
123
 
            raise AssertionError("No network name set.")
124
 
 
125
 
    def initialize_on_transport(self, transport):
126
 
        try:
127
 
            # hand off the request to the smart server
128
 
            client_medium = transport.get_smart_medium()
129
 
        except errors.NoSmartMedium:
130
 
            # TODO: lookup the local format from a server hint.
131
 
            local_dir_format = _mod_bzrdir.BzrDirMetaFormat1()
132
 
            return local_dir_format.initialize_on_transport(transport)
133
 
        client = _SmartClient(client_medium)
134
 
        path = client.remote_path_from_transport(transport)
135
 
        try:
136
 
            response = client.call('BzrDirFormat.initialize', path)
137
 
        except errors.ErrorFromSmartServer, err:
138
 
            _translate_error(err, path=path)
139
 
        if response[0] != 'ok':
140
 
            raise errors.SmartProtocolError('unexpected response code %s' % (response,))
141
 
        format = RemoteBzrDirFormat()
142
 
        self._supply_sub_formats_to(format)
143
 
        return RemoteBzrDir(transport, format)
144
 
 
145
 
    def parse_NoneTrueFalse(self, arg):
146
 
        if not arg:
147
 
            return None
148
 
        if arg == 'False':
149
 
            return False
150
 
        if arg == 'True':
151
 
            return True
152
 
        raise AssertionError("invalid arg %r" % arg)
153
 
 
154
 
    def _serialize_NoneTrueFalse(self, arg):
155
 
        if arg is False:
156
 
            return 'False'
157
 
        if arg:
158
 
            return 'True'
159
 
        return ''
160
 
 
161
 
    def _serialize_NoneString(self, arg):
162
 
        return arg or ''
163
 
 
164
 
    def initialize_on_transport_ex(self, transport, use_existing_dir=False,
165
 
        create_prefix=False, force_new_repo=False, stacked_on=None,
166
 
        stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
167
 
        shared_repo=False):
168
 
        try:
169
 
            # hand off the request to the smart server
170
 
            client_medium = transport.get_smart_medium()
171
 
        except errors.NoSmartMedium:
172
 
            do_vfs = True
173
 
        else:
174
 
            # Decline to open it if the server doesn't support our required
175
 
            # version (3) so that the VFS-based transport will do it.
176
 
            if client_medium.should_probe():
177
 
                try:
178
 
                    server_version = client_medium.protocol_version()
179
 
                    if server_version != '2':
180
 
                        do_vfs = True
181
 
                    else:
182
 
                        do_vfs = False
183
 
                except errors.SmartProtocolError:
184
 
                    # Apparently there's no usable smart server there, even though
185
 
                    # the medium supports the smart protocol.
186
 
                    do_vfs = True
187
 
            else:
188
 
                do_vfs = False
189
 
        if not do_vfs:
190
 
            client = _SmartClient(client_medium)
191
 
            path = client.remote_path_from_transport(transport)
192
 
            if client_medium._is_remote_before((1, 16)):
193
 
                do_vfs = True
194
 
        if do_vfs:
195
 
            # TODO: lookup the local format from a server hint.
196
 
            local_dir_format = _mod_bzrdir.BzrDirMetaFormat1()
197
 
            self._supply_sub_formats_to(local_dir_format)
198
 
            return local_dir_format.initialize_on_transport_ex(transport,
199
 
                use_existing_dir=use_existing_dir, create_prefix=create_prefix,
200
 
                force_new_repo=force_new_repo, stacked_on=stacked_on,
201
 
                stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
202
 
                make_working_trees=make_working_trees, shared_repo=shared_repo,
203
 
                vfs_only=True)
204
 
        return self._initialize_on_transport_ex_rpc(client, path, transport,
205
 
            use_existing_dir, create_prefix, force_new_repo, stacked_on,
206
 
            stack_on_pwd, repo_format_name, make_working_trees, shared_repo)
207
 
 
208
 
    def _initialize_on_transport_ex_rpc(self, client, path, transport,
209
 
        use_existing_dir, create_prefix, force_new_repo, stacked_on,
210
 
        stack_on_pwd, repo_format_name, make_working_trees, shared_repo):
211
 
        args = []
212
 
        args.append(self._serialize_NoneTrueFalse(use_existing_dir))
213
 
        args.append(self._serialize_NoneTrueFalse(create_prefix))
214
 
        args.append(self._serialize_NoneTrueFalse(force_new_repo))
215
 
        args.append(self._serialize_NoneString(stacked_on))
216
 
        # stack_on_pwd is often/usually our transport
217
 
        if stack_on_pwd:
218
 
            try:
219
 
                stack_on_pwd = transport.relpath(stack_on_pwd)
220
 
                if not stack_on_pwd:
221
 
                    stack_on_pwd = '.'
222
 
            except errors.PathNotChild:
223
 
                pass
224
 
        args.append(self._serialize_NoneString(stack_on_pwd))
225
 
        args.append(self._serialize_NoneString(repo_format_name))
226
 
        args.append(self._serialize_NoneTrueFalse(make_working_trees))
227
 
        args.append(self._serialize_NoneTrueFalse(shared_repo))
228
 
        request_network_name = self._network_name or \
229
 
            _mod_bzrdir.BzrDirFormat.get_default_format().network_name()
230
 
        try:
231
 
            response = client.call('BzrDirFormat.initialize_ex_1.16',
232
 
                request_network_name, path, *args)
233
 
        except errors.UnknownSmartMethod:
234
 
            client._medium._remember_remote_is_before((1,16))
235
 
            local_dir_format = _mod_bzrdir.BzrDirMetaFormat1()
236
 
            self._supply_sub_formats_to(local_dir_format)
237
 
            return local_dir_format.initialize_on_transport_ex(transport,
238
 
                use_existing_dir=use_existing_dir, create_prefix=create_prefix,
239
 
                force_new_repo=force_new_repo, stacked_on=stacked_on,
240
 
                stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
241
 
                make_working_trees=make_working_trees, shared_repo=shared_repo,
242
 
                vfs_only=True)
243
 
        except errors.ErrorFromSmartServer, err:
244
 
            _translate_error(err, path=path)
245
 
        repo_path = response[0]
246
 
        bzrdir_name = response[6]
247
 
        require_stacking = response[7]
248
 
        require_stacking = self.parse_NoneTrueFalse(require_stacking)
249
 
        format = RemoteBzrDirFormat()
250
 
        format._network_name = bzrdir_name
251
 
        self._supply_sub_formats_to(format)
252
 
        bzrdir = RemoteBzrDir(transport, format, _client=client)
253
 
        if repo_path:
254
 
            repo_format = response_tuple_to_repo_format(response[1:])
255
 
            if repo_path == '.':
256
 
                repo_path = ''
257
 
            if repo_path:
258
 
                repo_bzrdir_format = RemoteBzrDirFormat()
259
 
                repo_bzrdir_format._network_name = response[5]
260
 
                repo_bzr = RemoteBzrDir(transport.clone(repo_path),
261
 
                    repo_bzrdir_format)
262
 
            else:
263
 
                repo_bzr = bzrdir
264
 
            final_stack = response[8] or None
265
 
            final_stack_pwd = response[9] or None
266
 
            if final_stack_pwd:
267
 
                final_stack_pwd = urlutils.join(
268
 
                    transport.base, final_stack_pwd)
269
 
            remote_repo = RemoteRepository(repo_bzr, repo_format)
270
 
            if len(response) > 10:
271
 
                # Updated server verb that locks remotely.
272
 
                repo_lock_token = response[10] or None
273
 
                remote_repo.lock_write(repo_lock_token, _skip_rpc=True)
274
 
                if repo_lock_token:
275
 
                    remote_repo.dont_leave_lock_in_place()
276
 
            else:
277
 
                remote_repo.lock_write()
278
 
            policy = _mod_bzrdir.UseExistingRepository(remote_repo, final_stack,
279
 
                final_stack_pwd, require_stacking)
280
 
            policy.acquire_repository()
281
 
        else:
282
 
            remote_repo = None
283
 
            policy = None
284
 
        bzrdir._format.set_branch_format(self.get_branch_format())
285
 
        if require_stacking:
286
 
            # The repo has already been created, but we need to make sure that
287
 
            # we'll make a stackable branch.
288
 
            bzrdir._format.require_stacking(_skip_repo=True)
289
 
        return remote_repo, bzrdir, require_stacking, policy
290
 
 
291
 
    def _open(self, transport):
292
 
        return RemoteBzrDir(transport, self)
293
 
 
294
 
    def __eq__(self, other):
295
 
        if not isinstance(other, RemoteBzrDirFormat):
296
 
            return False
297
 
        return self.get_format_description() == other.get_format_description()
298
 
 
299
 
    def __return_repository_format(self):
300
 
        # Always return a RemoteRepositoryFormat object, but if a specific bzr
301
 
        # repository format has been asked for, tell the RemoteRepositoryFormat
302
 
        # that it should use that for init() etc.
303
 
        result = RemoteRepositoryFormat()
304
 
        custom_format = getattr(self, '_repository_format', None)
305
 
        if custom_format:
306
 
            if isinstance(custom_format, RemoteRepositoryFormat):
307
 
                return custom_format
308
 
            else:
309
 
                # We will use the custom format to create repositories over the
310
 
                # wire; expose its details like rich_root_data for code to
311
 
                # query
312
 
                result._custom_format = custom_format
313
 
        return result
314
 
 
315
 
    def get_branch_format(self):
316
 
        result = _mod_bzrdir.BzrDirMetaFormat1.get_branch_format(self)
317
 
        if not isinstance(result, RemoteBranchFormat):
318
 
            new_result = RemoteBranchFormat()
319
 
            new_result._custom_format = result
320
 
            # cache the result
321
 
            self.set_branch_format(new_result)
322
 
            result = new_result
323
 
        return result
324
 
 
325
 
    repository_format = property(__return_repository_format,
326
 
        _mod_bzrdir.BzrDirMetaFormat1._set_repository_format) #.im_func)
327
 
 
328
 
 
329
 
class RemoteBzrDir(_mod_bzrdir.BzrDir, _RpcHelper):
 
91
# Note: RemoteBzrDirFormat is in bzrdir.py
 
92
 
 
93
class RemoteBzrDir(BzrDir, _RpcHelper):
330
94
    """Control directory on a remote server, accessed via bzr:// or similar."""
331
95
 
332
96
    def __init__(self, transport, format, _client=None, _force_probe=False):
335
99
        :param _client: Private parameter for testing. Disables probing and the
336
100
            use of a real bzrdir.
337
101
        """
338
 
        _mod_bzrdir.BzrDir.__init__(self, transport, format)
 
102
        BzrDir.__init__(self, transport, format)
339
103
        # this object holds a delegated bzrdir that uses file-level operations
340
104
        # to talk to the other side
341
105
        self._real_bzrdir = None
401
165
                import traceback
402
166
                warning('VFS BzrDir access triggered\n%s',
403
167
                    ''.join(traceback.format_stack()))
404
 
            self._real_bzrdir = _mod_bzrdir.BzrDir.open_from_transport(
 
168
            self._real_bzrdir = BzrDir.open_from_transport(
405
169
                self.root_transport, _server_formats=False)
406
170
            self._format._network_name = \
407
171
                self._real_bzrdir._format.network_name()
413
177
        # Prevent aliasing problems in the next_open_branch_result cache.
414
178
        # See create_branch for rationale.
415
179
        self._next_open_branch_result = None
416
 
        return _mod_bzrdir.BzrDir.break_lock(self)
 
180
        return BzrDir.break_lock(self)
417
181
 
418
182
    def _vfs_cloning_metadir(self, require_stacking=False):
419
183
        self._ensure_real()
450
214
        if len(branch_info) != 2:
451
215
            raise errors.UnexpectedSmartServerResponse(response)
452
216
        branch_ref, branch_name = branch_info
453
 
        format = controldir.network_format_registry.get(control_name)
 
217
        format = bzrdir.network_format_registry.get(control_name)
454
218
        if repo_name:
455
 
            format.repository_format = _mod_repository.network_format_registry.get(
 
219
            format.repository_format = repository.network_format_registry.get(
456
220
                repo_name)
457
221
        if branch_ref == 'ref':
458
222
            # XXX: we need possible_transports here to avoid reopening the
459
223
            # connection to the referenced location
460
 
            ref_bzrdir = _mod_bzrdir.BzrDir.open(branch_name)
 
224
            ref_bzrdir = BzrDir.open(branch_name)
461
225
            branch_format = ref_bzrdir.cloning_metadir().get_branch_format()
462
226
            format.set_branch_format(branch_format)
463
227
        elif branch_ref == 'branch':
482
246
        self._ensure_real()
483
247
        self._real_bzrdir.destroy_repository()
484
248
 
485
 
    def create_branch(self, name=None, repository=None):
 
249
    def create_branch(self, name=None):
486
250
        # as per meta1 formats - just delegate to the format object which may
487
251
        # be parameterised.
488
252
        real_branch = self._format.get_branch_format().initialize(self,
489
 
            name=name, repository=repository)
 
253
            name=name)
490
254
        if not isinstance(real_branch, RemoteBranch):
491
 
            if not isinstance(repository, RemoteRepository):
492
 
                raise AssertionError(
493
 
                    'need a RemoteRepository to use with RemoteBranch, got %r'
494
 
                    % (repository,))
495
 
            result = RemoteBranch(self, repository, real_branch, name=name)
 
255
            result = RemoteBranch(self, self.find_repository(), real_branch,
 
256
                                  name=name)
496
257
        else:
497
258
            result = real_branch
498
259
        # BzrDir.clone_on_transport() uses the result of create_branch but does
510
271
        self._real_bzrdir.destroy_branch(name=name)
511
272
        self._next_open_branch_result = None
512
273
 
513
 
    def create_workingtree(self, revision_id=None, from_branch=None,
514
 
        accelerator_tree=None, hardlink=False):
 
274
    def create_workingtree(self, revision_id=None, from_branch=None):
515
275
        raise errors.NotLocalUrl(self.transport.base)
516
276
 
517
277
    def find_branch_format(self, name=None):
686
446
        """Upgrading of remote bzrdirs is not supported yet."""
687
447
        return False
688
448
 
689
 
    def needs_format_conversion(self, format):
 
449
    def needs_format_conversion(self, format=None):
690
450
        """Upgrading of remote bzrdirs is not supported yet."""
 
451
        if format is None:
 
452
            symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
 
453
                % 'needs_format_conversion(format=None)')
691
454
        return False
692
455
 
693
456
    def clone(self, url, revision_id=None, force_new_repo=False,
700
463
        return RemoteBzrDirConfig(self)
701
464
 
702
465
 
703
 
class RemoteRepositoryFormat(_mod_repository.RepositoryFormat):
 
466
class RemoteRepositoryFormat(repository.RepositoryFormat):
704
467
    """Format for repositories accessed over a _SmartClient.
705
468
 
706
469
    Instances of this repository are represented by RemoteRepository
721
484
    """
722
485
 
723
486
    _matchingbzrdir = RemoteBzrDirFormat()
724
 
    supports_full_versioned_files = True
725
 
    supports_leaving_lock = True
726
487
 
727
488
    def __init__(self):
728
 
        _mod_repository.RepositoryFormat.__init__(self)
 
489
        repository.RepositoryFormat.__init__(self)
729
490
        self._custom_format = None
730
491
        self._network_name = None
731
492
        self._creating_bzrdir = None
732
493
        self._supports_chks = None
733
494
        self._supports_external_lookups = None
734
495
        self._supports_tree_reference = None
735
 
        self._supports_funky_characters = None
736
496
        self._rich_root_data = None
737
497
 
738
498
    def __repr__(self):
767
527
        return self._supports_external_lookups
768
528
 
769
529
    @property
770
 
    def supports_funky_characters(self):
771
 
        if self._supports_funky_characters is None:
772
 
            self._ensure_real()
773
 
            self._supports_funky_characters = \
774
 
                self._custom_format.supports_funky_characters
775
 
        return self._supports_funky_characters
776
 
 
777
 
    @property
778
530
    def supports_tree_reference(self):
779
531
        if self._supports_tree_reference is None:
780
532
            self._ensure_real()
822
574
            network_name = self._network_name
823
575
        else:
824
576
            # Select the current bzrlib default and ask for that.
825
 
            reference_bzrdir_format = _mod_bzrdir.format_registry.get('default')()
 
577
            reference_bzrdir_format = bzrdir.format_registry.get('default')()
826
578
            reference_format = reference_bzrdir_format.repository_format
827
579
            network_name = reference_format.network_name()
828
580
        # 2) try direct creation via RPC
854
606
 
855
607
    def _ensure_real(self):
856
608
        if self._custom_format is None:
857
 
            self._custom_format = _mod_repository.network_format_registry.get(
 
609
            self._custom_format = repository.network_format_registry.get(
858
610
                self._network_name)
859
611
 
860
612
    @property
956
708
        # transport, but I'm not sure it's worth making this method
957
709
        # optional -- mbp 2010-04-21
958
710
        return self.bzrdir.get_repository_transport(None)
959
 
 
 
711
        
960
712
    def __str__(self):
961
713
        return "%s(%s)" % (self.__class__.__name__, self.base)
962
714
 
1096
848
        """Private method for using with old (< 1.2) servers to fallback."""
1097
849
        if revision_id is None:
1098
850
            revision_id = ''
1099
 
        elif _mod_revision.is_null(revision_id):
 
851
        elif revision.is_null(revision_id):
1100
852
            return {}
1101
853
 
1102
854
        path = self.bzrdir._path_for_remote_call(self._client)
1183
935
        """See Repository.gather_stats()."""
1184
936
        path = self.bzrdir._path_for_remote_call(self._client)
1185
937
        # revid can be None to indicate no revisions, not just NULL_REVISION
1186
 
        if revid is None or _mod_revision.is_null(revid):
 
938
        if revid is None or revision.is_null(revid):
1187
939
            fmt_revid = ''
1188
940
        else:
1189
941
            fmt_revid = revid
1591
1343
        return result
1592
1344
 
1593
1345
    @needs_read_lock
1594
 
    def search_missing_revision_ids(self, other,
1595
 
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
1596
 
            find_ghosts=True, revision_ids=None, if_present_ids=None):
 
1346
    def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
1597
1347
        """Return the revision ids that other has that this does not.
1598
1348
 
1599
1349
        These are returned in topological order.
1600
1350
 
1601
1351
        revision_id: only return revision ids included by revision_id.
1602
1352
        """
1603
 
        if symbol_versioning.deprecated_passed(revision_id):
1604
 
            symbol_versioning.warn(
1605
 
                'search_missing_revision_ids(revision_id=...) was '
1606
 
                'deprecated in 2.4.  Use revision_ids=[...] instead.',
1607
 
                DeprecationWarning, stacklevel=2)
1608
 
            if revision_ids is not None:
1609
 
                raise AssertionError(
1610
 
                    'revision_ids is mutually exclusive with revision_id')
1611
 
            if revision_id is not None:
1612
 
                revision_ids = [revision_id]
1613
 
        inter_repo = _mod_repository.InterRepository.get(other, self)
1614
 
        return inter_repo.search_missing_revision_ids(
1615
 
            find_ghosts=find_ghosts, revision_ids=revision_ids,
1616
 
            if_present_ids=if_present_ids)
 
1353
        return repository.InterRepository.get(
 
1354
            other, self).search_missing_revision_ids(revision_id, find_ghosts)
1617
1355
 
1618
 
    def fetch(self, source, revision_id=None, find_ghosts=False,
 
1356
    def fetch(self, source, revision_id=None, pb=None, find_ghosts=False,
1619
1357
            fetch_spec=None):
1620
1358
        # No base implementation to use as RemoteRepository is not a subclass
1621
1359
        # of Repository; so this is a copy of Repository.fetch().
1632
1370
            # check that last_revision is in 'from' and then return a
1633
1371
            # no-operation.
1634
1372
            if (revision_id is not None and
1635
 
                not _mod_revision.is_null(revision_id)):
 
1373
                not revision.is_null(revision_id)):
1636
1374
                self.get_revision(revision_id)
1637
1375
            return 0, []
1638
1376
        # if there is no specific appropriate InterRepository, this will get
1639
1377
        # the InterRepository base class, which raises an
1640
1378
        # IncompatibleRepositories when asked to fetch.
1641
 
        inter = _mod_repository.InterRepository.get(source, self)
1642
 
        return inter.fetch(revision_id=revision_id,
 
1379
        inter = repository.InterRepository.get(source, self)
 
1380
        return inter.fetch(revision_id=revision_id, pb=pb,
1643
1381
            find_ghosts=find_ghosts, fetch_spec=fetch_spec)
1644
1382
 
1645
1383
    def create_bundle(self, target, base, fileobj, format=None):
1869
1607
            tmpdir = osutils.mkdtemp()
1870
1608
            try:
1871
1609
                _extract_tar(tar, tmpdir)
1872
 
                tmp_bzrdir = _mod_bzrdir.BzrDir.open(tmpdir)
 
1610
                tmp_bzrdir = BzrDir.open(tmpdir)
1873
1611
                tmp_repo = tmp_bzrdir.open_repository()
1874
1612
                tmp_repo.copy_content_into(destination, revision_id)
1875
1613
            finally:
2020
1758
        return '\n'.join((start_keys, stop_keys, count))
2021
1759
 
2022
1760
    def _serialise_search_result(self, search_result):
2023
 
        parts = search_result.get_network_struct()
 
1761
        if isinstance(search_result, graph.PendingAncestryResult):
 
1762
            parts = ['ancestry-of']
 
1763
            parts.extend(search_result.heads)
 
1764
        else:
 
1765
            recipe = search_result.get_recipe()
 
1766
            parts = [recipe[0], self._serialise_search_recipe(recipe)]
2024
1767
        return '\n'.join(parts)
2025
1768
 
2026
1769
    def autopack(self):
2036
1779
            raise errors.UnexpectedSmartServerResponse(response)
2037
1780
 
2038
1781
 
2039
 
class RemoteStreamSink(_mod_repository.StreamSink):
 
1782
class RemoteStreamSink(repository.StreamSink):
2040
1783
 
2041
1784
    def _insert_real(self, stream, src_format, resume_tokens):
2042
1785
        self.target_repo._ensure_real()
2143
1886
        self._last_substream and self._last_stream so that the stream can be
2144
1887
        resumed by _resume_stream_with_vfs.
2145
1888
        """
2146
 
 
 
1889
                    
2147
1890
        stream_iter = iter(stream)
2148
1891
        for substream_kind, substream in stream_iter:
2149
1892
            if substream_kind == 'inventory-deltas':
2152
1895
                return
2153
1896
            else:
2154
1897
                yield substream_kind, substream
2155
 
 
2156
 
 
2157
 
class RemoteStreamSource(_mod_repository.StreamSource):
 
1898
            
 
1899
 
 
1900
class RemoteStreamSource(repository.StreamSource):
2158
1901
    """Stream data from a remote server."""
2159
1902
 
2160
1903
    def get_stream(self, search):
2220
1963
        candidate_verbs = [
2221
1964
            ('Repository.get_stream_1.19', (1, 19)),
2222
1965
            ('Repository.get_stream', (1, 13))]
2223
 
 
2224
1966
        found_verb = False
2225
1967
        for verb, version in candidate_verbs:
2226
1968
            if medium._is_remote_before(version):
2230
1972
                    verb, args, search_bytes)
2231
1973
            except errors.UnknownSmartMethod:
2232
1974
                medium._remember_remote_is_before(version)
2233
 
            except errors.UnknownErrorFromSmartServer, e:
2234
 
                if isinstance(search, graph.EverythingResult):
2235
 
                    error_verb = e.error_from_smart_server.error_verb
2236
 
                    if error_verb == 'BadSearch':
2237
 
                        # Pre-2.4 servers don't support this sort of search.
2238
 
                        # XXX: perhaps falling back to VFS on BadSearch is a
2239
 
                        # good idea in general?  It might provide a little bit
2240
 
                        # of protection against client-side bugs.
2241
 
                        medium._remember_remote_is_before((2, 4))
2242
 
                        break
2243
 
                raise
2244
1975
            else:
2245
1976
                response_tuple, response_handler = response
2246
1977
                found_verb = True
2361
2092
                                  name=name)
2362
2093
        return result
2363
2094
 
2364
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2095
    def initialize(self, a_bzrdir, name=None):
2365
2096
        # 1) get the network name to use.
2366
2097
        if self._custom_format:
2367
2098
            network_name = self._custom_format.network_name()
2368
2099
        else:
2369
2100
            # Select the current bzrlib default and ask for that.
2370
 
            reference_bzrdir_format = _mod_bzrdir.format_registry.get('default')()
 
2101
            reference_bzrdir_format = bzrdir.format_registry.get('default')()
2371
2102
            reference_format = reference_bzrdir_format.get_branch_format()
2372
2103
            self._custom_format = reference_format
2373
2104
            network_name = reference_format.network_name()
2395
2126
        # Turn the response into a RemoteRepository object.
2396
2127
        format = RemoteBranchFormat(network_name=response[1])
2397
2128
        repo_format = response_tuple_to_repo_format(response[3:])
2398
 
        repo_path = response[2]
2399
 
        if repository is not None:
2400
 
            remote_repo_url = urlutils.join(a_bzrdir.user_url, repo_path)
2401
 
            url_diff = urlutils.relative_url(repository.user_url,
2402
 
                    remote_repo_url)
2403
 
            if url_diff != '.':
2404
 
                raise AssertionError(
2405
 
                    'repository.user_url %r does not match URL from server '
2406
 
                    'response (%r + %r)'
2407
 
                    % (repository.user_url, a_bzrdir.user_url, repo_path))
2408
 
            remote_repo = repository
 
2129
        if response[2] == '':
 
2130
            repo_bzrdir = a_bzrdir
2409
2131
        else:
2410
 
            if repo_path == '':
2411
 
                repo_bzrdir = a_bzrdir
2412
 
            else:
2413
 
                repo_bzrdir = RemoteBzrDir(
2414
 
                    a_bzrdir.root_transport.clone(repo_path), a_bzrdir._format,
2415
 
                    a_bzrdir._client)
2416
 
            remote_repo = RemoteRepository(repo_bzrdir, repo_format)
 
2132
            repo_bzrdir = RemoteBzrDir(
 
2133
                a_bzrdir.root_transport.clone(response[2]), a_bzrdir._format,
 
2134
                a_bzrdir._client)
 
2135
        remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2417
2136
        remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2418
2137
            format=format, setup_stacking=False, name=name)
2419
2138
        # XXX: We know this is a new branch, so it must have revno 0, revid
2440
2159
        self._ensure_real()
2441
2160
        return self._custom_format.supports_set_append_revisions_only()
2442
2161
 
2443
 
    def _use_default_local_heads_to_fetch(self):
2444
 
        # If the branch format is a metadir format *and* its heads_to_fetch
2445
 
        # implementation is not overridden vs the base class, we can use the
2446
 
        # base class logic rather than use the heads_to_fetch RPC.  This is
2447
 
        # usually cheaper in terms of net round trips, as the last-revision and
2448
 
        # tags info fetched is cached and would be fetched anyway.
2449
 
        self._ensure_real()
2450
 
        if isinstance(self._custom_format, branch.BranchFormatMetadir):
2451
 
            branch_class = self._custom_format._branch_class()
2452
 
            heads_to_fetch_impl = branch_class.heads_to_fetch.im_func
2453
 
            if heads_to_fetch_impl is branch.Branch.heads_to_fetch.im_func:
2454
 
                return True
2455
 
        return False
2456
2162
 
2457
2163
class RemoteBranch(branch.Branch, _RpcHelper, lock._RelockDebugMixin):
2458
2164
    """Branch stored on a server accessed by HPSS RPC.
2657
2363
            self._is_stacked = False
2658
2364
        else:
2659
2365
            self._is_stacked = True
2660
 
 
 
2366
        
2661
2367
    def _vfs_get_tags_bytes(self):
2662
2368
        self._ensure_real()
2663
2369
        return self._real_branch._get_tags_bytes()
2664
2370
 
2665
 
    @needs_read_lock
2666
2371
    def _get_tags_bytes(self):
2667
 
        if self._tags_bytes is None:
2668
 
            self._tags_bytes = self._get_tags_bytes_via_hpss()
2669
 
        return self._tags_bytes
2670
 
 
2671
 
    def _get_tags_bytes_via_hpss(self):
2672
2372
        medium = self._client._medium
2673
2373
        if medium._is_remote_before((1, 13)):
2674
2374
            return self._vfs_get_tags_bytes()
2684
2384
        return self._real_branch._set_tags_bytes(bytes)
2685
2385
 
2686
2386
    def _set_tags_bytes(self, bytes):
2687
 
        if self.is_locked():
2688
 
            self._tags_bytes = bytes
2689
2387
        medium = self._client._medium
2690
2388
        if medium._is_remote_before((1, 18)):
2691
2389
            self._vfs_set_tags_bytes(bytes)
2998
2696
        # XXX: These should be returned by the set_last_revision_info verb
2999
2697
        old_revno, old_revid = self.last_revision_info()
3000
2698
        self._run_pre_change_branch_tip_hooks(revno, revision_id)
3001
 
        revision_id = _mod_revision.ensure_null(revision_id)
 
2699
        revision_id = ensure_null(revision_id)
3002
2700
        try:
3003
2701
            response = self._call('Branch.set_last_revision_info',
3004
2702
                self._remote_path(), self._lock_token, self._repo_lock_token,
3040
2738
        self._ensure_real()
3041
2739
        return self._real_branch.set_push_location(location)
3042
2740
 
3043
 
    def heads_to_fetch(self):
3044
 
        if self._format._use_default_local_heads_to_fetch():
3045
 
            # We recognise this format, and its heads-to-fetch implementation
3046
 
            # is the default one (tip + tags).  In this case it's cheaper to
3047
 
            # just use the default implementation rather than a special RPC as
3048
 
            # the tip and tags data is cached.
3049
 
            return branch.Branch.heads_to_fetch(self)
3050
 
        medium = self._client._medium
3051
 
        if medium._is_remote_before((2, 4)):
3052
 
            return self._vfs_heads_to_fetch()
3053
 
        try:
3054
 
            return self._rpc_heads_to_fetch()
3055
 
        except errors.UnknownSmartMethod:
3056
 
            medium._remember_remote_is_before((2, 4))
3057
 
            return self._vfs_heads_to_fetch()
3058
 
 
3059
 
    def _rpc_heads_to_fetch(self):
3060
 
        response = self._call('Branch.heads_to_fetch', self._remote_path())
3061
 
        if len(response) != 2:
3062
 
            raise errors.UnexpectedSmartServerResponse(response)
3063
 
        must_fetch, if_present_fetch = response
3064
 
        return set(must_fetch), set(if_present_fetch)
3065
 
 
3066
 
    def _vfs_heads_to_fetch(self):
3067
 
        self._ensure_real()
3068
 
        return self._real_branch.heads_to_fetch()
3069
 
 
3070
2741
 
3071
2742
class RemoteConfig(object):
3072
2743
    """A Config that reads and writes from smart verbs.
3259
2930
                    'Missing key %r in context %r', key_err.args[0], context)
3260
2931
                raise err
3261
2932
 
3262
 
    if err.error_verb == 'NoSuchRevision':
 
2933
    if err.error_verb == 'IncompatibleRepositories':
 
2934
        raise errors.IncompatibleRepositories(err.error_args[0],
 
2935
            err.error_args[1], err.error_args[2])
 
2936
    elif err.error_verb == 'NoSuchRevision':
3263
2937
        raise NoSuchRevision(find('branch'), err.error_args[0])
3264
2938
    elif err.error_verb == 'nosuchrevision':
3265
2939
        raise NoSuchRevision(find('repository'), err.error_args[0])
3272
2946
            detail=extra)
3273
2947
    elif err.error_verb == 'norepository':
3274
2948
        raise errors.NoRepositoryPresent(find('bzrdir'))
 
2949
    elif err.error_verb == 'LockContention':
 
2950
        raise errors.LockContention('(remote lock)')
3275
2951
    elif err.error_verb == 'UnlockableTransport':
3276
2952
        raise errors.UnlockableTransport(find('bzrdir').root_transport)
 
2953
    elif err.error_verb == 'LockFailed':
 
2954
        raise errors.LockFailed(err.error_args[0], err.error_args[1])
3277
2955
    elif err.error_verb == 'TokenMismatch':
3278
2956
        raise errors.TokenMismatch(find('token'), '(remote token)')
3279
2957
    elif err.error_verb == 'Diverged':
3280
2958
        raise errors.DivergedBranches(find('branch'), find('other_branch'))
 
2959
    elif err.error_verb == 'TipChangeRejected':
 
2960
        raise errors.TipChangeRejected(err.error_args[0].decode('utf8'))
 
2961
    elif err.error_verb == 'UnstackableBranchFormat':
 
2962
        raise errors.UnstackableBranchFormat(*err.error_args)
 
2963
    elif err.error_verb == 'UnstackableRepositoryFormat':
 
2964
        raise errors.UnstackableRepositoryFormat(*err.error_args)
3281
2965
    elif err.error_verb == 'NotStacked':
3282
2966
        raise errors.NotStacked(branch=find('branch'))
3283
2967
    elif err.error_verb == 'PermissionDenied':
3293
2977
    elif err.error_verb == 'NoSuchFile':
3294
2978
        path = get_path()
3295
2979
        raise errors.NoSuchFile(path)
3296
 
    _translate_error_without_context(err)
3297
 
 
3298
 
 
3299
 
def _translate_error_without_context(err):
3300
 
    """Translate any ErrorFromSmartServer values that don't require context"""
3301
 
    if err.error_verb == 'IncompatibleRepositories':
3302
 
        raise errors.IncompatibleRepositories(err.error_args[0],
3303
 
            err.error_args[1], err.error_args[2])
3304
 
    elif err.error_verb == 'LockContention':
3305
 
        raise errors.LockContention('(remote lock)')
3306
 
    elif err.error_verb == 'LockFailed':
3307
 
        raise errors.LockFailed(err.error_args[0], err.error_args[1])
3308
 
    elif err.error_verb == 'TipChangeRejected':
3309
 
        raise errors.TipChangeRejected(err.error_args[0].decode('utf8'))
3310
 
    elif err.error_verb == 'UnstackableBranchFormat':
3311
 
        raise errors.UnstackableBranchFormat(*err.error_args)
3312
 
    elif err.error_verb == 'UnstackableRepositoryFormat':
3313
 
        raise errors.UnstackableRepositoryFormat(*err.error_args)
3314
2980
    elif err.error_verb == 'FileExists':
3315
2981
        raise errors.FileExists(err.error_args[0])
3316
2982
    elif err.error_verb == 'DirectoryNotEmpty':
3335
3001
            raise UnicodeEncodeError(encoding, val, start, end, reason)
3336
3002
    elif err.error_verb == 'ReadOnlyError':
3337
3003
        raise errors.TransportNotPossible('readonly transport')
3338
 
    elif err.error_verb == 'MemoryError':
3339
 
        raise errors.BzrError("remote server out of memory\n"
3340
 
            "Retry non-remotely, or contact the server admin for details.")
3341
3004
    raise errors.UnknownErrorFromSmartServer(err)