1
# Copyright (C) 2006 Canonical Ltd
3
# Authors: Robert Collins <robert.collins@canonical.com>
4
# Jelmer Vernooij <jelmer@samba.org>
5
# John Carr <john.carr@unrouted.co.uk>
7
# This program is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation; either version 2 of the License, or
10
# (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with this program; if not, write to the Free Software
19
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
"""A GIT branch and repository format implementation for bzr."""
29
from bzrlib import bzrdir, errors as bzr_errors
30
from bzrlib.foreign import foreign_vcs_registry
31
from bzrlib.lockable_files import TransportLock
32
from bzrlib.transport import register_lazy_transport
33
from bzrlib.commands import Command, register_command
34
from bzrlib.option import Option
35
from bzrlib.trace import warning
37
MINIMUM_DULWICH_VERSION = (0, 1, 0)
38
COMPATIBLE_BZR_VERSIONS = [(1, 11, 0), (1, 12, 0)]
40
if getattr(sys, "frozen", None):
41
# allow import additional libs from ./_lib for bzr.exe only
42
sys.path.append(os.path.normpath(os.path.join(os.path.dirname(__file__), '_lib')))
44
_versions_checked = False
45
def lazy_check_versions():
46
global _versions_checked
49
_versions_checked = True
51
from dulwich import __version__ as dulwich_version
53
warning("Please install dulwich, https://launchpad.net/dulwich")
56
if dulwich_version < MINIMUM_DULWICH_VERSION:
57
warning("Dulwich is too old; at least %d.%d.%d is required" % MINIMUM_DULWICH_VERSION)
60
bzrlib.api.require_any_api(bzrlib, COMPATIBLE_BZR_VERSIONS)
62
bzrdir.format_registry.register_lazy('git',
63
"bzrlib.plugins.git.dir", "LocalGitBzrDirFormat",
64
help='GIT repository.', native=False, experimental=True,
68
from bzrlib.revisionspec import revspec_registry
69
revspec_registry.register_lazy("git:", "bzrlib.plugins.git.revspec",
73
from bzrlib.revisionspec import SPEC_TYPES
74
from bzrlib.plugins.git.revspec import RevisionSpec_git
75
SPEC_TYPES.append(RevisionSpec_git)
77
class GitBzrDirFormat(bzrdir.BzrDirFormat):
78
_lock_class = TransportLock
80
def is_supported(self):
84
class LocalGitBzrDirFormat(GitBzrDirFormat):
85
"""The .git directory control format."""
88
def _known_formats(self):
89
return set([LocalGitBzrDirFormat()])
91
def open(self, transport, _found=None):
92
"""Open this directory.
96
# we dont grok readonly - git isn't integrated with transport.
98
if url.startswith('readonly+'):
99
url = url[len('readonly+'):]
102
gitrepo = git.repo.Repo(transport.local_abspath("."))
103
except bzr_errors.NotLocalUrl:
104
raise bzr_errors.NotBranchError(path=transport.base)
105
from bzrlib.plugins.git.dir import LocalGitDir, GitLockableFiles, GitLock
106
lockfiles = GitLockableFiles(transport, GitLock())
107
return LocalGitDir(transport, lockfiles, gitrepo, self)
110
def probe_transport(klass, transport):
111
"""Our format is present if the transport ends in '.not/'."""
112
from bzrlib.transport.local import LocalTransport
114
if not isinstance(transport, LocalTransport):
115
raise bzr_errors.NotBranchError(path=transport.base)
117
# This should quickly filter out most things that are not
118
# git repositories, saving us the trouble from loading dulwich.
119
if not transport.has(".git") and not transport.has("objects"):
120
raise bzr_errors.NotBranchError(path=transport.base)
122
import dulwich as git
125
format.open(transport)
127
except git.errors.NotGitRepository, e:
128
raise bzr_errors.NotBranchError(path=transport.base)
129
raise bzr_errors.NotBranchError(path=transport.base)
131
def get_format_description(self):
132
return "Local Git Repository"
134
def get_format_string(self):
135
return "Local Git Repository"
137
def initialize_on_transport(self, transport):
138
from bzrlib.transport.local import LocalTransport
140
if not isinstance(transport, LocalTransport):
141
raise NotImplementedError(self.initialize,
142
"Can't create Git Repositories/branches on "
143
"non-local transports")
145
from dulwich.repo import Repo
146
Repo.create(transport.local_abspath("."))
147
return self.open(transport)
149
def is_supported(self):
153
class RemoteGitBzrDirFormat(GitBzrDirFormat):
154
"""The .git directory control format."""
157
def _known_formats(self):
158
return set([RemoteGitBzrDirFormat()])
160
def open(self, transport, _found=None):
161
"""Open this directory.
164
from bzrlib.plugins.git.remote import RemoteGitDir, GitSmartTransport
165
if not isinstance(transport, GitSmartTransport):
166
raise bzr_errors.NotBranchError(transport.base)
167
# we dont grok readonly - git isn't integrated with transport.
169
if url.startswith('readonly+'):
170
url = url[len('readonly+'):]
172
from bzrlib.plugins.git.dir import GitLockableFiles, GitLock
173
lockfiles = GitLockableFiles(transport, GitLock())
174
return RemoteGitDir(transport, lockfiles, self)
177
def probe_transport(klass, transport):
178
"""Our format is present if the transport ends in '.not/'."""
179
# little ugly, but works
181
from bzrlib.plugins.git.remote import GitSmartTransport
182
if not isinstance(transport, GitSmartTransport):
183
raise bzr_errors.NotBranchError(transport.base)
184
# The only way to know a path exists and contains a valid repository
185
# is to do a request against it:
187
transport.fetch_pack(lambda x: [], None, lambda x: None,
188
lambda x: mutter("git: %s" % x))
189
except errors.git_errors.GitProtocolError:
190
raise bzr_errors.NotBranchError(path=transport.base)
193
raise bzr_errors.NotBranchError(path=transport.base)
195
def get_format_description(self):
196
return "Remote Git Repository"
198
def get_format_string(self):
199
return "Remote Git Repository"
201
def initialize_on_transport(self, transport):
202
raise bzr_errors.UninitializableFormat(self)
205
bzrdir.BzrDirFormat.register_control_format(LocalGitBzrDirFormat)
206
bzrdir.BzrDirFormat.register_control_format(RemoteGitBzrDirFormat)
208
register_lazy_transport("git://", 'bzrlib.plugins.git.remote',
211
foreign_vcs_registry.register_lazy("git",
212
"bzrlib.plugins.git.mapping",
214
"Stupid content tracker")
217
class cmd_git_serve(Command):
218
"""Provide access to a Bazaar branch using the git protocol.
220
This command is experimental and doesn't do much yet.
224
help='serve contents of directory',
228
def run(self, directory=None):
229
lazy_check_versions()
230
from dulwich.server import TCPGitServer
231
from bzrlib.plugins.git.server import BzrBackend
232
from bzrlib.trace import warning
234
warning("server support in bzr-git is experimental.")
236
if directory is None:
237
directory = os.getcwd()
239
backend = BzrBackend(directory)
241
server = TCPGitServer(backend, 'localhost')
242
server.serve_forever()
244
register_command(cmd_git_serve)
247
class cmd_git_import(Command):
248
"""Import all branches from a git repository.
252
takes_args = ["src_location", "dest_location"]
254
def run(self, src_location, dest_location):
255
from bzrlib.bzrdir import BzrDir, format_registry
256
from bzrlib.errors import NoRepositoryPresent, NotBranchError
257
from bzrlib.repository import Repository
258
source_repo = Repository.open(src_location)
259
format = format_registry.make_bzrdir('rich-root-pack')
261
target_bzrdir = BzrDir.open(dest_location)
262
except NotBranchError:
263
target_bzrdir = BzrDir.create(dest_location, format=format)
265
target_repo = target_bzrdir.open_repository()
266
except NoRepositoryPresent:
267
target_repo = target_bzrdir.create_repository(shared=True)
269
target_repo.fetch(source_repo)
270
for name, ref in source_repo._git.heads().iteritems():
271
head_loc = os.path.join(dest_location, name)
273
head_bzrdir = BzrDir.open(head_loc)
274
except NotBranchError:
275
head_bzrdir = BzrDir.create(head_loc, format=format)
277
head_branch = head_bzrdir.open_branch()
278
except NotBranchError:
279
head_branch = head_bzrdir.create_branch()
280
head_branch.generate_revision_history(source_repo.get_mapping().revision_id_foreign_to_bzr(ref))
283
register_command(cmd_git_import)
287
from bzrlib.plugins.git import tests
288
return tests.test_suite()