/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 breezy/git/__init__.py

  • Committer: Martin
  • Date: 2018-11-16 19:10:17 UTC
  • mto: This revision was merged to the branch mainline in revision 7177.
  • Revision ID: gzlist@googlemail.com-20181116191017-kyedz1qck0ovon3h
Remove lazy_regexp reset in bt.test_source

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006 Canonical Ltd
 
1
# Copyright (C) 2009-2018 Jelmer Vernooij <jelmer@jelmer.uk>
 
2
# Copyright (C) 2006-2009 Canonical Ltd
 
3
 
2
4
# Authors: Robert Collins <robert.collins@canonical.com>
 
5
#          Jelmer Vernooij <jelmer@jelmer.uk>
 
6
#          John Carr <john.carr@unrouted.co.uk>
3
7
#
4
8
# This program is free software; you can redistribute it and/or modify
5
9
# it under the terms of the GNU General Public License as published by
13
17
#
14
18
# You should have received a copy of the GNU General Public License
15
19
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
20
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
21
 
18
22
 
19
23
"""A GIT branch and repository format implementation for bzr."""
20
24
 
21
 
try:
22
 
    import dulwich as git
23
 
except ImportError:
24
 
    import os, sys
25
 
    sys.path.insert(0, os.path.join(os.path.dirname(__file__), "dulwich"))
26
 
    import dulwich as git
27
 
from bzrlib import bzrdir
28
 
from bzrlib.foreign import ForeignVcs, VcsMappingRegistry, foreign_vcs_registry
29
 
from bzrlib.plugins.git.dir import LocalGitBzrDirFormat, RemoteGitBzrDirFormat
30
 
from bzrlib.transport import register_lazy_transport
31
 
 
32
 
bzrdir.format_registry.register(
33
 
    'git', LocalGitBzrDirFormat,
34
 
    help='GIT repository.', 
35
 
    native=False, experimental=True,
36
 
    )
37
 
 
38
 
bzrdir.BzrDirFormat.register_control_format(LocalGitBzrDirFormat)
39
 
bzrdir.BzrDirFormat.register_control_format(RemoteGitBzrDirFormat)
40
 
 
41
 
register_lazy_transport("git://", 'bzrlib.plugins.git.remote',
42
 
                        'GitSmartTransport')
43
 
 
44
 
 
45
 
class ForeignGit(ForeignVcs):
46
 
    """Foreign Git."""
47
 
 
48
 
 
49
 
git_mapping_registry = VcsMappingRegistry()
50
 
git_mapping_registry.register_lazy('git-experimental', "bzrlib.plugins.git.mapping",
51
 
                                   "BzrGitMappingExperimental")
52
 
foreign_vcs_registry.register("git", ForeignGit(git_mapping_registry), 
53
 
                                      "Stupid content tracker")
 
25
from __future__ import absolute_import
 
26
 
 
27
import os
 
28
import sys
 
29
 
 
30
dulwich_minimum_version = (0, 19, 7)
 
31
 
 
32
from .. import (  # noqa: F401
 
33
    __version__ as breezy_version,
 
34
    errors as brz_errors,
 
35
    trace,
 
36
    version_info,
 
37
    )
 
38
 
 
39
from ..controldir import (
 
40
    ControlDirFormat,
 
41
    Prober,
 
42
    format_registry,
 
43
    network_format_registry as controldir_network_format_registry,
 
44
    )
 
45
 
 
46
from ..transport import (
 
47
    register_lazy_transport,
 
48
    register_transport_proto,
 
49
    transport_server_registry,
 
50
    )
 
51
from ..commands import (
 
52
    plugin_cmds,
 
53
    )
 
54
 
 
55
 
 
56
if getattr(sys, "frozen", None):
 
57
    # allow import additional libs from ./_lib for bzr.exe only
 
58
    sys.path.append(os.path.normpath(
 
59
        os.path.join(os.path.dirname(__file__), '_lib')))
 
60
 
 
61
 
 
62
def import_dulwich():
 
63
    try:
 
64
        from dulwich import __version__ as dulwich_version
 
65
    except ImportError:
 
66
        raise brz_errors.DependencyNotPresent(
 
67
            "dulwich",
 
68
            "bzr-git: Please install dulwich, https://www.dulwich.io/")
 
69
    else:
 
70
        if dulwich_version < dulwich_minimum_version:
 
71
            raise brz_errors.DependencyNotPresent(
 
72
                "dulwich",
 
73
                "bzr-git: Dulwich is too old; at least %d.%d.%d is required" %
 
74
                dulwich_minimum_version)
 
75
 
 
76
 
 
77
_versions_checked = False
 
78
 
 
79
 
 
80
def lazy_check_versions():
 
81
    global _versions_checked
 
82
    if _versions_checked:
 
83
        return
 
84
    import_dulwich()
 
85
    _versions_checked = True
 
86
 
 
87
 
 
88
format_registry.register_lazy(
 
89
    'git', __name__ + ".dir", "LocalGitControlDirFormat",
 
90
    help='GIT repository.', native=False, experimental=False)
 
91
 
 
92
format_registry.register_lazy(
 
93
    'git-bare', __name__ + ".dir", "BareLocalGitControlDirFormat",
 
94
    help='Bare GIT repository (no working tree).', native=False,
 
95
    experimental=False)
 
96
 
 
97
from ..revisionspec import (RevisionSpec_dwim, revspec_registry)
 
98
revspec_registry.register_lazy("git:", __name__ + ".revspec",
 
99
                               "RevisionSpec_git")
 
100
RevisionSpec_dwim.append_possible_lazy_revspec(
 
101
    __name__ + ".revspec", "RevisionSpec_git")
 
102
 
 
103
 
 
104
class LocalGitProber(Prober):
 
105
 
 
106
    def probe_transport(self, transport):
 
107
        try:
 
108
            external_url = transport.external_url()
 
109
        except brz_errors.InProcessTransport:
 
110
            raise brz_errors.NotBranchError(path=transport.base)
 
111
        if (external_url.startswith("http:") or
 
112
                external_url.startswith("https:")):
 
113
            # Already handled by RemoteGitProber
 
114
            raise brz_errors.NotBranchError(path=transport.base)
 
115
        from .. import urlutils
 
116
        if urlutils.split(transport.base)[1] == ".git":
 
117
            raise brz_errors.NotBranchError(path=transport.base)
 
118
        if not transport.has_any(['objects', '.git/objects', '.git']):
 
119
            raise brz_errors.NotBranchError(path=transport.base)
 
120
        lazy_check_versions()
 
121
        from .dir import (
 
122
            BareLocalGitControlDirFormat,
 
123
            LocalGitControlDirFormat,
 
124
            )
 
125
        if transport.has_any(['.git/objects', '.git']):
 
126
            return LocalGitControlDirFormat()
 
127
        if transport.has('info') and transport.has('objects'):
 
128
            return BareLocalGitControlDirFormat()
 
129
        raise brz_errors.NotBranchError(path=transport.base)
 
130
 
 
131
    @classmethod
 
132
    def known_formats(cls):
 
133
        from .dir import (
 
134
            BareLocalGitControlDirFormat,
 
135
            LocalGitControlDirFormat,
 
136
            )
 
137
        return [BareLocalGitControlDirFormat(), LocalGitControlDirFormat()]
 
138
 
 
139
 
 
140
def user_agent_for_github():
 
141
    # GitHub requires we lie. https://github.com/dulwich/dulwich/issues/562
 
142
    return "git/Breezy/%s" % breezy_version
 
143
 
 
144
 
 
145
class RemoteGitProber(Prober):
 
146
 
 
147
    def probe_http_transport(self, transport):
 
148
        from .. import urlutils
 
149
        base_url, _ = urlutils.split_segment_parameters(
 
150
            transport.external_url())
 
151
        url = urlutils.join(base_url, "info/refs") + "?service=git-upload-pack"
 
152
        from ..transport.http import Request
 
153
        headers = {"Content-Type": "application/x-git-upload-pack-request",
 
154
                   "Accept": "application/x-git-upload-pack-result",
 
155
                   }
 
156
        req = Request('GET', url, accepted_errors=[200, 403, 404, 405],
 
157
                      headers=headers)
 
158
        (scheme, user, password, host, port,
 
159
         path) = urlutils.parse_url(req.get_full_url())
 
160
        if host == "github.com":
 
161
            # GitHub requires we lie.
 
162
            # https://github.com/dulwich/dulwich/issues/562
 
163
            req.add_header("User-Agent", user_agent_for_github())
 
164
        elif host == "bazaar.launchpad.net":
 
165
            # Don't attempt Git probes against bazaar.launchpad.net; pad.lv/1744830
 
166
            raise brz_errors.NotBranchError(transport.base)
 
167
        resp = transport._perform(req)
 
168
        if resp.code in (404, 405):
 
169
            raise brz_errors.NotBranchError(transport.base)
 
170
        headers = resp.headers
 
171
        ct = headers.get("Content-Type")
 
172
        if ct is None:
 
173
            raise brz_errors.NotBranchError(transport.base)
 
174
        if ct.startswith("application/x-git"):
 
175
            from .remote import RemoteGitControlDirFormat
 
176
            return RemoteGitControlDirFormat()
 
177
        else:
 
178
            from .dir import (
 
179
                BareLocalGitControlDirFormat,
 
180
                )
 
181
            ret = BareLocalGitControlDirFormat()
 
182
            ret._refs_text = resp.read()
 
183
            return ret
 
184
 
 
185
    def probe_transport(self, transport):
 
186
        try:
 
187
            external_url = transport.external_url()
 
188
        except brz_errors.InProcessTransport:
 
189
            raise brz_errors.NotBranchError(path=transport.base)
 
190
 
 
191
        if (external_url.startswith("http:") or
 
192
                external_url.startswith("https:")):
 
193
            return self.probe_http_transport(transport)
 
194
 
 
195
        if (not external_url.startswith("git://") and
 
196
                not external_url.startswith("git+")):
 
197
            raise brz_errors.NotBranchError(transport.base)
 
198
 
 
199
        # little ugly, but works
 
200
        from .remote import (
 
201
            GitSmartTransport,
 
202
            RemoteGitControlDirFormat,
 
203
            )
 
204
        if isinstance(transport, GitSmartTransport):
 
205
            return RemoteGitControlDirFormat()
 
206
        raise brz_errors.NotBranchError(path=transport.base)
 
207
 
 
208
    @classmethod
 
209
    def known_formats(cls):
 
210
        from .remote import RemoteGitControlDirFormat
 
211
        return [RemoteGitControlDirFormat()]
 
212
 
 
213
 
 
214
ControlDirFormat.register_prober(LocalGitProber)
 
215
ControlDirFormat._server_probers.append(RemoteGitProber)
 
216
 
 
217
register_transport_proto(
 
218
    'git://', help="Access using the Git smart server protocol.")
 
219
register_transport_proto(
 
220
    'git+ssh://',
 
221
    help="Access using the Git smart server protocol over SSH.")
 
222
 
 
223
register_lazy_transport("git://", __name__ + '.remote',
 
224
                        'TCPGitSmartTransport')
 
225
register_lazy_transport("git+ssh://", __name__ + '.remote',
 
226
                        'SSHGitSmartTransport')
 
227
 
 
228
 
 
229
plugin_cmds.register_lazy("cmd_git_import", [], __name__ + ".commands")
 
230
plugin_cmds.register_lazy("cmd_git_object", ["git-objects", "git-cat"],
 
231
                          __name__ + ".commands")
 
232
plugin_cmds.register_lazy("cmd_git_refs", [], __name__ + ".commands")
 
233
plugin_cmds.register_lazy("cmd_git_apply", [], __name__ + ".commands")
 
234
plugin_cmds.register_lazy("cmd_git_push_pristine_tar_deltas",
 
235
                          ['git-push-pristine-tar', 'git-push-pristine'],
 
236
                          __name__ + ".commands")
 
237
 
 
238
 
 
239
def extract_git_foreign_revid(rev):
 
240
    try:
 
241
        foreign_revid = rev.foreign_revid
 
242
    except AttributeError:
 
243
        from .mapping import mapping_registry
 
244
        foreign_revid, mapping = \
 
245
            mapping_registry.parse_revision_id(rev.revision_id)
 
246
        return foreign_revid
 
247
    else:
 
248
        from .mapping import foreign_vcs_git
 
249
        if rev.mapping.vcs == foreign_vcs_git:
 
250
            return foreign_revid
 
251
        else:
 
252
            raise brz_errors.InvalidRevisionId(rev.revision_id, None)
 
253
 
 
254
 
 
255
def update_stanza(rev, stanza):
 
256
    try:
 
257
        git_commit = extract_git_foreign_revid(rev)
 
258
    except brz_errors.InvalidRevisionId:
 
259
        pass
 
260
    else:
 
261
        stanza.add("git-commit", git_commit)
 
262
 
 
263
 
 
264
from ..hooks import install_lazy_named_hook
 
265
install_lazy_named_hook(
 
266
    "breezy.version_info_formats.format_rio",
 
267
    "RioVersionInfoBuilder.hooks", "revision", update_stanza,
 
268
    "git commits")
 
269
 
 
270
transport_server_registry.register_lazy(
 
271
    'git', __name__ + '.server', 'serve_git',
 
272
    'Git Smart server protocol over TCP. (default port: 9418)')
 
273
 
 
274
transport_server_registry.register_lazy(
 
275
    'git-receive-pack', __name__ + '.server',
 
276
    'serve_git_receive_pack',
 
277
    help='Git Smart server receive pack command. (inetd mode only)')
 
278
transport_server_registry.register_lazy(
 
279
    'git-upload-pack', __name__ + 'git.server',
 
280
    'serve_git_upload_pack',
 
281
    help='Git Smart server upload pack command. (inetd mode only)')
 
282
 
 
283
from ..repository import (
 
284
    format_registry as repository_format_registry,
 
285
    network_format_registry as repository_network_format_registry,
 
286
    )
 
287
repository_network_format_registry.register_lazy(
 
288
    b'git', __name__ + '.repository', 'GitRepositoryFormat')
 
289
 
 
290
register_extra_lazy_repository_format = getattr(repository_format_registry,
 
291
                                                "register_extra_lazy")
 
292
register_extra_lazy_repository_format(__name__ + '.repository',
 
293
                                      'GitRepositoryFormat')
 
294
 
 
295
from ..branch import (
 
296
    network_format_registry as branch_network_format_registry,
 
297
    )
 
298
branch_network_format_registry.register_lazy(
 
299
    b'git', __name__ + '.branch', 'LocalGitBranchFormat')
 
300
 
 
301
 
 
302
from ..branch import (
 
303
    format_registry as branch_format_registry,
 
304
    )
 
305
branch_format_registry.register_extra_lazy(
 
306
    __name__ + '.branch',
 
307
    'LocalGitBranchFormat',
 
308
    )
 
309
branch_format_registry.register_extra_lazy(
 
310
    __name__ + '.remote',
 
311
    'RemoteGitBranchFormat',
 
312
    )
 
313
 
 
314
 
 
315
from ..workingtree import (
 
316
    format_registry as workingtree_format_registry,
 
317
    )
 
318
workingtree_format_registry.register_extra_lazy(
 
319
    __name__ + '.workingtree',
 
320
    'GitWorkingTreeFormat',
 
321
    )
 
322
 
 
323
controldir_network_format_registry.register_lazy(
 
324
    b'git', __name__ + ".dir", "GitControlDirFormat")
 
325
 
 
326
 
 
327
from ..diff import format_registry as diff_format_registry
 
328
diff_format_registry.register_lazy('git', __name__ + '.send',
 
329
    'GitDiffTree', 'Git am-style diff format')
 
330
 
 
331
from ..send import (
 
332
    format_registry as send_format_registry,
 
333
    )
 
334
send_format_registry.register_lazy('git', __name__ + '.send',
 
335
                                   'send_git', 'Git am-style diff format')
 
336
 
 
337
from ..directory_service import directories
 
338
directories.register_lazy('github:', __name__ + '.directory',
 
339
                          'GitHubDirectory',
 
340
                          'GitHub directory.')
 
341
directories.register_lazy('git@github.com:', __name__ + '.directory',
 
342
                          'GitHubDirectory',
 
343
                          'GitHub directory.')
 
344
 
 
345
from ..help_topics import (
 
346
    topic_registry,
 
347
    )
 
348
topic_registry.register_lazy('git', __name__ + '.help', 'help_git',
 
349
    'Using Bazaar with Git')
 
350
 
 
351
from ..foreign import (
 
352
    foreign_vcs_registry,
 
353
    )
 
354
foreign_vcs_registry.register_lazy("git",
 
355
    __name__ + ".mapping", "foreign_vcs_git", "Stupid content tracker")
 
356
 
 
357
 
 
358
def update_git_cache(repository, revid):
 
359
    """Update the git cache after a local commit."""
 
360
    if getattr(repository, "_git", None) is not None:
 
361
        return  # No need to update cache for git repositories
 
362
 
 
363
    if not repository.control_transport.has("git"):
 
364
        return  # No existing cache, don't bother updating
 
365
    try:
 
366
        lazy_check_versions()
 
367
    except brz_errors.DependencyNotPresent as e:
 
368
        # dulwich is probably missing. silently ignore
 
369
        trace.mutter("not updating git map for %r: %s",
 
370
                     repository, e)
 
371
 
 
372
    from .object_store import BazaarObjectStore
 
373
    store = BazaarObjectStore(repository)
 
374
    with store.lock_write():
 
375
        try:
 
376
            parent_revisions = set(repository.get_parent_map([revid])[revid])
 
377
        except KeyError:
 
378
            # Isn't this a bit odd - how can a revision that was just committed
 
379
            # be missing?
 
380
            return
 
381
        missing_revisions = store._missing_revisions(parent_revisions)
 
382
        if not missing_revisions:
 
383
            store._cache.idmap.start_write_group()
 
384
            try:
 
385
                # Only update if the cache was up to date previously
 
386
                store._update_sha_map_revision(revid)
 
387
            except BaseException:
 
388
                store._cache.idmap.abort_write_group()
 
389
                raise
 
390
            else:
 
391
                store._cache.idmap.commit_write_group()
 
392
 
 
393
 
 
394
def post_commit_update_cache(local_branch, master_branch, old_revno, old_revid,
 
395
                             new_revno, new_revid):
 
396
    if local_branch is not None:
 
397
        update_git_cache(local_branch.repository, new_revid)
 
398
    update_git_cache(master_branch.repository, new_revid)
 
399
 
 
400
 
 
401
def loggerhead_git_hook(branch_app, environ):
 
402
    branch = branch_app.branch
 
403
    config_stack = branch.get_config_stack()
 
404
    if config_stack.get('http_git'):
 
405
        return None
 
406
    from .server import git_http_hook
 
407
    return git_http_hook(branch, environ['REQUEST_METHOD'],
 
408
                         environ['PATH_INFO'])
 
409
 
 
410
 
 
411
install_lazy_named_hook("breezy.branch",
 
412
                        "Branch.hooks", "post_commit",
 
413
                        post_commit_update_cache, "git cache")
 
414
install_lazy_named_hook("breezy.plugins.loggerhead.apps.branch",
 
415
                        "BranchWSGIApp.hooks", "controller",
 
416
                        loggerhead_git_hook, "git support")
 
417
 
 
418
 
 
419
from ..config import (
 
420
    option_registry,
 
421
    Option,
 
422
    bool_from_store,
 
423
    )
 
424
 
 
425
option_registry.register(
 
426
    Option('git.http',
 
427
           default=None, from_unicode=bool_from_store, invalid='warning',
 
428
           help='''\
 
429
Allow fetching of Git packs over HTTP.
 
430
 
 
431
This enables support for fetching Git packs over HTTP in Loggerhead.
 
432
'''))
54
433
 
55
434
 
56
435
def test_suite():
57
 
    from bzrlib.plugins.git import tests
 
436
    from . import tests
58
437
    return tests.test_suite()