/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

  • Committer: Vincent Ladeuil
  • Date: 2011-07-06 09:22:00 UTC
  • mfrom: (6008 +trunk)
  • mto: (6012.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 6013.
  • Revision ID: v.ladeuil+lp@free.fr-20110706092200-7iai2mwzc0sqdsvf
MergingĀ inĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
from bzrlib import (
20
20
    bencode,
21
21
    branch,
22
 
    bzrdir,
 
22
    bzrdir as _mod_bzrdir,
23
23
    config,
24
24
    controldir,
25
25
    debug,
27
27
    graph,
28
28
    lock,
29
29
    lockdir,
30
 
    repository,
31
30
    repository as _mod_repository,
32
 
    revision,
33
31
    revision as _mod_revision,
34
32
    static_tuple,
35
33
    symbol_versioning,
36
34
    urlutils,
37
 
)
 
35
    vf_repository,
 
36
    )
38
37
from bzrlib.branch import BranchReferenceFormat, BranchWriteLockResult
39
 
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
40
38
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
41
39
from bzrlib.errors import (
42
40
    NoSuchRevision,
44
42
    )
45
43
from bzrlib.lockable_files import LockableFiles
46
44
from bzrlib.smart import client, vfs, repository as smart_repo
47
 
from bzrlib.revision import ensure_null, NULL_REVISION
48
 
from bzrlib.repository import RepositoryWriteLockResult
 
45
from bzrlib.smart.client import _SmartClient
 
46
from bzrlib.revision import NULL_REVISION
 
47
from bzrlib.repository import RepositoryWriteLockResult, _LazyListJoin
49
48
from bzrlib.trace import mutter, note, warning
50
49
 
51
50
 
89
88
    return format
90
89
 
91
90
 
92
 
# Note: RemoteBzrDirFormat is in bzrdir.py
93
 
 
94
 
class RemoteBzrDir(BzrDir, _RpcHelper):
 
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):
95
331
    """Control directory on a remote server, accessed via bzr:// or similar."""
96
332
 
97
333
    def __init__(self, transport, format, _client=None, _force_probe=False):
100
336
        :param _client: Private parameter for testing. Disables probing and the
101
337
            use of a real bzrdir.
102
338
        """
103
 
        BzrDir.__init__(self, transport, format)
 
339
        _mod_bzrdir.BzrDir.__init__(self, transport, format)
104
340
        # this object holds a delegated bzrdir that uses file-level operations
105
341
        # to talk to the other side
106
342
        self._real_bzrdir = None
166
402
                import traceback
167
403
                warning('VFS BzrDir access triggered\n%s',
168
404
                    ''.join(traceback.format_stack()))
169
 
            self._real_bzrdir = BzrDir.open_from_transport(
 
405
            self._real_bzrdir = _mod_bzrdir.BzrDir.open_from_transport(
170
406
                self.root_transport, _server_formats=False)
171
407
            self._format._network_name = \
172
408
                self._real_bzrdir._format.network_name()
178
414
        # Prevent aliasing problems in the next_open_branch_result cache.
179
415
        # See create_branch for rationale.
180
416
        self._next_open_branch_result = None
181
 
        return BzrDir.break_lock(self)
 
417
        return _mod_bzrdir.BzrDir.break_lock(self)
182
418
 
183
419
    def _vfs_cloning_metadir(self, require_stacking=False):
184
420
        self._ensure_real()
217
453
        branch_ref, branch_name = branch_info
218
454
        format = controldir.network_format_registry.get(control_name)
219
455
        if repo_name:
220
 
            format.repository_format = repository.network_format_registry.get(
 
456
            format.repository_format = _mod_repository.network_format_registry.get(
221
457
                repo_name)
222
458
        if branch_ref == 'ref':
223
459
            # XXX: we need possible_transports here to avoid reopening the
224
460
            # connection to the referenced location
225
 
            ref_bzrdir = BzrDir.open(branch_name)
 
461
            ref_bzrdir = _mod_bzrdir.BzrDir.open(branch_name)
226
462
            branch_format = ref_bzrdir.cloning_metadir().get_branch_format()
227
463
            format.set_branch_format(branch_format)
228
464
        elif branch_ref == 'branch':
451
687
        """Upgrading of remote bzrdirs is not supported yet."""
452
688
        return False
453
689
 
454
 
    def needs_format_conversion(self, format=None):
 
690
    def needs_format_conversion(self, format):
455
691
        """Upgrading of remote bzrdirs is not supported yet."""
456
 
        if format is None:
457
 
            symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
458
 
                % 'needs_format_conversion(format=None)')
459
692
        return False
460
693
 
461
694
    def clone(self, url, revision_id=None, force_new_repo=False,
468
701
        return RemoteBzrDirConfig(self)
469
702
 
470
703
 
471
 
class RemoteRepositoryFormat(repository.RepositoryFormat):
 
704
class RemoteRepositoryFormat(vf_repository.VersionedFileRepositoryFormat):
472
705
    """Format for repositories accessed over a _SmartClient.
473
706
 
474
707
    Instances of this repository are represented by RemoteRepository
489
722
    """
490
723
 
491
724
    _matchingbzrdir = RemoteBzrDirFormat()
 
725
    supports_full_versioned_files = True
 
726
    supports_leaving_lock = True
492
727
 
493
728
    def __init__(self):
494
 
        repository.RepositoryFormat.__init__(self)
 
729
        _mod_repository.RepositoryFormat.__init__(self)
495
730
        self._custom_format = None
496
731
        self._network_name = None
497
732
        self._creating_bzrdir = None
 
733
        self._revision_graph_can_have_wrong_parents = None
498
734
        self._supports_chks = None
499
735
        self._supports_external_lookups = None
500
736
        self._supports_tree_reference = None
 
737
        self._supports_funky_characters = None
501
738
        self._rich_root_data = None
502
739
 
503
740
    def __repr__(self):
532
769
        return self._supports_external_lookups
533
770
 
534
771
    @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
535
780
    def supports_tree_reference(self):
536
781
        if self._supports_tree_reference is None:
537
782
            self._ensure_real()
539
784
                self._custom_format.supports_tree_reference
540
785
        return self._supports_tree_reference
541
786
 
 
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
 
542
795
    def _vfs_initialize(self, a_bzrdir, shared):
543
796
        """Helper for common code in initialize."""
544
797
        if self._custom_format:
579
832
            network_name = self._network_name
580
833
        else:
581
834
            # Select the current bzrlib default and ask for that.
582
 
            reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
835
            reference_bzrdir_format = _mod_bzrdir.format_registry.get('default')()
583
836
            reference_format = reference_bzrdir_format.repository_format
584
837
            network_name = reference_format.network_name()
585
838
        # 2) try direct creation via RPC
611
864
 
612
865
    def _ensure_real(self):
613
866
        if self._custom_format is None:
614
 
            self._custom_format = repository.network_format_registry.get(
 
867
            self._custom_format = _mod_repository.network_format_registry.get(
615
868
                self._network_name)
616
869
 
617
870
    @property
713
966
        # transport, but I'm not sure it's worth making this method
714
967
        # optional -- mbp 2010-04-21
715
968
        return self.bzrdir.get_repository_transport(None)
716
 
        
 
969
 
717
970
    def __str__(self):
718
971
        return "%s(%s)" % (self.__class__.__name__, self.base)
719
972
 
827
1080
    def find_text_key_references(self):
828
1081
        """Find the text key references within the repository.
829
1082
 
830
 
        :return: a dictionary mapping (file_id, revision_id) tuples to altered file-ids to an iterable of
831
 
        revision_ids. Each altered file-ids has the exact revision_ids that
832
 
        altered it listed explicitly.
833
1083
        :return: A dictionary mapping text keys ((fileid, revision_id) tuples)
834
1084
            to whether they were referred to by the inventory of the
835
1085
            revision_id that they contain. The inventory texts from all present
853
1103
        """Private method for using with old (< 1.2) servers to fallback."""
854
1104
        if revision_id is None:
855
1105
            revision_id = ''
856
 
        elif revision.is_null(revision_id):
 
1106
        elif _mod_revision.is_null(revision_id):
857
1107
            return {}
858
1108
 
859
1109
        path = self.bzrdir._path_for_remote_call(self._client)
883
1133
        return RemoteStreamSource(self, to_format)
884
1134
 
885
1135
    @needs_read_lock
 
1136
    def get_file_graph(self):
 
1137
        return graph.Graph(self.texts)
 
1138
 
 
1139
    @needs_read_lock
886
1140
    def has_revision(self, revision_id):
887
1141
        """True if this repository has a copy of the revision."""
888
1142
        # Copy of bzrlib.repository.Repository.has_revision
940
1194
        """See Repository.gather_stats()."""
941
1195
        path = self.bzrdir._path_for_remote_call(self._client)
942
1196
        # revid can be None to indicate no revisions, not just NULL_REVISION
943
 
        if revid is None or revision.is_null(revid):
 
1197
        if revid is None or _mod_revision.is_null(revid):
944
1198
            fmt_revid = ''
945
1199
        else:
946
1200
            fmt_revid = revid
1229
1483
 
1230
1484
    def get_commit_builder(self, branch, parents, config, timestamp=None,
1231
1485
                           timezone=None, committer=None, revprops=None,
1232
 
                           revision_id=None):
 
1486
                           revision_id=None, lossy=False):
1233
1487
        # FIXME: It ought to be possible to call this without immediately
1234
1488
        # triggering _ensure_real.  For now it's the easiest thing to do.
1235
1489
        self._ensure_real()
1236
1490
        real_repo = self._real_repository
1237
1491
        builder = real_repo.get_commit_builder(branch, parents,
1238
1492
                config, timestamp=timestamp, timezone=timezone,
1239
 
                committer=committer, revprops=revprops, revision_id=revision_id)
 
1493
                committer=committer, revprops=revprops,
 
1494
                revision_id=revision_id, lossy=lossy)
1240
1495
        return builder
1241
1496
 
1242
1497
    def add_fallback_repository(self, repository):
1348
1603
        return result
1349
1604
 
1350
1605
    @needs_read_lock
1351
 
    def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
 
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):
1352
1610
        """Return the revision ids that other has that this does not.
1353
1611
 
1354
1612
        These are returned in topological order.
1355
1613
 
1356
1614
        revision_id: only return revision ids included by revision_id.
1357
1615
        """
1358
 
        return repository.InterRepository.get(
1359
 
            other, self).search_missing_revision_ids(revision_id, find_ghosts)
 
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)
1360
1630
 
1361
 
    def fetch(self, source, revision_id=None, pb=None, find_ghosts=False,
 
1631
    def fetch(self, source, revision_id=None, find_ghosts=False,
1362
1632
            fetch_spec=None):
1363
1633
        # No base implementation to use as RemoteRepository is not a subclass
1364
1634
        # of Repository; so this is a copy of Repository.fetch().
1375
1645
            # check that last_revision is in 'from' and then return a
1376
1646
            # no-operation.
1377
1647
            if (revision_id is not None and
1378
 
                not revision.is_null(revision_id)):
 
1648
                not _mod_revision.is_null(revision_id)):
1379
1649
                self.get_revision(revision_id)
1380
1650
            return 0, []
1381
1651
        # if there is no specific appropriate InterRepository, this will get
1382
1652
        # the InterRepository base class, which raises an
1383
1653
        # IncompatibleRepositories when asked to fetch.
1384
 
        inter = repository.InterRepository.get(source, self)
1385
 
        return inter.fetch(revision_id=revision_id, pb=pb,
 
1654
        inter = _mod_repository.InterRepository.get(source, self)
 
1655
        return inter.fetch(revision_id=revision_id,
1386
1656
            find_ghosts=find_ghosts, fetch_spec=fetch_spec)
1387
1657
 
1388
1658
    def create_bundle(self, target, base, fileobj, format=None):
1390
1660
        self._real_repository.create_bundle(target, base, fileobj, format)
1391
1661
 
1392
1662
    @needs_read_lock
 
1663
    @symbol_versioning.deprecated_method(
 
1664
        symbol_versioning.deprecated_in((2, 4, 0)))
1393
1665
    def get_ancestry(self, revision_id, topo_sorted=True):
1394
1666
        self._ensure_real()
1395
1667
        return self._real_repository.get_ancestry(revision_id, topo_sorted)
1612
1884
            tmpdir = osutils.mkdtemp()
1613
1885
            try:
1614
1886
                _extract_tar(tar, tmpdir)
1615
 
                tmp_bzrdir = BzrDir.open(tmpdir)
 
1887
                tmp_bzrdir = _mod_bzrdir.BzrDir.open(tmpdir)
1616
1888
                tmp_repo = tmp_bzrdir.open_repository()
1617
1889
                tmp_repo.copy_content_into(destination, revision_id)
1618
1890
            finally:
1703
1975
    def supports_rich_root(self):
1704
1976
        return self._format.rich_root_data
1705
1977
 
 
1978
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
1706
1979
    def iter_reverse_revision_history(self, revision_id):
1707
1980
        self._ensure_real()
1708
1981
        return self._real_repository.iter_reverse_revision_history(revision_id)
1729
2002
        return self._real_repository.item_keys_introduced_by(revision_ids,
1730
2003
            _files_pb=_files_pb)
1731
2004
 
1732
 
    def revision_graph_can_have_wrong_parents(self):
1733
 
        # The answer depends on the remote repo format.
1734
 
        self._ensure_real()
1735
 
        return self._real_repository.revision_graph_can_have_wrong_parents()
1736
 
 
1737
2005
    def _find_inconsistent_revision_parents(self, revisions_iterator=None):
1738
2006
        self._ensure_real()
1739
2007
        return self._real_repository._find_inconsistent_revision_parents(
1747
2015
        providers = [self._unstacked_provider]
1748
2016
        if other is not None:
1749
2017
            providers.insert(0, other)
1750
 
        providers.extend(r._make_parents_provider() for r in
1751
 
                         self._fallback_repositories)
1752
 
        return graph.StackedParentsProvider(providers)
 
2018
        return graph.StackedParentsProvider(_LazyListJoin(
 
2019
            providers, self._fallback_repositories))
1753
2020
 
1754
2021
    def _serialise_search_recipe(self, recipe):
1755
2022
        """Serialise a graph search recipe.
1763
2030
        return '\n'.join((start_keys, stop_keys, count))
1764
2031
 
1765
2032
    def _serialise_search_result(self, search_result):
1766
 
        if isinstance(search_result, graph.PendingAncestryResult):
1767
 
            parts = ['ancestry-of']
1768
 
            parts.extend(search_result.heads)
1769
 
        else:
1770
 
            recipe = search_result.get_recipe()
1771
 
            parts = [recipe[0], self._serialise_search_recipe(recipe)]
 
2033
        parts = search_result.get_network_struct()
1772
2034
        return '\n'.join(parts)
1773
2035
 
1774
2036
    def autopack(self):
1784
2046
            raise errors.UnexpectedSmartServerResponse(response)
1785
2047
 
1786
2048
 
1787
 
class RemoteStreamSink(repository.StreamSink):
 
2049
class RemoteStreamSink(vf_repository.StreamSink):
1788
2050
 
1789
2051
    def _insert_real(self, stream, src_format, resume_tokens):
1790
2052
        self.target_repo._ensure_real()
1891
2153
        self._last_substream and self._last_stream so that the stream can be
1892
2154
        resumed by _resume_stream_with_vfs.
1893
2155
        """
1894
 
                    
 
2156
 
1895
2157
        stream_iter = iter(stream)
1896
2158
        for substream_kind, substream in stream_iter:
1897
2159
            if substream_kind == 'inventory-deltas':
1900
2162
                return
1901
2163
            else:
1902
2164
                yield substream_kind, substream
1903
 
            
1904
 
 
1905
 
class RemoteStreamSource(repository.StreamSource):
 
2165
 
 
2166
 
 
2167
class RemoteStreamSource(vf_repository.StreamSource):
1906
2168
    """Stream data from a remote server."""
1907
2169
 
1908
2170
    def get_stream(self, search):
1968
2230
        candidate_verbs = [
1969
2231
            ('Repository.get_stream_1.19', (1, 19)),
1970
2232
            ('Repository.get_stream', (1, 13))]
 
2233
 
1971
2234
        found_verb = False
1972
2235
        for verb, version in candidate_verbs:
1973
2236
            if medium._is_remote_before(version):
1977
2240
                    verb, args, search_bytes)
1978
2241
            except errors.UnknownSmartMethod:
1979
2242
                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
1980
2254
            else:
1981
2255
                response_tuple, response_handler = response
1982
2256
                found_verb = True
2103
2377
            network_name = self._custom_format.network_name()
2104
2378
        else:
2105
2379
            # Select the current bzrlib default and ask for that.
2106
 
            reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
2380
            reference_bzrdir_format = _mod_bzrdir.format_registry.get('default')()
2107
2381
            reference_format = reference_bzrdir_format.get_branch_format()
2108
2382
            self._custom_format = reference_format
2109
2383
            network_name = reference_format.network_name()
2176
2450
        self._ensure_real()
2177
2451
        return self._custom_format.supports_set_append_revisions_only()
2178
2452
 
 
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
2179
2466
 
2180
2467
class RemoteBranch(branch.Branch, _RpcHelper, lock._RelockDebugMixin):
2181
2468
    """Branch stored on a server accessed by HPSS RPC.
2380
2667
            self._is_stacked = False
2381
2668
        else:
2382
2669
            self._is_stacked = True
2383
 
        
 
2670
 
2384
2671
    def _vfs_get_tags_bytes(self):
2385
2672
        self._ensure_real()
2386
2673
        return self._real_branch._get_tags_bytes()
2568
2855
            missing_parent = parent_map[missing_parent]
2569
2856
        raise errors.RevisionNotPresent(missing_parent, self.repository)
2570
2857
 
2571
 
    def _last_revision_info(self):
 
2858
    def _read_last_revision_info(self):
2572
2859
        response = self._call('Branch.last_revision_info', self._remote_path())
2573
2860
        if response[0] != 'ok':
2574
2861
            raise SmartProtocolError('unexpected response code %s' % (response,))
2637
2924
            raise errors.UnexpectedSmartServerResponse(response)
2638
2925
        self._run_post_change_branch_tip_hooks(old_revno, old_revid)
2639
2926
 
 
2927
    @symbol_versioning.deprecated_method(symbol_versioning.deprecated_in((2, 4, 0)))
2640
2928
    @needs_write_lock
2641
2929
    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):
2642
2935
        # Send just the tip revision of the history; the server will generate
2643
2936
        # the full history from that.  If the revision doesn't exist in this
2644
2937
        # branch, NoSuchRevision will be raised.
2702
2995
            _override_hook_target=self, **kwargs)
2703
2996
 
2704
2997
    @needs_read_lock
2705
 
    def push(self, target, overwrite=False, stop_revision=None):
 
2998
    def push(self, target, overwrite=False, stop_revision=None, lossy=False):
2706
2999
        self._ensure_real()
2707
3000
        return self._real_branch.push(
2708
 
            target, overwrite=overwrite, stop_revision=stop_revision,
 
3001
            target, overwrite=overwrite, stop_revision=stop_revision, lossy=lossy,
2709
3002
            _override_hook_source_branch=self)
2710
3003
 
2711
3004
    def is_locked(self):
2721
3014
        # XXX: These should be returned by the set_last_revision_info verb
2722
3015
        old_revno, old_revid = self.last_revision_info()
2723
3016
        self._run_pre_change_branch_tip_hooks(revno, revision_id)
2724
 
        revision_id = ensure_null(revision_id)
 
3017
        if not revision_id or not isinstance(revision_id, basestring):
 
3018
            raise errors.InvalidRevisionId(revision_id=revision_id, branch=self)
2725
3019
        try:
2726
3020
            response = self._call('Branch.set_last_revision_info',
2727
3021
                self._remote_path(), self._lock_token, self._repo_lock_token,
2756
3050
            except errors.UnknownSmartMethod:
2757
3051
                medium._remember_remote_is_before((1, 6))
2758
3052
        self._clear_cached_state_of_remote_branch_only()
2759
 
        self.set_revision_history(self._lefthand_history(revision_id,
 
3053
        self._set_revision_history(self._lefthand_history(revision_id,
2760
3054
            last_rev=last_rev,other_branch=other_branch))
2761
3055
 
2762
3056
    def set_push_location(self, location):
2763
3057
        self._ensure_real()
2764
3058
        return self._real_branch.set_push_location(location)
2765
3059
 
 
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
 
2766
3087
 
2767
3088
class RemoteConfig(object):
2768
3089
    """A Config that reads and writes from smart verbs.
2782
3103
        """
2783
3104
        try:
2784
3105
            configobj = self._get_configobj()
 
3106
            section_obj = None
2785
3107
            if section is None:
2786
3108
                section_obj = configobj
2787
3109
            else:
2788
3110
                try:
2789
3111
                    section_obj = configobj[section]
2790
3112
                except KeyError:
2791
 
                    return default
2792
 
            return section_obj.get(name, default)
 
3113
                    pass
 
3114
            if section_obj is None:
 
3115
                value = default
 
3116
            else:
 
3117
                value = section_obj.get(name, default)
2793
3118
        except errors.UnknownSmartMethod:
2794
 
            return self._vfs_get_option(name, section, default)
 
3119
            value = self._vfs_get_option(name, section, default)
 
3120
        for hook in config.OldConfigHooks['get']:
 
3121
            hook(self, name, value)
 
3122
        return value
2795
3123
 
2796
3124
    def _response_to_configobj(self, response):
2797
3125
        if len(response[0]) and response[0][0] != 'ok':
2798
3126
            raise errors.UnexpectedSmartServerResponse(response)
2799
3127
        lines = response[1].read_body_bytes().splitlines()
2800
 
        return config.ConfigObj(lines, encoding='utf-8')
 
3128
        conf = config.ConfigObj(lines, encoding='utf-8')
 
3129
        for hook in config.OldConfigHooks['load']:
 
3130
            hook(self)
 
3131
        return conf
2801
3132
 
2802
3133
 
2803
3134
class RemoteBranchConfig(RemoteConfig):
2955
3286
                    'Missing key %r in context %r', key_err.args[0], context)
2956
3287
                raise err
2957
3288
 
2958
 
    if err.error_verb == 'IncompatibleRepositories':
2959
 
        raise errors.IncompatibleRepositories(err.error_args[0],
2960
 
            err.error_args[1], err.error_args[2])
2961
 
    elif err.error_verb == 'NoSuchRevision':
 
3289
    if err.error_verb == 'NoSuchRevision':
2962
3290
        raise NoSuchRevision(find('branch'), err.error_args[0])
2963
3291
    elif err.error_verb == 'nosuchrevision':
2964
3292
        raise NoSuchRevision(find('repository'), err.error_args[0])
2971
3299
            detail=extra)
2972
3300
    elif err.error_verb == 'norepository':
2973
3301
        raise errors.NoRepositoryPresent(find('bzrdir'))
2974
 
    elif err.error_verb == 'LockContention':
2975
 
        raise errors.LockContention('(remote lock)')
2976
3302
    elif err.error_verb == 'UnlockableTransport':
2977
3303
        raise errors.UnlockableTransport(find('bzrdir').root_transport)
2978
 
    elif err.error_verb == 'LockFailed':
2979
 
        raise errors.LockFailed(err.error_args[0], err.error_args[1])
2980
3304
    elif err.error_verb == 'TokenMismatch':
2981
3305
        raise errors.TokenMismatch(find('token'), '(remote token)')
2982
3306
    elif err.error_verb == 'Diverged':
2983
3307
        raise errors.DivergedBranches(find('branch'), find('other_branch'))
2984
 
    elif err.error_verb == 'TipChangeRejected':
2985
 
        raise errors.TipChangeRejected(err.error_args[0].decode('utf8'))
2986
 
    elif err.error_verb == 'UnstackableBranchFormat':
2987
 
        raise errors.UnstackableBranchFormat(*err.error_args)
2988
 
    elif err.error_verb == 'UnstackableRepositoryFormat':
2989
 
        raise errors.UnstackableRepositoryFormat(*err.error_args)
2990
3308
    elif err.error_verb == 'NotStacked':
2991
3309
        raise errors.NotStacked(branch=find('branch'))
2992
3310
    elif err.error_verb == 'PermissionDenied':
3002
3320
    elif err.error_verb == 'NoSuchFile':
3003
3321
        path = get_path()
3004
3322
        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)
3005
3341
    elif err.error_verb == 'FileExists':
3006
3342
        raise errors.FileExists(err.error_args[0])
3007
3343
    elif err.error_verb == 'DirectoryNotEmpty':
3026
3362
            raise UnicodeEncodeError(encoding, val, start, end, reason)
3027
3363
    elif err.error_verb == 'ReadOnlyError':
3028
3364
        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.")
3029
3368
    raise errors.UnknownErrorFromSmartServer(err)