~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

(vila) Properly refuse to obey --take-this and --take-other for text
 conflicts. (Vincent Ladeuil)

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
 
    controldir,
25
24
    debug,
26
25
    errors,
27
26
    graph,
28
27
    lock,
29
28
    lockdir,
 
29
    repository,
30
30
    repository as _mod_repository,
 
31
    revision,
31
32
    revision as _mod_revision,
32
33
    static_tuple,
33
34
    symbol_versioning,
34
 
    urlutils,
35
 
    vf_repository,
36
 
    )
 
35
)
37
36
from bzrlib.branch import BranchReferenceFormat, BranchWriteLockResult
 
37
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
38
38
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
39
39
from bzrlib.errors import (
40
40
    NoSuchRevision,
42
42
    )
43
43
from bzrlib.lockable_files import LockableFiles
44
44
from bzrlib.smart import client, vfs, repository as smart_repo
45
 
from bzrlib.smart.client import _SmartClient
46
 
from bzrlib.revision import NULL_REVISION
47
 
from bzrlib.repository import RepositoryWriteLockResult, _LazyListJoin
 
45
from bzrlib.revision import ensure_null, NULL_REVISION
 
46
from bzrlib.repository import RepositoryWriteLockResult
48
47
from bzrlib.trace import mutter, note, warning
49
48
 
50
49
 
88
87
    return format
89
88
 
90
89
 
91
 
# Note that RemoteBzrDirProber lives in bzrlib.bzrdir so bzrlib.remote
92
 
# does not have to be imported unless a remote format is involved.
93
 
 
94
 
class RemoteBzrDirFormat(_mod_bzrdir.BzrDirMetaFormat1):
95
 
    """Format representing bzrdirs accessed via a smart server"""
96
 
 
97
 
    supports_workingtrees = False
98
 
 
99
 
    def __init__(self):
100
 
        _mod_bzrdir.BzrDirMetaFormat1.__init__(self)
101
 
        # XXX: It's a bit ugly that the network name is here, because we'd
102
 
        # like to believe that format objects are stateless or at least
103
 
        # immutable,  However, we do at least avoid mutating the name after
104
 
        # it's returned.  See <https://bugs.launchpad.net/bzr/+bug/504102>
105
 
        self._network_name = None
106
 
 
107
 
    def __repr__(self):
108
 
        return "%s(_network_name=%r)" % (self.__class__.__name__,
109
 
            self._network_name)
110
 
 
111
 
    def get_format_description(self):
112
 
        if self._network_name:
113
 
            real_format = controldir.network_format_registry.get(self._network_name)
114
 
            return 'Remote: ' + real_format.get_format_description()
115
 
        return 'bzr remote bzrdir'
116
 
 
117
 
    def get_format_string(self):
118
 
        raise NotImplementedError(self.get_format_string)
119
 
 
120
 
    def network_name(self):
121
 
        if self._network_name:
122
 
            return self._network_name
123
 
        else:
124
 
            raise AssertionError("No network name set.")
125
 
 
126
 
    def initialize_on_transport(self, transport):
127
 
        try:
128
 
            # hand off the request to the smart server
129
 
            client_medium = transport.get_smart_medium()
130
 
        except errors.NoSmartMedium:
131
 
            # TODO: lookup the local format from a server hint.
132
 
            local_dir_format = _mod_bzrdir.BzrDirMetaFormat1()
133
 
            return local_dir_format.initialize_on_transport(transport)
134
 
        client = _SmartClient(client_medium)
135
 
        path = client.remote_path_from_transport(transport)
136
 
        try:
137
 
            response = client.call('BzrDirFormat.initialize', path)
138
 
        except errors.ErrorFromSmartServer, err:
139
 
            _translate_error(err, path=path)
140
 
        if response[0] != 'ok':
141
 
            raise errors.SmartProtocolError('unexpected response code %s' % (response,))
142
 
        format = RemoteBzrDirFormat()
143
 
        self._supply_sub_formats_to(format)
144
 
        return RemoteBzrDir(transport, format)
145
 
 
146
 
    def parse_NoneTrueFalse(self, arg):
147
 
        if not arg:
148
 
            return None
149
 
        if arg == 'False':
150
 
            return False
151
 
        if arg == 'True':
152
 
            return True
153
 
        raise AssertionError("invalid arg %r" % arg)
154
 
 
155
 
    def _serialize_NoneTrueFalse(self, arg):
156
 
        if arg is False:
157
 
            return 'False'
158
 
        if arg:
159
 
            return 'True'
160
 
        return ''
161
 
 
162
 
    def _serialize_NoneString(self, arg):
163
 
        return arg or ''
164
 
 
165
 
    def initialize_on_transport_ex(self, transport, use_existing_dir=False,
166
 
        create_prefix=False, force_new_repo=False, stacked_on=None,
167
 
        stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
168
 
        shared_repo=False):
169
 
        try:
170
 
            # hand off the request to the smart server
171
 
            client_medium = transport.get_smart_medium()
172
 
        except errors.NoSmartMedium:
173
 
            do_vfs = True
174
 
        else:
175
 
            # Decline to open it if the server doesn't support our required
176
 
            # version (3) so that the VFS-based transport will do it.
177
 
            if client_medium.should_probe():
178
 
                try:
179
 
                    server_version = client_medium.protocol_version()
180
 
                    if server_version != '2':
181
 
                        do_vfs = True
182
 
                    else:
183
 
                        do_vfs = False
184
 
                except errors.SmartProtocolError:
185
 
                    # Apparently there's no usable smart server there, even though
186
 
                    # the medium supports the smart protocol.
187
 
                    do_vfs = True
188
 
            else:
189
 
                do_vfs = False
190
 
        if not do_vfs:
191
 
            client = _SmartClient(client_medium)
192
 
            path = client.remote_path_from_transport(transport)
193
 
            if client_medium._is_remote_before((1, 16)):
194
 
                do_vfs = True
195
 
        if do_vfs:
196
 
            # TODO: lookup the local format from a server hint.
197
 
            local_dir_format = _mod_bzrdir.BzrDirMetaFormat1()
198
 
            self._supply_sub_formats_to(local_dir_format)
199
 
            return local_dir_format.initialize_on_transport_ex(transport,
200
 
                use_existing_dir=use_existing_dir, create_prefix=create_prefix,
201
 
                force_new_repo=force_new_repo, stacked_on=stacked_on,
202
 
                stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
203
 
                make_working_trees=make_working_trees, shared_repo=shared_repo,
204
 
                vfs_only=True)
205
 
        return self._initialize_on_transport_ex_rpc(client, path, transport,
206
 
            use_existing_dir, create_prefix, force_new_repo, stacked_on,
207
 
            stack_on_pwd, repo_format_name, make_working_trees, shared_repo)
208
 
 
209
 
    def _initialize_on_transport_ex_rpc(self, client, path, transport,
210
 
        use_existing_dir, create_prefix, force_new_repo, stacked_on,
211
 
        stack_on_pwd, repo_format_name, make_working_trees, shared_repo):
212
 
        args = []
213
 
        args.append(self._serialize_NoneTrueFalse(use_existing_dir))
214
 
        args.append(self._serialize_NoneTrueFalse(create_prefix))
215
 
        args.append(self._serialize_NoneTrueFalse(force_new_repo))
216
 
        args.append(self._serialize_NoneString(stacked_on))
217
 
        # stack_on_pwd is often/usually our transport
218
 
        if stack_on_pwd:
219
 
            try:
220
 
                stack_on_pwd = transport.relpath(stack_on_pwd)
221
 
                if not stack_on_pwd:
222
 
                    stack_on_pwd = '.'
223
 
            except errors.PathNotChild:
224
 
                pass
225
 
        args.append(self._serialize_NoneString(stack_on_pwd))
226
 
        args.append(self._serialize_NoneString(repo_format_name))
227
 
        args.append(self._serialize_NoneTrueFalse(make_working_trees))
228
 
        args.append(self._serialize_NoneTrueFalse(shared_repo))
229
 
        request_network_name = self._network_name or \
230
 
            _mod_bzrdir.BzrDirFormat.get_default_format().network_name()
231
 
        try:
232
 
            response = client.call('BzrDirFormat.initialize_ex_1.16',
233
 
                request_network_name, path, *args)
234
 
        except errors.UnknownSmartMethod:
235
 
            client._medium._remember_remote_is_before((1,16))
236
 
            local_dir_format = _mod_bzrdir.BzrDirMetaFormat1()
237
 
            self._supply_sub_formats_to(local_dir_format)
238
 
            return local_dir_format.initialize_on_transport_ex(transport,
239
 
                use_existing_dir=use_existing_dir, create_prefix=create_prefix,
240
 
                force_new_repo=force_new_repo, stacked_on=stacked_on,
241
 
                stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
242
 
                make_working_trees=make_working_trees, shared_repo=shared_repo,
243
 
                vfs_only=True)
244
 
        except errors.ErrorFromSmartServer, err:
245
 
            _translate_error(err, path=path)
246
 
        repo_path = response[0]
247
 
        bzrdir_name = response[6]
248
 
        require_stacking = response[7]
249
 
        require_stacking = self.parse_NoneTrueFalse(require_stacking)
250
 
        format = RemoteBzrDirFormat()
251
 
        format._network_name = bzrdir_name
252
 
        self._supply_sub_formats_to(format)
253
 
        bzrdir = RemoteBzrDir(transport, format, _client=client)
254
 
        if repo_path:
255
 
            repo_format = response_tuple_to_repo_format(response[1:])
256
 
            if repo_path == '.':
257
 
                repo_path = ''
258
 
            if repo_path:
259
 
                repo_bzrdir_format = RemoteBzrDirFormat()
260
 
                repo_bzrdir_format._network_name = response[5]
261
 
                repo_bzr = RemoteBzrDir(transport.clone(repo_path),
262
 
                    repo_bzrdir_format)
263
 
            else:
264
 
                repo_bzr = bzrdir
265
 
            final_stack = response[8] or None
266
 
            final_stack_pwd = response[9] or None
267
 
            if final_stack_pwd:
268
 
                final_stack_pwd = urlutils.join(
269
 
                    transport.base, final_stack_pwd)
270
 
            remote_repo = RemoteRepository(repo_bzr, repo_format)
271
 
            if len(response) > 10:
272
 
                # Updated server verb that locks remotely.
273
 
                repo_lock_token = response[10] or None
274
 
                remote_repo.lock_write(repo_lock_token, _skip_rpc=True)
275
 
                if repo_lock_token:
276
 
                    remote_repo.dont_leave_lock_in_place()
277
 
            else:
278
 
                remote_repo.lock_write()
279
 
            policy = _mod_bzrdir.UseExistingRepository(remote_repo, final_stack,
280
 
                final_stack_pwd, require_stacking)
281
 
            policy.acquire_repository()
282
 
        else:
283
 
            remote_repo = None
284
 
            policy = None
285
 
        bzrdir._format.set_branch_format(self.get_branch_format())
286
 
        if require_stacking:
287
 
            # The repo has already been created, but we need to make sure that
288
 
            # we'll make a stackable branch.
289
 
            bzrdir._format.require_stacking(_skip_repo=True)
290
 
        return remote_repo, bzrdir, require_stacking, policy
291
 
 
292
 
    def _open(self, transport):
293
 
        return RemoteBzrDir(transport, self)
294
 
 
295
 
    def __eq__(self, other):
296
 
        if not isinstance(other, RemoteBzrDirFormat):
297
 
            return False
298
 
        return self.get_format_description() == other.get_format_description()
299
 
 
300
 
    def __return_repository_format(self):
301
 
        # Always return a RemoteRepositoryFormat object, but if a specific bzr
302
 
        # repository format has been asked for, tell the RemoteRepositoryFormat
303
 
        # that it should use that for init() etc.
304
 
        result = RemoteRepositoryFormat()
305
 
        custom_format = getattr(self, '_repository_format', None)
306
 
        if custom_format:
307
 
            if isinstance(custom_format, RemoteRepositoryFormat):
308
 
                return custom_format
309
 
            else:
310
 
                # We will use the custom format to create repositories over the
311
 
                # wire; expose its details like rich_root_data for code to
312
 
                # query
313
 
                result._custom_format = custom_format
314
 
        return result
315
 
 
316
 
    def get_branch_format(self):
317
 
        result = _mod_bzrdir.BzrDirMetaFormat1.get_branch_format(self)
318
 
        if not isinstance(result, RemoteBranchFormat):
319
 
            new_result = RemoteBranchFormat()
320
 
            new_result._custom_format = result
321
 
            # cache the result
322
 
            self.set_branch_format(new_result)
323
 
            result = new_result
324
 
        return result
325
 
 
326
 
    repository_format = property(__return_repository_format,
327
 
        _mod_bzrdir.BzrDirMetaFormat1._set_repository_format) #.im_func)
328
 
 
329
 
 
330
 
class RemoteBzrDir(_mod_bzrdir.BzrDir, _RpcHelper):
 
90
# Note: RemoteBzrDirFormat is in bzrdir.py
 
91
 
 
92
class RemoteBzrDir(BzrDir, _RpcHelper):
331
93
    """Control directory on a remote server, accessed via bzr:// or similar."""
332
94
 
333
95
    def __init__(self, transport, format, _client=None, _force_probe=False):
336
98
        :param _client: Private parameter for testing. Disables probing and the
337
99
            use of a real bzrdir.
338
100
        """
339
 
        _mod_bzrdir.BzrDir.__init__(self, transport, format)
 
101
        BzrDir.__init__(self, transport, format)
340
102
        # this object holds a delegated bzrdir that uses file-level operations
341
103
        # to talk to the other side
342
104
        self._real_bzrdir = None
402
164
                import traceback
403
165
                warning('VFS BzrDir access triggered\n%s',
404
166
                    ''.join(traceback.format_stack()))
405
 
            self._real_bzrdir = _mod_bzrdir.BzrDir.open_from_transport(
 
167
            self._real_bzrdir = BzrDir.open_from_transport(
406
168
                self.root_transport, _server_formats=False)
407
169
            self._format._network_name = \
408
170
                self._real_bzrdir._format.network_name()
414
176
        # Prevent aliasing problems in the next_open_branch_result cache.
415
177
        # See create_branch for rationale.
416
178
        self._next_open_branch_result = None
417
 
        return _mod_bzrdir.BzrDir.break_lock(self)
 
179
        return BzrDir.break_lock(self)
418
180
 
419
181
    def _vfs_cloning_metadir(self, require_stacking=False):
420
182
        self._ensure_real()
451
213
        if len(branch_info) != 2:
452
214
            raise errors.UnexpectedSmartServerResponse(response)
453
215
        branch_ref, branch_name = branch_info
454
 
        format = controldir.network_format_registry.get(control_name)
 
216
        format = bzrdir.network_format_registry.get(control_name)
455
217
        if repo_name:
456
 
            format.repository_format = _mod_repository.network_format_registry.get(
 
218
            format.repository_format = repository.network_format_registry.get(
457
219
                repo_name)
458
220
        if branch_ref == 'ref':
459
221
            # XXX: we need possible_transports here to avoid reopening the
460
222
            # connection to the referenced location
461
 
            ref_bzrdir = _mod_bzrdir.BzrDir.open(branch_name)
 
223
            ref_bzrdir = BzrDir.open(branch_name)
462
224
            branch_format = ref_bzrdir.cloning_metadir().get_branch_format()
463
225
            format.set_branch_format(branch_format)
464
226
        elif branch_ref == 'branch':
483
245
        self._ensure_real()
484
246
        self._real_bzrdir.destroy_repository()
485
247
 
486
 
    def create_branch(self, name=None, repository=None):
 
248
    def create_branch(self, name=None):
487
249
        # as per meta1 formats - just delegate to the format object which may
488
250
        # be parameterised.
489
251
        real_branch = self._format.get_branch_format().initialize(self,
490
 
            name=name, repository=repository)
 
252
            name=name)
491
253
        if not isinstance(real_branch, RemoteBranch):
492
 
            if not isinstance(repository, RemoteRepository):
493
 
                raise AssertionError(
494
 
                    'need a RemoteRepository to use with RemoteBranch, got %r'
495
 
                    % (repository,))
496
 
            result = RemoteBranch(self, repository, real_branch, name=name)
 
254
            result = RemoteBranch(self, self.find_repository(), real_branch,
 
255
                                  name=name)
497
256
        else:
498
257
            result = real_branch
499
258
        # BzrDir.clone_on_transport() uses the result of create_branch but does
511
270
        self._real_bzrdir.destroy_branch(name=name)
512
271
        self._next_open_branch_result = None
513
272
 
514
 
    def create_workingtree(self, revision_id=None, from_branch=None,
515
 
        accelerator_tree=None, hardlink=False):
 
273
    def create_workingtree(self, revision_id=None, from_branch=None):
516
274
        raise errors.NotLocalUrl(self.transport.base)
517
275
 
518
276
    def find_branch_format(self, name=None):
687
445
        """Upgrading of remote bzrdirs is not supported yet."""
688
446
        return False
689
447
 
690
 
    def needs_format_conversion(self, format):
 
448
    def needs_format_conversion(self, format=None):
691
449
        """Upgrading of remote bzrdirs is not supported yet."""
 
450
        if format is None:
 
451
            symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
 
452
                % 'needs_format_conversion(format=None)')
692
453
        return False
693
454
 
694
455
    def clone(self, url, revision_id=None, force_new_repo=False,
701
462
        return RemoteBzrDirConfig(self)
702
463
 
703
464
 
704
 
class RemoteRepositoryFormat(vf_repository.VersionedFileRepositoryFormat):
 
465
class RemoteRepositoryFormat(repository.RepositoryFormat):
705
466
    """Format for repositories accessed over a _SmartClient.
706
467
 
707
468
    Instances of this repository are represented by RemoteRepository
722
483
    """
723
484
 
724
485
    _matchingbzrdir = RemoteBzrDirFormat()
725
 
    supports_full_versioned_files = True
726
 
    supports_leaving_lock = True
727
486
 
728
487
    def __init__(self):
729
 
        _mod_repository.RepositoryFormat.__init__(self)
 
488
        repository.RepositoryFormat.__init__(self)
730
489
        self._custom_format = None
731
490
        self._network_name = None
732
491
        self._creating_bzrdir = None
733
 
        self._revision_graph_can_have_wrong_parents = None
734
492
        self._supports_chks = None
735
493
        self._supports_external_lookups = None
736
494
        self._supports_tree_reference = None
737
 
        self._supports_funky_characters = None
738
495
        self._rich_root_data = None
739
496
 
740
497
    def __repr__(self):
769
526
        return self._supports_external_lookups
770
527
 
771
528
    @property
772
 
    def supports_funky_characters(self):
773
 
        if self._supports_funky_characters is None:
774
 
            self._ensure_real()
775
 
            self._supports_funky_characters = \
776
 
                self._custom_format.supports_funky_characters
777
 
        return self._supports_funky_characters
778
 
 
779
 
    @property
780
529
    def supports_tree_reference(self):
781
530
        if self._supports_tree_reference is None:
782
531
            self._ensure_real()
784
533
                self._custom_format.supports_tree_reference
785
534
        return self._supports_tree_reference
786
535
 
787
 
    @property
788
 
    def revision_graph_can_have_wrong_parents(self):
789
 
        if self._revision_graph_can_have_wrong_parents is None:
790
 
            self._ensure_real()
791
 
            self._revision_graph_can_have_wrong_parents = \
792
 
                self._custom_format.revision_graph_can_have_wrong_parents
793
 
        return self._revision_graph_can_have_wrong_parents
794
 
 
795
536
    def _vfs_initialize(self, a_bzrdir, shared):
796
537
        """Helper for common code in initialize."""
797
538
        if self._custom_format:
832
573
            network_name = self._network_name
833
574
        else:
834
575
            # Select the current bzrlib default and ask for that.
835
 
            reference_bzrdir_format = _mod_bzrdir.format_registry.get('default')()
 
576
            reference_bzrdir_format = bzrdir.format_registry.get('default')()
836
577
            reference_format = reference_bzrdir_format.repository_format
837
578
            network_name = reference_format.network_name()
838
579
        # 2) try direct creation via RPC
864
605
 
865
606
    def _ensure_real(self):
866
607
        if self._custom_format is None:
867
 
            self._custom_format = _mod_repository.network_format_registry.get(
 
608
            self._custom_format = repository.network_format_registry.get(
868
609
                self._network_name)
869
610
 
870
611
    @property
907
648
 
908
649
 
909
650
class RemoteRepository(_RpcHelper, lock._RelockDebugMixin,
910
 
    controldir.ControlComponent):
 
651
    bzrdir.ControlComponent):
911
652
    """Repository accessed over rpc.
912
653
 
913
654
    For the moment most operations are performed using local transport-backed
966
707
        # transport, but I'm not sure it's worth making this method
967
708
        # optional -- mbp 2010-04-21
968
709
        return self.bzrdir.get_repository_transport(None)
969
 
 
 
710
        
970
711
    def __str__(self):
971
712
        return "%s(%s)" % (self.__class__.__name__, self.base)
972
713
 
1080
821
    def find_text_key_references(self):
1081
822
        """Find the text key references within the repository.
1082
823
 
 
824
        :return: a dictionary mapping (file_id, revision_id) tuples to altered file-ids to an iterable of
 
825
        revision_ids. Each altered file-ids has the exact revision_ids that
 
826
        altered it listed explicitly.
1083
827
        :return: A dictionary mapping text keys ((fileid, revision_id) tuples)
1084
828
            to whether they were referred to by the inventory of the
1085
829
            revision_id that they contain. The inventory texts from all present
1103
847
        """Private method for using with old (< 1.2) servers to fallback."""
1104
848
        if revision_id is None:
1105
849
            revision_id = ''
1106
 
        elif _mod_revision.is_null(revision_id):
 
850
        elif revision.is_null(revision_id):
1107
851
            return {}
1108
852
 
1109
853
        path = self.bzrdir._path_for_remote_call(self._client)
1133
877
        return RemoteStreamSource(self, to_format)
1134
878
 
1135
879
    @needs_read_lock
1136
 
    def get_file_graph(self):
1137
 
        return graph.Graph(self.texts)
1138
 
 
1139
 
    @needs_read_lock
1140
880
    def has_revision(self, revision_id):
1141
881
        """True if this repository has a copy of the revision."""
1142
882
        # Copy of bzrlib.repository.Repository.has_revision
1194
934
        """See Repository.gather_stats()."""
1195
935
        path = self.bzrdir._path_for_remote_call(self._client)
1196
936
        # revid can be None to indicate no revisions, not just NULL_REVISION
1197
 
        if revid is None or _mod_revision.is_null(revid):
 
937
        if revid is None or revision.is_null(revid):
1198
938
            fmt_revid = ''
1199
939
        else:
1200
940
            fmt_revid = revid
1483
1223
 
1484
1224
    def get_commit_builder(self, branch, parents, config, timestamp=None,
1485
1225
                           timezone=None, committer=None, revprops=None,
1486
 
                           revision_id=None, lossy=False):
 
1226
                           revision_id=None):
1487
1227
        # FIXME: It ought to be possible to call this without immediately
1488
1228
        # triggering _ensure_real.  For now it's the easiest thing to do.
1489
1229
        self._ensure_real()
1490
1230
        real_repo = self._real_repository
1491
1231
        builder = real_repo.get_commit_builder(branch, parents,
1492
1232
                config, timestamp=timestamp, timezone=timezone,
1493
 
                committer=committer, revprops=revprops,
1494
 
                revision_id=revision_id, lossy=lossy)
 
1233
                committer=committer, revprops=revprops, revision_id=revision_id)
1495
1234
        return builder
1496
1235
 
1497
1236
    def add_fallback_repository(self, repository):
1603
1342
        return result
1604
1343
 
1605
1344
    @needs_read_lock
1606
 
    def search_missing_revision_ids(self, other,
1607
 
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
1608
 
            find_ghosts=True, revision_ids=None, if_present_ids=None,
1609
 
            limit=None):
 
1345
    def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
1610
1346
        """Return the revision ids that other has that this does not.
1611
1347
 
1612
1348
        These are returned in topological order.
1613
1349
 
1614
1350
        revision_id: only return revision ids included by revision_id.
1615
1351
        """
1616
 
        if symbol_versioning.deprecated_passed(revision_id):
1617
 
            symbol_versioning.warn(
1618
 
                'search_missing_revision_ids(revision_id=...) was '
1619
 
                'deprecated in 2.4.  Use revision_ids=[...] instead.',
1620
 
                DeprecationWarning, stacklevel=2)
1621
 
            if revision_ids is not None:
1622
 
                raise AssertionError(
1623
 
                    'revision_ids is mutually exclusive with revision_id')
1624
 
            if revision_id is not None:
1625
 
                revision_ids = [revision_id]
1626
 
        inter_repo = _mod_repository.InterRepository.get(other, self)
1627
 
        return inter_repo.search_missing_revision_ids(
1628
 
            find_ghosts=find_ghosts, revision_ids=revision_ids,
1629
 
            if_present_ids=if_present_ids, limit=limit)
 
1352
        return repository.InterRepository.get(
 
1353
            other, self).search_missing_revision_ids(revision_id, find_ghosts)
1630
1354
 
1631
 
    def fetch(self, source, revision_id=None, find_ghosts=False,
 
1355
    def fetch(self, source, revision_id=None, pb=None, find_ghosts=False,
1632
1356
            fetch_spec=None):
1633
1357
        # No base implementation to use as RemoteRepository is not a subclass
1634
1358
        # of Repository; so this is a copy of Repository.fetch().
1645
1369
            # check that last_revision is in 'from' and then return a
1646
1370
            # no-operation.
1647
1371
            if (revision_id is not None and
1648
 
                not _mod_revision.is_null(revision_id)):
 
1372
                not revision.is_null(revision_id)):
1649
1373
                self.get_revision(revision_id)
1650
1374
            return 0, []
1651
1375
        # if there is no specific appropriate InterRepository, this will get
1652
1376
        # the InterRepository base class, which raises an
1653
1377
        # IncompatibleRepositories when asked to fetch.
1654
 
        inter = _mod_repository.InterRepository.get(source, self)
1655
 
        return inter.fetch(revision_id=revision_id,
 
1378
        inter = repository.InterRepository.get(source, self)
 
1379
        return inter.fetch(revision_id=revision_id, pb=pb,
1656
1380
            find_ghosts=find_ghosts, fetch_spec=fetch_spec)
1657
1381
 
1658
1382
    def create_bundle(self, target, base, fileobj, format=None):
1660
1384
        self._real_repository.create_bundle(target, base, fileobj, format)
1661
1385
 
1662
1386
    @needs_read_lock
1663
 
    @symbol_versioning.deprecated_method(
1664
 
        symbol_versioning.deprecated_in((2, 4, 0)))
1665
1387
    def get_ancestry(self, revision_id, topo_sorted=True):
1666
1388
        self._ensure_real()
1667
1389
        return self._real_repository.get_ancestry(revision_id, topo_sorted)
1884
1606
            tmpdir = osutils.mkdtemp()
1885
1607
            try:
1886
1608
                _extract_tar(tar, tmpdir)
1887
 
                tmp_bzrdir = _mod_bzrdir.BzrDir.open(tmpdir)
 
1609
                tmp_bzrdir = BzrDir.open(tmpdir)
1888
1610
                tmp_repo = tmp_bzrdir.open_repository()
1889
1611
                tmp_repo.copy_content_into(destination, revision_id)
1890
1612
            finally:
1975
1697
    def supports_rich_root(self):
1976
1698
        return self._format.rich_root_data
1977
1699
 
1978
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
1979
1700
    def iter_reverse_revision_history(self, revision_id):
1980
1701
        self._ensure_real()
1981
1702
        return self._real_repository.iter_reverse_revision_history(revision_id)
2002
1723
        return self._real_repository.item_keys_introduced_by(revision_ids,
2003
1724
            _files_pb=_files_pb)
2004
1725
 
 
1726
    def revision_graph_can_have_wrong_parents(self):
 
1727
        # The answer depends on the remote repo format.
 
1728
        self._ensure_real()
 
1729
        return self._real_repository.revision_graph_can_have_wrong_parents()
 
1730
 
2005
1731
    def _find_inconsistent_revision_parents(self, revisions_iterator=None):
2006
1732
        self._ensure_real()
2007
1733
        return self._real_repository._find_inconsistent_revision_parents(
2015
1741
        providers = [self._unstacked_provider]
2016
1742
        if other is not None:
2017
1743
            providers.insert(0, other)
2018
 
        return graph.StackedParentsProvider(_LazyListJoin(
2019
 
            providers, self._fallback_repositories))
 
1744
        providers.extend(r._make_parents_provider() for r in
 
1745
                         self._fallback_repositories)
 
1746
        return graph.StackedParentsProvider(providers)
2020
1747
 
2021
1748
    def _serialise_search_recipe(self, recipe):
2022
1749
        """Serialise a graph search recipe.
2030
1757
        return '\n'.join((start_keys, stop_keys, count))
2031
1758
 
2032
1759
    def _serialise_search_result(self, search_result):
2033
 
        parts = search_result.get_network_struct()
 
1760
        if isinstance(search_result, graph.PendingAncestryResult):
 
1761
            parts = ['ancestry-of']
 
1762
            parts.extend(search_result.heads)
 
1763
        else:
 
1764
            recipe = search_result.get_recipe()
 
1765
            parts = [recipe[0], self._serialise_search_recipe(recipe)]
2034
1766
        return '\n'.join(parts)
2035
1767
 
2036
1768
    def autopack(self):
2046
1778
            raise errors.UnexpectedSmartServerResponse(response)
2047
1779
 
2048
1780
 
2049
 
class RemoteStreamSink(vf_repository.StreamSink):
 
1781
class RemoteStreamSink(repository.StreamSink):
2050
1782
 
2051
1783
    def _insert_real(self, stream, src_format, resume_tokens):
2052
1784
        self.target_repo._ensure_real()
2153
1885
        self._last_substream and self._last_stream so that the stream can be
2154
1886
        resumed by _resume_stream_with_vfs.
2155
1887
        """
2156
 
 
 
1888
                    
2157
1889
        stream_iter = iter(stream)
2158
1890
        for substream_kind, substream in stream_iter:
2159
1891
            if substream_kind == 'inventory-deltas':
2162
1894
                return
2163
1895
            else:
2164
1896
                yield substream_kind, substream
2165
 
 
2166
 
 
2167
 
class RemoteStreamSource(vf_repository.StreamSource):
 
1897
            
 
1898
 
 
1899
class RemoteStreamSource(repository.StreamSource):
2168
1900
    """Stream data from a remote server."""
2169
1901
 
2170
1902
    def get_stream(self, search):
2230
1962
        candidate_verbs = [
2231
1963
            ('Repository.get_stream_1.19', (1, 19)),
2232
1964
            ('Repository.get_stream', (1, 13))]
2233
 
 
2234
1965
        found_verb = False
2235
1966
        for verb, version in candidate_verbs:
2236
1967
            if medium._is_remote_before(version):
2240
1971
                    verb, args, search_bytes)
2241
1972
            except errors.UnknownSmartMethod:
2242
1973
                medium._remember_remote_is_before(version)
2243
 
            except errors.UnknownErrorFromSmartServer, e:
2244
 
                if isinstance(search, graph.EverythingResult):
2245
 
                    error_verb = e.error_from_smart_server.error_verb
2246
 
                    if error_verb == 'BadSearch':
2247
 
                        # Pre-2.4 servers don't support this sort of search.
2248
 
                        # XXX: perhaps falling back to VFS on BadSearch is a
2249
 
                        # good idea in general?  It might provide a little bit
2250
 
                        # of protection against client-side bugs.
2251
 
                        medium._remember_remote_is_before((2, 4))
2252
 
                        break
2253
 
                raise
2254
1974
            else:
2255
1975
                response_tuple, response_handler = response
2256
1976
                found_verb = True
2371
2091
                                  name=name)
2372
2092
        return result
2373
2093
 
2374
 
    def initialize(self, a_bzrdir, name=None, repository=None):
 
2094
    def initialize(self, a_bzrdir, name=None):
2375
2095
        # 1) get the network name to use.
2376
2096
        if self._custom_format:
2377
2097
            network_name = self._custom_format.network_name()
2378
2098
        else:
2379
2099
            # Select the current bzrlib default and ask for that.
2380
 
            reference_bzrdir_format = _mod_bzrdir.format_registry.get('default')()
 
2100
            reference_bzrdir_format = bzrdir.format_registry.get('default')()
2381
2101
            reference_format = reference_bzrdir_format.get_branch_format()
2382
2102
            self._custom_format = reference_format
2383
2103
            network_name = reference_format.network_name()
2405
2125
        # Turn the response into a RemoteRepository object.
2406
2126
        format = RemoteBranchFormat(network_name=response[1])
2407
2127
        repo_format = response_tuple_to_repo_format(response[3:])
2408
 
        repo_path = response[2]
2409
 
        if repository is not None:
2410
 
            remote_repo_url = urlutils.join(a_bzrdir.user_url, repo_path)
2411
 
            url_diff = urlutils.relative_url(repository.user_url,
2412
 
                    remote_repo_url)
2413
 
            if url_diff != '.':
2414
 
                raise AssertionError(
2415
 
                    'repository.user_url %r does not match URL from server '
2416
 
                    'response (%r + %r)'
2417
 
                    % (repository.user_url, a_bzrdir.user_url, repo_path))
2418
 
            remote_repo = repository
 
2128
        if response[2] == '':
 
2129
            repo_bzrdir = a_bzrdir
2419
2130
        else:
2420
 
            if repo_path == '':
2421
 
                repo_bzrdir = a_bzrdir
2422
 
            else:
2423
 
                repo_bzrdir = RemoteBzrDir(
2424
 
                    a_bzrdir.root_transport.clone(repo_path), a_bzrdir._format,
2425
 
                    a_bzrdir._client)
2426
 
            remote_repo = RemoteRepository(repo_bzrdir, repo_format)
 
2131
            repo_bzrdir = RemoteBzrDir(
 
2132
                a_bzrdir.root_transport.clone(response[2]), a_bzrdir._format,
 
2133
                a_bzrdir._client)
 
2134
        remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2427
2135
        remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2428
2136
            format=format, setup_stacking=False, name=name)
2429
2137
        # XXX: We know this is a new branch, so it must have revno 0, revid
2450
2158
        self._ensure_real()
2451
2159
        return self._custom_format.supports_set_append_revisions_only()
2452
2160
 
2453
 
    def _use_default_local_heads_to_fetch(self):
2454
 
        # If the branch format is a metadir format *and* its heads_to_fetch
2455
 
        # implementation is not overridden vs the base class, we can use the
2456
 
        # base class logic rather than use the heads_to_fetch RPC.  This is
2457
 
        # usually cheaper in terms of net round trips, as the last-revision and
2458
 
        # tags info fetched is cached and would be fetched anyway.
2459
 
        self._ensure_real()
2460
 
        if isinstance(self._custom_format, branch.BranchFormatMetadir):
2461
 
            branch_class = self._custom_format._branch_class()
2462
 
            heads_to_fetch_impl = branch_class.heads_to_fetch.im_func
2463
 
            if heads_to_fetch_impl is branch.Branch.heads_to_fetch.im_func:
2464
 
                return True
2465
 
        return False
2466
2161
 
2467
2162
class RemoteBranch(branch.Branch, _RpcHelper, lock._RelockDebugMixin):
2468
2163
    """Branch stored on a server accessed by HPSS RPC.
2667
2362
            self._is_stacked = False
2668
2363
        else:
2669
2364
            self._is_stacked = True
2670
 
 
 
2365
        
2671
2366
    def _vfs_get_tags_bytes(self):
2672
2367
        self._ensure_real()
2673
2368
        return self._real_branch._get_tags_bytes()
2674
2369
 
2675
 
    @needs_read_lock
2676
2370
    def _get_tags_bytes(self):
2677
 
        if self._tags_bytes is None:
2678
 
            self._tags_bytes = self._get_tags_bytes_via_hpss()
2679
 
        return self._tags_bytes
2680
 
 
2681
 
    def _get_tags_bytes_via_hpss(self):
2682
2371
        medium = self._client._medium
2683
2372
        if medium._is_remote_before((1, 13)):
2684
2373
            return self._vfs_get_tags_bytes()
2694
2383
        return self._real_branch._set_tags_bytes(bytes)
2695
2384
 
2696
2385
    def _set_tags_bytes(self, bytes):
2697
 
        if self.is_locked():
2698
 
            self._tags_bytes = bytes
2699
2386
        medium = self._client._medium
2700
2387
        if medium._is_remote_before((1, 18)):
2701
2388
            self._vfs_set_tags_bytes(bytes)
2855
2542
            missing_parent = parent_map[missing_parent]
2856
2543
        raise errors.RevisionNotPresent(missing_parent, self.repository)
2857
2544
 
2858
 
    def _read_last_revision_info(self):
 
2545
    def _last_revision_info(self):
2859
2546
        response = self._call('Branch.last_revision_info', self._remote_path())
2860
2547
        if response[0] != 'ok':
2861
2548
            raise SmartProtocolError('unexpected response code %s' % (response,))
2924
2611
            raise errors.UnexpectedSmartServerResponse(response)
2925
2612
        self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2926
2613
 
2927
 
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
2928
2614
    @needs_write_lock
2929
2615
    def set_revision_history(self, rev_history):
2930
 
        """See Branch.set_revision_history."""
2931
 
        self._set_revision_history(rev_history)
2932
 
 
2933
 
    @needs_write_lock
2934
 
    def _set_revision_history(self, rev_history):
2935
2616
        # Send just the tip revision of the history; the server will generate
2936
2617
        # the full history from that.  If the revision doesn't exist in this
2937
2618
        # branch, NoSuchRevision will be raised.
2995
2676
            _override_hook_target=self, **kwargs)
2996
2677
 
2997
2678
    @needs_read_lock
2998
 
    def push(self, target, overwrite=False, stop_revision=None, lossy=False):
 
2679
    def push(self, target, overwrite=False, stop_revision=None):
2999
2680
        self._ensure_real()
3000
2681
        return self._real_branch.push(
3001
 
            target, overwrite=overwrite, stop_revision=stop_revision, lossy=lossy,
 
2682
            target, overwrite=overwrite, stop_revision=stop_revision,
3002
2683
            _override_hook_source_branch=self)
3003
2684
 
3004
2685
    def is_locked(self):
3014
2695
        # XXX: These should be returned by the set_last_revision_info verb
3015
2696
        old_revno, old_revid = self.last_revision_info()
3016
2697
        self._run_pre_change_branch_tip_hooks(revno, revision_id)
3017
 
        if not revision_id or not isinstance(revision_id, basestring):
3018
 
            raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
 
2698
        revision_id = ensure_null(revision_id)
3019
2699
        try:
3020
2700
            response = self._call('Branch.set_last_revision_info',
3021
2701
                self._remote_path(), self._lock_token, self._repo_lock_token,
3050
2730
            except errors.UnknownSmartMethod:
3051
2731
                medium._remember_remote_is_before((1, 6))
3052
2732
        self._clear_cached_state_of_remote_branch_only()
3053
 
        self._set_revision_history(self._lefthand_history(revision_id,
 
2733
        self.set_revision_history(self._lefthand_history(revision_id,
3054
2734
            last_rev=last_rev,other_branch=other_branch))
3055
2735
 
3056
2736
    def set_push_location(self, location):
3057
2737
        self._ensure_real()
3058
2738
        return self._real_branch.set_push_location(location)
3059
2739
 
3060
 
    def heads_to_fetch(self):
3061
 
        if self._format._use_default_local_heads_to_fetch():
3062
 
            # We recognise this format, and its heads-to-fetch implementation
3063
 
            # is the default one (tip + tags).  In this case it's cheaper to
3064
 
            # just use the default implementation rather than a special RPC as
3065
 
            # the tip and tags data is cached.
3066
 
            return branch.Branch.heads_to_fetch(self)
3067
 
        medium = self._client._medium
3068
 
        if medium._is_remote_before((2, 4)):
3069
 
            return self._vfs_heads_to_fetch()
3070
 
        try:
3071
 
            return self._rpc_heads_to_fetch()
3072
 
        except errors.UnknownSmartMethod:
3073
 
            medium._remember_remote_is_before((2, 4))
3074
 
            return self._vfs_heads_to_fetch()
3075
 
 
3076
 
    def _rpc_heads_to_fetch(self):
3077
 
        response = self._call('Branch.heads_to_fetch', self._remote_path())
3078
 
        if len(response) != 2:
3079
 
            raise errors.UnexpectedSmartServerResponse(response)
3080
 
        must_fetch, if_present_fetch = response
3081
 
        return set(must_fetch), set(if_present_fetch)
3082
 
 
3083
 
    def _vfs_heads_to_fetch(self):
3084
 
        self._ensure_real()
3085
 
        return self._real_branch.heads_to_fetch()
3086
 
 
3087
2740
 
3088
2741
class RemoteConfig(object):
3089
2742
    """A Config that reads and writes from smart verbs.
3103
2756
        """
3104
2757
        try:
3105
2758
            configobj = self._get_configobj()
3106
 
            section_obj = None
3107
2759
            if section is None:
3108
2760
                section_obj = configobj
3109
2761
            else:
3110
2762
                try:
3111
2763
                    section_obj = configobj[section]
3112
2764
                except KeyError:
3113
 
                    pass
3114
 
            if section_obj is None:
3115
 
                value = default
3116
 
            else:
3117
 
                value = section_obj.get(name, default)
 
2765
                    return default
 
2766
            return section_obj.get(name, default)
3118
2767
        except errors.UnknownSmartMethod:
3119
 
            value = self._vfs_get_option(name, section, default)
3120
 
        for hook in config.OldConfigHooks['get']:
3121
 
            hook(self, name, value)
3122
 
        return value
 
2768
            return self._vfs_get_option(name, section, default)
3123
2769
 
3124
2770
    def _response_to_configobj(self, response):
3125
2771
        if len(response[0]) and response[0][0] != 'ok':
3126
2772
            raise errors.UnexpectedSmartServerResponse(response)
3127
2773
        lines = response[1].read_body_bytes().splitlines()
3128
 
        conf = config.ConfigObj(lines, encoding='utf-8')
3129
 
        for hook in config.OldConfigHooks['load']:
3130
 
            hook(self)
3131
 
        return conf
 
2774
        return config.ConfigObj(lines, encoding='utf-8')
3132
2775
 
3133
2776
 
3134
2777
class RemoteBranchConfig(RemoteConfig):
3286
2929
                    'Missing key %r in context %r', key_err.args[0], context)
3287
2930
                raise err
3288
2931
 
3289
 
    if err.error_verb == 'NoSuchRevision':
 
2932
    if err.error_verb == 'IncompatibleRepositories':
 
2933
        raise errors.IncompatibleRepositories(err.error_args[0],
 
2934
            err.error_args[1], err.error_args[2])
 
2935
    elif err.error_verb == 'NoSuchRevision':
3290
2936
        raise NoSuchRevision(find('branch'), err.error_args[0])
3291
2937
    elif err.error_verb == 'nosuchrevision':
3292
2938
        raise NoSuchRevision(find('repository'), err.error_args[0])
3299
2945
            detail=extra)
3300
2946
    elif err.error_verb == 'norepository':
3301
2947
        raise errors.NoRepositoryPresent(find('bzrdir'))
 
2948
    elif err.error_verb == 'LockContention':
 
2949
        raise errors.LockContention('(remote lock)')
3302
2950
    elif err.error_verb == 'UnlockableTransport':
3303
2951
        raise errors.UnlockableTransport(find('bzrdir').root_transport)
 
2952
    elif err.error_verb == 'LockFailed':
 
2953
        raise errors.LockFailed(err.error_args[0], err.error_args[1])
3304
2954
    elif err.error_verb == 'TokenMismatch':
3305
2955
        raise errors.TokenMismatch(find('token'), '(remote token)')
3306
2956
    elif err.error_verb == 'Diverged':
3307
2957
        raise errors.DivergedBranches(find('branch'), find('other_branch'))
 
2958
    elif err.error_verb == 'TipChangeRejected':
 
2959
        raise errors.TipChangeRejected(err.error_args[0].decode('utf8'))
 
2960
    elif err.error_verb == 'UnstackableBranchFormat':
 
2961
        raise errors.UnstackableBranchFormat(*err.error_args)
 
2962
    elif err.error_verb == 'UnstackableRepositoryFormat':
 
2963
        raise errors.UnstackableRepositoryFormat(*err.error_args)
3308
2964
    elif err.error_verb == 'NotStacked':
3309
2965
        raise errors.NotStacked(branch=find('branch'))
3310
2966
    elif err.error_verb == 'PermissionDenied':
3320
2976
    elif err.error_verb == 'NoSuchFile':
3321
2977
        path = get_path()
3322
2978
        raise errors.NoSuchFile(path)
3323
 
    _translate_error_without_context(err)
3324
 
 
3325
 
 
3326
 
def _translate_error_without_context(err):
3327
 
    """Translate any ErrorFromSmartServer values that don't require context"""
3328
 
    if err.error_verb == 'IncompatibleRepositories':
3329
 
        raise errors.IncompatibleRepositories(err.error_args[0],
3330
 
            err.error_args[1], err.error_args[2])
3331
 
    elif err.error_verb == 'LockContention':
3332
 
        raise errors.LockContention('(remote lock)')
3333
 
    elif err.error_verb == 'LockFailed':
3334
 
        raise errors.LockFailed(err.error_args[0], err.error_args[1])
3335
 
    elif err.error_verb == 'TipChangeRejected':
3336
 
        raise errors.TipChangeRejected(err.error_args[0].decode('utf8'))
3337
 
    elif err.error_verb == 'UnstackableBranchFormat':
3338
 
        raise errors.UnstackableBranchFormat(*err.error_args)
3339
 
    elif err.error_verb == 'UnstackableRepositoryFormat':
3340
 
        raise errors.UnstackableRepositoryFormat(*err.error_args)
3341
2979
    elif err.error_verb == 'FileExists':
3342
2980
        raise errors.FileExists(err.error_args[0])
3343
2981
    elif err.error_verb == 'DirectoryNotEmpty':
3362
3000
            raise UnicodeEncodeError(encoding, val, start, end, reason)
3363
3001
    elif err.error_verb == 'ReadOnlyError':
3364
3002
        raise errors.TransportNotPossible('readonly transport')
3365
 
    elif err.error_verb == 'MemoryError':
3366
 
        raise errors.BzrError("remote server out of memory\n"
3367
 
            "Retry non-remotely, or contact the server admin for details.")
3368
3003
    raise errors.UnknownErrorFromSmartServer(err)