/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 remote.py

SupportĀ limitĀ argument.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
from bzrlib import (
18
18
    config,
19
19
    debug,
20
 
    tag,
21
20
    trace,
22
21
    ui,
23
22
    urlutils,
 
23
    version_info as bzrlib_version,
24
24
    )
25
25
from bzrlib.errors import (
26
26
    BzrError,
 
27
    InProcessTransport,
27
28
    InvalidRevisionId,
28
29
    NoSuchFile,
29
30
    NoSuchRevision,
 
31
    NotBranchError,
30
32
    NotLocalUrl,
 
33
    UninitializableFormat,
31
34
    )
32
35
from bzrlib.transport import (
33
36
    Transport,
40
43
 
41
44
from bzrlib.plugins.git.branch import (
42
45
    GitBranch,
 
46
    GitTags,
 
47
    )
 
48
from bzrlib.plugins.git.dir import (
 
49
    GitControlDirFormat,
 
50
    GitDir,
43
51
    )
44
52
from bzrlib.plugins.git.errors import (
45
53
    GitSmartRemoteNotSupported,
46
54
    NoSuchRef,
47
55
    )
48
 
from bzrlib.plugins.git.dir import (
49
 
    GitDir,
50
 
    )
51
56
from bzrlib.plugins.git.mapping import (
52
57
    mapping_registry,
53
58
    )
55
60
    GitRepository,
56
61
    )
57
62
from bzrlib.plugins.git.refs import (
58
 
    extract_tags,
59
63
    branch_name_to_ref,
 
64
    is_peeled,
60
65
    )
61
66
 
62
 
import dulwich as git
 
67
import dulwich
 
68
import dulwich.client
63
69
from dulwich.errors import (
64
70
    GitProtocolError,
65
71
    )
66
72
from dulwich.pack import (
67
73
    Pack,
68
 
    ThinPackData,
 
74
    PackData,
69
75
    )
 
76
from dulwich.repo import DictRefsContainer
70
77
import os
71
78
import tempfile
72
79
import urllib
97
104
    return (host, port, username, path)
98
105
 
99
106
 
 
107
def parse_git_error(url, message):
 
108
    """Parse a remote git server error and return a bzr exception.
 
109
 
 
110
    :param url: URL of the remote repository
 
111
    :param message: Message sent by the remote git server
 
112
    """
 
113
    message = str(message).strip()
 
114
    if message.startswith("Could not find Repository "):
 
115
        return NotBranchError(url, message)
 
116
    # Don't know, just return it to the user as-is
 
117
    return BzrError(message)
 
118
 
 
119
 
100
120
class GitSmartTransport(Transport):
101
121
 
102
122
    def __init__(self, url, _client=None):
107
127
            trace.mutter('host: %r, user: %r, port: %r, path: %r',
108
128
                         self._host, self._username, self._port, self._path)
109
129
        self._client = _client
 
130
        if "," in self._path and bzrlib_version < (2, 5, 0):
 
131
            trace.warning(
 
132
                "ignoring parameters %r, not supported in bzr < 2.5.",
 
133
                self._path.rsplit(",", 1)[1])
 
134
        self._stripped_path = self._path.rsplit(",", 1)[0]
110
135
 
111
136
    def external_url(self):
112
137
        return self.base
118
143
        raise NotImplementedError(self._get_client)
119
144
 
120
145
    def _get_path(self):
121
 
        return self._path
122
 
 
123
 
    def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
124
 
        if progress is None:
125
 
            def progress(text):
126
 
                trace.info("git: %s" % text)
127
 
        client = self._get_client(thin_packs=False)
128
 
        try:
129
 
            return client.fetch_pack(self._get_path(), determine_wants,
130
 
                graph_walker, pack_data, progress)
131
 
        except GitProtocolError, e:
132
 
            raise BzrError(e)
133
 
 
134
 
    def send_pack(self, get_changed_refs, generate_pack_contents):
135
 
        client = self._get_client(thin_packs=False)
136
 
        try:
137
 
            return client.send_pack(self._get_path(), get_changed_refs,
138
 
                generate_pack_contents)
139
 
        except GitProtocolError, e:
140
 
            raise BzrError(e)
 
146
        return self._stripped_path
141
147
 
142
148
    def get(self, path):
143
149
        raise NoSuchFile(path)
164
170
            ret = self._client
165
171
            self._client = None
166
172
            return ret
167
 
        return git.client.TCPGitClient(self._host, self._port,
 
173
        return dulwich.client.TCPGitClient(self._host, self._port,
168
174
            thin_packs=thin_packs, report_activity=self._report_activity)
169
175
 
170
176
 
173
179
    _scheme = 'git+ssh'
174
180
 
175
181
    def _get_path(self):
176
 
        if self._path.startswith("/~/"):
177
 
            return self._path[3:]
178
 
        return self._path
 
182
        path = self._stripped_path
 
183
        if path.startswith("/~/"):
 
184
            return path[3:]
 
185
        return path
179
186
 
180
187
    def _get_client(self, thin_packs):
181
188
        if self._client is not None:
183
190
            self._client = None
184
191
            return ret
185
192
        location_config = config.LocationConfig(self.base)
186
 
        client = git.client.SSHGitClient(self._host, self._port, self._username,
 
193
        client = dulwich.client.SSHGitClient(self._host, self._port, self._username,
187
194
            thin_packs=thin_packs, report_activity=self._report_activity)
188
195
        # Set up alternate pack program paths
189
196
        upload_pack = location_config.get_user_option('git_upload_pack')
197
204
 
198
205
class RemoteGitDir(GitDir):
199
206
 
200
 
    def __init__(self, transport, lockfiles, format):
 
207
    def __init__(self, transport, format, get_client, client_path):
201
208
        self._format = format
202
209
        self.root_transport = transport
203
210
        self.transport = transport
204
 
        self._lockfiles = lockfiles
205
211
        self._mode_check_done = None
206
 
 
207
 
    def _branch_name_to_ref(self, name, default=None):
208
 
        return branch_name_to_ref(name, default=default)
 
212
        self._get_client = get_client
 
213
        self._client_path = client_path
 
214
        self.base = self.root_transport.base
 
215
        self._refs = None
 
216
 
 
217
    def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
 
218
        if progress is None:
 
219
            def progress(text):
 
220
                trace.info("git: %s" % text)
 
221
        def wrap_determine_wants(refs_dict):
 
222
            return determine_wants(remote_refs_dict_to_container(refs_dict))
 
223
        client = self._get_client(thin_packs=False)
 
224
        try:
 
225
            refs_dict = client.fetch_pack(self._client_path, wrap_determine_wants,
 
226
                graph_walker, pack_data, progress)
 
227
            self._refs = remote_refs_dict_to_container(refs_dict)
 
228
            return refs_dict
 
229
        except GitProtocolError, e:
 
230
            raise parse_git_error(self.transport.external_url(), e)
 
231
 
 
232
    def send_pack(self, get_changed_refs, generate_pack_contents):
 
233
        client = self._get_client(thin_packs=False)
 
234
        try:
 
235
            return client.send_pack(self._client_path, get_changed_refs,
 
236
                generate_pack_contents)
 
237
        except GitProtocolError, e:
 
238
            raise parse_git_error(self.transport.external_url(), e)
 
239
 
 
240
    def destroy_branch(self, name=None):
 
241
        refname = self._get_selected_ref(name)
 
242
        if refname is None:
 
243
            refname = "HEAD"
 
244
        def get_changed_refs(old_refs):
 
245
            ret = dict(old_refs)
 
246
            if not refname in ret:
 
247
                raise NotBranchError(self.user_url)
 
248
            ret[refname] = "00" * 20
 
249
            return ret
 
250
        self.send_pack(get_changed_refs, lambda have, want: [])
 
251
 
 
252
    @property
 
253
    def user_url(self):
 
254
        return self.control_url
 
255
 
 
256
    @property
 
257
    def user_transport(self):
 
258
        return self.root_transport
 
259
 
 
260
    @property
 
261
    def control_url(self):
 
262
        return self.control_transport.base
 
263
 
 
264
    @property
 
265
    def control_transport(self):
 
266
        return self.root_transport
209
267
 
210
268
    def open_repository(self):
211
 
        return RemoteGitRepository(self, self._lockfiles)
 
269
        return RemoteGitRepository(self)
212
270
 
213
 
    def _open_branch(self, name=None, ignore_fallbacks=False, 
214
 
                    unsupported=False):
 
271
    def open_branch(self, name=None, unsupported=False,
 
272
            ignore_fallbacks=False, ref=None, possible_transports=None):
215
273
        repo = self.open_repository()
216
 
        refname = self._branch_name_to_ref(name)
217
 
        return RemoteGitBranch(self, repo, refname, self._lockfiles)
 
274
        refname = self._get_selected_ref(name, ref)
 
275
        return RemoteGitBranch(self, repo, refname)
218
276
 
219
277
    def open_workingtree(self, recommend_upgrade=False):
220
278
        raise NotLocalUrl(self.transport.base)
221
279
 
 
280
    def get_peeled(self, name):
 
281
        return self.get_refs_container().get_peeled(name)
 
282
 
 
283
    def get_refs_container(self):
 
284
        if self._refs is not None:
 
285
            return self._refs
 
286
        refs_dict = self.fetch_pack(lambda x: [], None,
 
287
            lambda x: None, lambda x: trace.mutter("git: %s" % x))
 
288
        self._refs = remote_refs_dict_to_container(refs_dict)
 
289
        return self._refs
 
290
 
222
291
 
223
292
class EmptyObjectStoreIterator(dict):
224
293
 
235
304
    @property
236
305
    def data(self):
237
306
        if self._data is None:
238
 
            self._data = ThinPackData(self.resolve_ext_ref, self._data_path)
 
307
            self._data = PackData(self._data_path)
239
308
        return self._data
240
309
 
241
310
    @property
262
331
            os.remove(self._data_path)
263
332
 
264
333
 
 
334
class BzrGitHttpClient(dulwich.client.HttpGitClient):
 
335
 
 
336
    def __init__(self, transport, *args, **kwargs):
 
337
        self.transport = transport
 
338
        super(BzrGitHttpClient, self).__init__(transport.external_url(), *args, **kwargs)
 
339
        import urllib2
 
340
        self._http_perform = getattr(self.transport, "_perform", urllib2.urlopen)
 
341
 
 
342
    def _perform(self, req):
 
343
        req.accepted_errors = (200, 404)
 
344
        req.follow_redirections = True
 
345
        req.redirected_to = None
 
346
        return self._http_perform(req)
 
347
 
 
348
 
 
349
class RemoteGitControlDirFormat(GitControlDirFormat):
 
350
    """The .git directory control format."""
 
351
 
 
352
    supports_workingtrees = False
 
353
 
 
354
    @classmethod
 
355
    def _known_formats(self):
 
356
        return set([RemoteGitControlDirFormat()])
 
357
 
 
358
    def is_initializable(self):
 
359
        return False
 
360
 
 
361
    def is_supported(self):
 
362
        return True
 
363
 
 
364
    def open(self, transport, _found=None):
 
365
        """Open this directory.
 
366
 
 
367
        """
 
368
        # we dont grok readonly - git isn't integrated with transport.
 
369
        url = transport.base
 
370
        if url.startswith('readonly+'):
 
371
            url = url[len('readonly+'):]
 
372
        if isinstance(transport, GitSmartTransport):
 
373
            get_client = transport._get_client
 
374
            client_path = transport._get_path()
 
375
        elif urlparse.urlsplit(transport.external_url())[0] in ("http", "https"):
 
376
            def get_client(thin_packs=False):
 
377
                return BzrGitHttpClient(transport, thin_packs=thin_packs)
 
378
            client_path = transport._path
 
379
        else:
 
380
            raise NotBranchError(transport.base)
 
381
        return RemoteGitDir(transport, self, get_client, client_path)
 
382
 
 
383
    def get_format_description(self):
 
384
        return "Remote Git Repository"
 
385
 
 
386
    def initialize_on_transport(self, transport):
 
387
        raise UninitializableFormat(self)
 
388
 
 
389
    def supports_transport(self, transport):
 
390
        try:
 
391
            external_url = transport.external_url()
 
392
        except InProcessTransport:
 
393
            raise NotBranchError(path=transport.base)
 
394
        return (external_url.startswith("http:") or
 
395
                external_url.startswith("https:") or
 
396
                external_url.startswith("git+") or
 
397
                external_url.startswith("git:"))
 
398
 
 
399
 
265
400
class RemoteGitRepository(GitRepository):
266
401
 
267
 
    def __init__(self, gitdir, lockfiles):
268
 
        GitRepository.__init__(self, gitdir, lockfiles)
269
 
        self._refs = None
270
 
 
271
 
    @property
272
 
    def inventories(self):
273
 
        raise GitSmartRemoteNotSupported()
274
 
 
275
 
    @property
276
 
    def revisions(self):
277
 
        raise GitSmartRemoteNotSupported()
278
 
 
279
 
    @property
280
 
    def texts(self):
281
 
        raise GitSmartRemoteNotSupported()
282
 
 
283
 
    def get_refs(self):
284
 
        if self._refs is not None:
285
 
            return self._refs
286
 
        self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
287
 
            lambda x: None, lambda x: trace.mutter("git: %s" % x))
288
 
        return self._refs
 
402
    @property
 
403
    def user_url(self):
 
404
        return self.control_url
 
405
 
 
406
    def get_parent_map(self, revids):
 
407
        raise GitSmartRemoteNotSupported(self.get_parent_map, self)
289
408
 
290
409
    def fetch_pack(self, determine_wants, graph_walker, pack_data,
291
410
                   progress=None):
292
 
        return self._transport.fetch_pack(determine_wants, graph_walker,
 
411
        return self.bzrdir.fetch_pack(determine_wants, graph_walker,
293
412
                                          pack_data, progress)
294
413
 
295
414
    def send_pack(self, get_changed_refs, generate_pack_contents):
296
 
        return self._transport.send_pack(get_changed_refs, generate_pack_contents)
 
415
        return self.bzrdir.send_pack(get_changed_refs, generate_pack_contents)
297
416
 
298
417
    def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref,
299
418
                      progress=None):
300
419
        fd, path = tempfile.mkstemp(suffix=".pack")
301
 
        self.fetch_pack(determine_wants, graph_walker,
302
 
            lambda x: os.write(fd, x), progress)
303
 
        os.close(fd)
 
420
        try:
 
421
            self.fetch_pack(determine_wants, graph_walker,
 
422
                lambda x: os.write(fd, x), progress)
 
423
        finally:
 
424
            os.close(fd)
304
425
        if os.path.getsize(path) == 0:
305
426
            return EmptyObjectStoreIterator()
306
427
        return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
321
442
        # Not really an easy way to parse foreign revids here..
322
443
        return mapping.revision_id_foreign_to_bzr(foreign_revid)
323
444
 
324
 
 
325
 
class RemoteGitTagDict(tag.BasicTags):
326
 
 
327
 
    def __init__(self, branch):
328
 
        self.branch = branch
329
 
        self.repository = branch.repository
330
 
 
331
 
    def get_tag_dict(self):
332
 
        tags = {}
333
 
        for k, v in extract_tags(self.repository.get_refs()).iteritems():
334
 
            tags[k] = self.branch.mapping.revision_id_foreign_to_bzr(v)
335
 
        return tags
 
445
    def revision_tree(self, revid):
 
446
        raise GitSmartRemoteNotSupported(self.revision_tree, self)
 
447
 
 
448
    def get_revisions(self, revids):
 
449
        raise GitSmartRemoteNotSupported(self.get_revisions, self)
 
450
 
 
451
 
 
452
class RemoteGitTagDict(GitTags):
 
453
 
 
454
    def get_refs_container(self):
 
455
        return self.repository.bzrdir.get_refs_container()
336
456
 
337
457
    def set_tag(self, name, revid):
338
458
        # FIXME: Not supported yet, should do a push of a new ref
341
461
 
342
462
class RemoteGitBranch(GitBranch):
343
463
 
344
 
    def __init__(self, bzrdir, repository, name, lockfiles):
 
464
    def __init__(self, bzrdir, repository, name):
345
465
        self._sha = None
346
 
        super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
347
 
                lockfiles)
 
466
        super(RemoteGitBranch, self).__init__(bzrdir, repository, name)
 
467
 
 
468
    def last_revision_info(self):
 
469
        raise GitSmartRemoteNotSupported(self.last_revision_info, self)
 
470
 
 
471
    @property
 
472
    def user_url(self):
 
473
        return self.control_url
 
474
 
 
475
    @property
 
476
    def control_url(self):
 
477
        return self.base
348
478
 
349
479
    def revision_history(self):
350
 
        raise GitSmartRemoteNotSupported()
 
480
        raise GitSmartRemoteNotSupported(self.revision_history, self)
 
481
 
 
482
    def revision_id_to_revno(self, revision_id):
 
483
        raise GitSmartRemoteNotSupported(self.revision_id_to_revno, self)
351
484
 
352
485
    def last_revision(self):
353
486
        return self.lookup_foreign_revision_id(self.head)
354
487
 
355
 
    def _get_config(self):
356
 
        class EmptyConfig(object):
357
 
 
358
 
            def _get_configobj(self):
359
 
                return config.ConfigObj()
360
 
 
361
 
        return EmptyConfig()
362
 
 
363
488
    @property
364
489
    def head(self):
365
490
        if self._sha is not None:
366
491
            return self._sha
367
 
        heads = self.repository.get_refs()
368
 
        name = self.bzrdir._branch_name_to_ref(self.name, "HEAD")
369
 
        if name in heads:
370
 
            self._sha = heads[name]
371
 
        else:
372
 
            raise NoSuchRef(self.name)
 
492
        refs = self.bzrdir.get_refs_container()
 
493
        name = branch_name_to_ref(self.name, "HEAD")
 
494
        try:
 
495
            self._sha = refs[name]
 
496
        except KeyError:
 
497
            raise NoSuchRef(name, self.repository.user_url, refs)
373
498
        return self._sha
374
499
 
375
500
    def _synchronize_history(self, destination, revision_id):
381
506
 
382
507
    def set_push_location(self, url):
383
508
        pass
 
509
 
 
510
 
 
511
def remote_refs_dict_to_container(refs_dict):
 
512
    base = {}
 
513
    peeled = {}
 
514
    for k, v in refs_dict.iteritems():
 
515
        if is_peeled(k):
 
516
            peeled[k[:-3]] = v
 
517
        else:
 
518
            base[k] = v
 
519
            peeled[k] = v
 
520
    ret = DictRefsContainer(base)
 
521
    ret._peeled = peeled
 
522
    return ret