~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/remote.py

  • Committer: Jelmer Vernooij
  • Date: 2011-03-10 16:00:38 UTC
  • mto: (5712.4.8 bzrdir-weave)
  • mto: This revision was merged to the branch mainline in revision 5716.
  • Revision ID: jelmer@samba.org-20110310160038-qrff0b1ezht4pcj0
Add Prober.known_formats().

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
)
38
36
from bzrlib.branch import BranchReferenceFormat, BranchWriteLockResult
39
 
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
40
37
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
41
38
from bzrlib.errors import (
42
39
    NoSuchRevision,
44
41
    )
45
42
from bzrlib.lockable_files import LockableFiles
46
43
from bzrlib.smart import client, vfs, repository as smart_repo
47
 
from bzrlib.revision import ensure_null, NULL_REVISION
 
44
from bzrlib.revision import NULL_REVISION
48
45
from bzrlib.repository import RepositoryWriteLockResult
49
46
from bzrlib.trace import mutter, note, warning
50
47
 
89
86
    return format
90
87
 
91
88
 
92
 
# Note: RemoteBzrDirFormat is in bzrdir.py
93
 
 
94
 
class RemoteBzrDir(BzrDir, _RpcHelper):
 
89
# Note that RemoteBzrDirProber lives in bzrlib.bzrdir so bzrlib.remote
 
90
# does not have to be imported unless a remote format is involved.
 
91
 
 
92
class RemoteBzrDirFormat(_mod_bzrdir.BzrDirMetaFormat1):
 
93
    """Format representing bzrdirs accessed via a smart server"""
 
94
 
 
95
    supports_workingtrees = False
 
96
 
 
97
    def __init__(self):
 
98
        super(RemoteBzrDirFormat, self).__init__()
 
99
        # XXX: It's a bit ugly that the network name is here, because we'd
 
100
        # like to believe that format objects are stateless or at least
 
101
        # immutable,  However, we do at least avoid mutating the name after
 
102
        # it's returned.  See <https://bugs.launchpad.net/bzr/+bug/504102>
 
103
        self._network_name = None
 
104
 
 
105
    def __repr__(self):
 
106
        return "%s(_network_name=%r)" % (self.__class__.__name__,
 
107
            self._network_name)
 
108
 
 
109
    def get_format_description(self):
 
110
        if self._network_name:
 
111
            real_format = controldir.network_format_registry.get(self._network_name)
 
112
            return 'Remote: ' + real_format.get_format_description()
 
113
        return 'bzr remote bzrdir'
 
114
 
 
115
    def get_format_string(self):
 
116
        raise NotImplementedError(self.get_format_string)
 
117
 
 
118
    def network_name(self):
 
119
        if self._network_name:
 
120
            return self._network_name
 
121
        else:
 
122
            raise AssertionError("No network name set.")
 
123
 
 
124
    def initialize_on_transport(self, transport):
 
125
        try:
 
126
            # hand off the request to the smart server
 
127
            client_medium = transport.get_smart_medium()
 
128
        except errors.NoSmartMedium:
 
129
            # TODO: lookup the local format from a server hint.
 
130
            local_dir_format = _mod_bzrdir.BzrDirMetaFormat1()
 
131
            return local_dir_format.initialize_on_transport(transport)
 
132
        client = _SmartClient(client_medium)
 
133
        path = client.remote_path_from_transport(transport)
 
134
        try:
 
135
            response = client.call('BzrDirFormat.initialize', path)
 
136
        except errors.ErrorFromSmartServer, err:
 
137
            _translate_error(err, path=path)
 
138
        if response[0] != 'ok':
 
139
            raise errors.SmartProtocolError('unexpected response code %s' % (response,))
 
140
        format = RemoteBzrDirFormat()
 
141
        self._supply_sub_formats_to(format)
 
142
        return RemoteBzrDir(transport, format)
 
143
 
 
144
    def parse_NoneTrueFalse(self, arg):
 
145
        if not arg:
 
146
            return None
 
147
        if arg == 'False':
 
148
            return False
 
149
        if arg == 'True':
 
150
            return True
 
151
        raise AssertionError("invalid arg %r" % arg)
 
152
 
 
153
    def _serialize_NoneTrueFalse(self, arg):
 
154
        if arg is False:
 
155
            return 'False'
 
156
        if arg:
 
157
            return 'True'
 
158
        return ''
 
159
 
 
160
    def _serialize_NoneString(self, arg):
 
161
        return arg or ''
 
162
 
 
163
    def initialize_on_transport_ex(self, transport, use_existing_dir=False,
 
164
        create_prefix=False, force_new_repo=False, stacked_on=None,
 
165
        stack_on_pwd=None, repo_format_name=None, make_working_trees=None,
 
166
        shared_repo=False):
 
167
        try:
 
168
            # hand off the request to the smart server
 
169
            client_medium = transport.get_smart_medium()
 
170
        except errors.NoSmartMedium:
 
171
            do_vfs = True
 
172
        else:
 
173
            # Decline to open it if the server doesn't support our required
 
174
            # version (3) so that the VFS-based transport will do it.
 
175
            if client_medium.should_probe():
 
176
                try:
 
177
                    server_version = client_medium.protocol_version()
 
178
                    if server_version != '2':
 
179
                        do_vfs = True
 
180
                    else:
 
181
                        do_vfs = False
 
182
                except errors.SmartProtocolError:
 
183
                    # Apparently there's no usable smart server there, even though
 
184
                    # the medium supports the smart protocol.
 
185
                    do_vfs = True
 
186
            else:
 
187
                do_vfs = False
 
188
        if not do_vfs:
 
189
            client = _SmartClient(client_medium)
 
190
            path = client.remote_path_from_transport(transport)
 
191
            if client_medium._is_remote_before((1, 16)):
 
192
                do_vfs = True
 
193
        if do_vfs:
 
194
            # TODO: lookup the local format from a server hint.
 
195
            local_dir_format = _mod_bzrdir.BzrDirMetaFormat1()
 
196
            self._supply_sub_formats_to(local_dir_format)
 
197
            return local_dir_format.initialize_on_transport_ex(transport,
 
198
                use_existing_dir=use_existing_dir, create_prefix=create_prefix,
 
199
                force_new_repo=force_new_repo, stacked_on=stacked_on,
 
200
                stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
 
201
                make_working_trees=make_working_trees, shared_repo=shared_repo,
 
202
                vfs_only=True)
 
203
        return self._initialize_on_transport_ex_rpc(client, path, transport,
 
204
            use_existing_dir, create_prefix, force_new_repo, stacked_on,
 
205
            stack_on_pwd, repo_format_name, make_working_trees, shared_repo)
 
206
 
 
207
    def _initialize_on_transport_ex_rpc(self, client, path, transport,
 
208
        use_existing_dir, create_prefix, force_new_repo, stacked_on,
 
209
        stack_on_pwd, repo_format_name, make_working_trees, shared_repo):
 
210
        args = []
 
211
        args.append(self._serialize_NoneTrueFalse(use_existing_dir))
 
212
        args.append(self._serialize_NoneTrueFalse(create_prefix))
 
213
        args.append(self._serialize_NoneTrueFalse(force_new_repo))
 
214
        args.append(self._serialize_NoneString(stacked_on))
 
215
        # stack_on_pwd is often/usually our transport
 
216
        if stack_on_pwd:
 
217
            try:
 
218
                stack_on_pwd = transport.relpath(stack_on_pwd)
 
219
                if not stack_on_pwd:
 
220
                    stack_on_pwd = '.'
 
221
            except errors.PathNotChild:
 
222
                pass
 
223
        args.append(self._serialize_NoneString(stack_on_pwd))
 
224
        args.append(self._serialize_NoneString(repo_format_name))
 
225
        args.append(self._serialize_NoneTrueFalse(make_working_trees))
 
226
        args.append(self._serialize_NoneTrueFalse(shared_repo))
 
227
        request_network_name = self._network_name or \
 
228
            _mod_bzrdir.BzrDirFormat.get_default_format().network_name()
 
229
        try:
 
230
            response = client.call('BzrDirFormat.initialize_ex_1.16',
 
231
                request_network_name, path, *args)
 
232
        except errors.UnknownSmartMethod:
 
233
            client._medium._remember_remote_is_before((1,16))
 
234
            local_dir_format = _mod_bzrdir.BzrDirMetaFormat1()
 
235
            self._supply_sub_formats_to(local_dir_format)
 
236
            return local_dir_format.initialize_on_transport_ex(transport,
 
237
                use_existing_dir=use_existing_dir, create_prefix=create_prefix,
 
238
                force_new_repo=force_new_repo, stacked_on=stacked_on,
 
239
                stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
 
240
                make_working_trees=make_working_trees, shared_repo=shared_repo,
 
241
                vfs_only=True)
 
242
        except errors.ErrorFromSmartServer, err:
 
243
            _translate_error(err, path=path)
 
244
        repo_path = response[0]
 
245
        bzrdir_name = response[6]
 
246
        require_stacking = response[7]
 
247
        require_stacking = self.parse_NoneTrueFalse(require_stacking)
 
248
        format = RemoteBzrDirFormat()
 
249
        format._network_name = bzrdir_name
 
250
        self._supply_sub_formats_to(format)
 
251
        bzrdir = RemoteBzrDir(transport, format, _client=client)
 
252
        if repo_path:
 
253
            repo_format = response_tuple_to_repo_format(response[1:])
 
254
            if repo_path == '.':
 
255
                repo_path = ''
 
256
            if repo_path:
 
257
                repo_bzrdir_format = RemoteBzrDirFormat()
 
258
                repo_bzrdir_format._network_name = response[5]
 
259
                repo_bzr = RemoteBzrDir(transport.clone(repo_path),
 
260
                    repo_bzrdir_format)
 
261
            else:
 
262
                repo_bzr = bzrdir
 
263
            final_stack = response[8] or None
 
264
            final_stack_pwd = response[9] or None
 
265
            if final_stack_pwd:
 
266
                final_stack_pwd = urlutils.join(
 
267
                    transport.base, final_stack_pwd)
 
268
            remote_repo = RemoteRepository(repo_bzr, repo_format)
 
269
            if len(response) > 10:
 
270
                # Updated server verb that locks remotely.
 
271
                repo_lock_token = response[10] or None
 
272
                remote_repo.lock_write(repo_lock_token, _skip_rpc=True)
 
273
                if repo_lock_token:
 
274
                    remote_repo.dont_leave_lock_in_place()
 
275
            else:
 
276
                remote_repo.lock_write()
 
277
            policy = UseExistingRepository(remote_repo, final_stack,
 
278
                final_stack_pwd, require_stacking)
 
279
            policy.acquire_repository()
 
280
        else:
 
281
            remote_repo = None
 
282
            policy = None
 
283
        bzrdir._format.set_branch_format(self.get_branch_format())
 
284
        if require_stacking:
 
285
            # The repo has already been created, but we need to make sure that
 
286
            # we'll make a stackable branch.
 
287
            bzrdir._format.require_stacking(_skip_repo=True)
 
288
        return remote_repo, bzrdir, require_stacking, policy
 
289
 
 
290
    def _open(self, transport):
 
291
        return RemoteBzrDir(transport, self)
 
292
 
 
293
    def __eq__(self, other):
 
294
        if not isinstance(other, RemoteBzrDirFormat):
 
295
            return False
 
296
        return self.get_format_description() == other.get_format_description()
 
297
 
 
298
    def __return_repository_format(self):
 
299
        # Always return a RemoteRepositoryFormat object, but if a specific bzr
 
300
        # repository format has been asked for, tell the RemoteRepositoryFormat
 
301
        # that it should use that for init() etc.
 
302
        result = RemoteRepositoryFormat()
 
303
        custom_format = getattr(self, '_repository_format', None)
 
304
        if custom_format:
 
305
            if isinstance(custom_format, RemoteRepositoryFormat):
 
306
                return custom_format
 
307
            else:
 
308
                # We will use the custom format to create repositories over the
 
309
                # wire; expose its details like rich_root_data for code to
 
310
                # query
 
311
                result._custom_format = custom_format
 
312
        return result
 
313
 
 
314
    def get_branch_format(self):
 
315
        result = _mod_bzrdir.BzrDirMetaFormat1.get_branch_format(self)
 
316
        if not isinstance(result, RemoteBranchFormat):
 
317
            new_result = RemoteBranchFormat()
 
318
            new_result._custom_format = result
 
319
            # cache the result
 
320
            self.set_branch_format(new_result)
 
321
            result = new_result
 
322
        return result
 
323
 
 
324
    repository_format = property(__return_repository_format,
 
325
        _mod_bzrdir.BzrDirMetaFormat1._set_repository_format) #.im_func)
 
326
 
 
327
 
 
328
class RemoteBzrDir(_mod_bzrdir.BzrDir, _RpcHelper):
95
329
    """Control directory on a remote server, accessed via bzr:// or similar."""
96
330
 
97
331
    def __init__(self, transport, format, _client=None, _force_probe=False):
100
334
        :param _client: Private parameter for testing. Disables probing and the
101
335
            use of a real bzrdir.
102
336
        """
103
 
        BzrDir.__init__(self, transport, format)
 
337
        _mod_bzrdir.BzrDir.__init__(self, transport, format)
104
338
        # this object holds a delegated bzrdir that uses file-level operations
105
339
        # to talk to the other side
106
340
        self._real_bzrdir = None
166
400
                import traceback
167
401
                warning('VFS BzrDir access triggered\n%s',
168
402
                    ''.join(traceback.format_stack()))
169
 
            self._real_bzrdir = BzrDir.open_from_transport(
 
403
            self._real_bzrdir = _mod_bzrdir.BzrDir.open_from_transport(
170
404
                self.root_transport, _server_formats=False)
171
405
            self._format._network_name = \
172
406
                self._real_bzrdir._format.network_name()
178
412
        # Prevent aliasing problems in the next_open_branch_result cache.
179
413
        # See create_branch for rationale.
180
414
        self._next_open_branch_result = None
181
 
        return BzrDir.break_lock(self)
 
415
        return _mod_bzrdir.BzrDir.break_lock(self)
182
416
 
183
417
    def _vfs_cloning_metadir(self, require_stacking=False):
184
418
        self._ensure_real()
217
451
        branch_ref, branch_name = branch_info
218
452
        format = controldir.network_format_registry.get(control_name)
219
453
        if repo_name:
220
 
            format.repository_format = repository.network_format_registry.get(
 
454
            format.repository_format = _mod_repository.network_format_registry.get(
221
455
                repo_name)
222
456
        if branch_ref == 'ref':
223
457
            # XXX: we need possible_transports here to avoid reopening the
224
458
            # connection to the referenced location
225
 
            ref_bzrdir = BzrDir.open(branch_name)
 
459
            ref_bzrdir = _mod_bzrdir.BzrDir.open(branch_name)
226
460
            branch_format = ref_bzrdir.cloning_metadir().get_branch_format()
227
461
            format.set_branch_format(branch_format)
228
462
        elif branch_ref == 'branch':
465
699
        return RemoteBzrDirConfig(self)
466
700
 
467
701
 
468
 
class RemoteRepositoryFormat(repository.RepositoryFormat):
 
702
class RemoteRepositoryFormat(_mod_repository.RepositoryFormat):
469
703
    """Format for repositories accessed over a _SmartClient.
470
704
 
471
705
    Instances of this repository are represented by RemoteRepository
490
724
    supports_leaving_lock = True
491
725
 
492
726
    def __init__(self):
493
 
        repository.RepositoryFormat.__init__(self)
 
727
        super(RemoteRepositoryFormat, self).__init__()
494
728
        self._custom_format = None
495
729
        self._network_name = None
496
730
        self._creating_bzrdir = None
587
821
            network_name = self._network_name
588
822
        else:
589
823
            # Select the current bzrlib default and ask for that.
590
 
            reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
824
            reference_bzrdir_format = _mod_bzrdir.format_registry.get('default')()
591
825
            reference_format = reference_bzrdir_format.repository_format
592
826
            network_name = reference_format.network_name()
593
827
        # 2) try direct creation via RPC
619
853
 
620
854
    def _ensure_real(self):
621
855
        if self._custom_format is None:
622
 
            self._custom_format = repository.network_format_registry.get(
 
856
            self._custom_format = _mod_repository.network_format_registry.get(
623
857
                self._network_name)
624
858
 
625
859
    @property
721
955
        # transport, but I'm not sure it's worth making this method
722
956
        # optional -- mbp 2010-04-21
723
957
        return self.bzrdir.get_repository_transport(None)
724
 
        
 
958
 
725
959
    def __str__(self):
726
960
        return "%s(%s)" % (self.__class__.__name__, self.base)
727
961
 
861
1095
        """Private method for using with old (< 1.2) servers to fallback."""
862
1096
        if revision_id is None:
863
1097
            revision_id = ''
864
 
        elif revision.is_null(revision_id):
 
1098
        elif _mod_revision.is_null(revision_id):
865
1099
            return {}
866
1100
 
867
1101
        path = self.bzrdir._path_for_remote_call(self._client)
948
1182
        """See Repository.gather_stats()."""
949
1183
        path = self.bzrdir._path_for_remote_call(self._client)
950
1184
        # revid can be None to indicate no revisions, not just NULL_REVISION
951
 
        if revid is None or revision.is_null(revid):
 
1185
        if revid is None or _mod_revision.is_null(revid):
952
1186
            fmt_revid = ''
953
1187
        else:
954
1188
            fmt_revid = revid
1375
1609
                    'revision_ids is mutually exclusive with revision_id')
1376
1610
            if revision_id is not None:
1377
1611
                revision_ids = [revision_id]
1378
 
        inter_repo = repository.InterRepository.get(other, self)
 
1612
        inter_repo = _mod_repository.InterRepository.get(other, self)
1379
1613
        return inter_repo.search_missing_revision_ids(
1380
1614
            find_ghosts=find_ghosts, revision_ids=revision_ids,
1381
1615
            if_present_ids=if_present_ids)
1397
1631
            # check that last_revision is in 'from' and then return a
1398
1632
            # no-operation.
1399
1633
            if (revision_id is not None and
1400
 
                not revision.is_null(revision_id)):
 
1634
                not _mod_revision.is_null(revision_id)):
1401
1635
                self.get_revision(revision_id)
1402
1636
            return 0, []
1403
1637
        # if there is no specific appropriate InterRepository, this will get
1404
1638
        # the InterRepository base class, which raises an
1405
1639
        # IncompatibleRepositories when asked to fetch.
1406
 
        inter = repository.InterRepository.get(source, self)
 
1640
        inter = _mod_repository.InterRepository.get(source, self)
1407
1641
        return inter.fetch(revision_id=revision_id,
1408
1642
            find_ghosts=find_ghosts, fetch_spec=fetch_spec)
1409
1643
 
1634
1868
            tmpdir = osutils.mkdtemp()
1635
1869
            try:
1636
1870
                _extract_tar(tar, tmpdir)
1637
 
                tmp_bzrdir = BzrDir.open(tmpdir)
 
1871
                tmp_bzrdir = _mod_bzrdir.BzrDir.open(tmpdir)
1638
1872
                tmp_repo = tmp_bzrdir.open_repository()
1639
1873
                tmp_repo.copy_content_into(destination, revision_id)
1640
1874
            finally:
1801
2035
            raise errors.UnexpectedSmartServerResponse(response)
1802
2036
 
1803
2037
 
1804
 
class RemoteStreamSink(repository.StreamSink):
 
2038
class RemoteStreamSink(_mod_repository.StreamSink):
1805
2039
 
1806
2040
    def _insert_real(self, stream, src_format, resume_tokens):
1807
2041
        self.target_repo._ensure_real()
1908
2142
        self._last_substream and self._last_stream so that the stream can be
1909
2143
        resumed by _resume_stream_with_vfs.
1910
2144
        """
1911
 
                    
 
2145
 
1912
2146
        stream_iter = iter(stream)
1913
2147
        for substream_kind, substream in stream_iter:
1914
2148
            if substream_kind == 'inventory-deltas':
1917
2151
                return
1918
2152
            else:
1919
2153
                yield substream_kind, substream
1920
 
            
1921
 
 
1922
 
class RemoteStreamSource(repository.StreamSource):
 
2154
 
 
2155
 
 
2156
class RemoteStreamSource(_mod_repository.StreamSource):
1923
2157
    """Stream data from a remote server."""
1924
2158
 
1925
2159
    def get_stream(self, search):
2132
2366
            network_name = self._custom_format.network_name()
2133
2367
        else:
2134
2368
            # Select the current bzrlib default and ask for that.
2135
 
            reference_bzrdir_format = bzrdir.format_registry.get('default')()
 
2369
            reference_bzrdir_format = _mod_bzrdir.format_registry.get('default')()
2136
2370
            reference_format = reference_bzrdir_format.get_branch_format()
2137
2371
            self._custom_format = reference_format
2138
2372
            network_name = reference_format.network_name()
2422
2656
            self._is_stacked = False
2423
2657
        else:
2424
2658
            self._is_stacked = True
2425
 
        
 
2659
 
2426
2660
    def _vfs_get_tags_bytes(self):
2427
2661
        self._ensure_real()
2428
2662
        return self._real_branch._get_tags_bytes()
2763
2997
        # XXX: These should be returned by the set_last_revision_info verb
2764
2998
        old_revno, old_revid = self.last_revision_info()
2765
2999
        self._run_pre_change_branch_tip_hooks(revno, revision_id)
2766
 
        revision_id = ensure_null(revision_id)
 
3000
        revision_id = _mod_revision.ensure_null(revision_id)
2767
3001
        try:
2768
3002
            response = self._call('Branch.set_last_revision_info',
2769
3003
                self._remote_path(), self._lock_token, self._repo_lock_token,