15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
from bzrlib.errors import (
31
from bzrlib.trace import (
34
from bzrlib.transport import (
38
from bzrlib.plugins.git import (
43
from bzrlib.plugins.git.branch import (
47
from bzrlib.plugins.git.errors import (
48
GitSmartRemoteNotSupported,
51
from bzrlib.plugins.git.dir import (
54
from bzrlib.plugins.git.mapping import (
57
from bzrlib.plugins.git.repository import (
63
from dulwich.errors import (
66
from dulwich.pack import (
18
from bzrlib import urlutils
19
from bzrlib.bzrdir import BzrDir, BzrDirFormat
20
from bzrlib.errors import NoSuchFile, NotLocalUrl
21
from bzrlib.lockable_files import TransportLock
22
from bzrlib.repository import Repository
23
from bzrlib.trace import info
24
from bzrlib.transport import Transport
26
from bzrlib.plugins.git import git
27
from bzrlib.plugins.git.branch import GitBranch
28
from bzrlib.plugins.git.foreign import ForeignBranch
29
from bzrlib.plugins.git.repository import GitFormat, GitRepository
76
from dulwich.pack import load_pack_index
78
from dulwich.pack import PackIndex as load_pack_index
81
# Don't run any tests on GitSmartTransport as it is not intended to be
82
# a full implementation of Transport
83
def get_test_permutations():
34
from dulwich.pack import PackData
87
37
class GitSmartTransport(Transport):
89
39
def __init__(self, url, _client=None):
90
40
Transport.__init__(self, url)
91
41
(scheme, _, loc, _, _) = urlparse.urlsplit(url)
42
assert scheme == "git"
92
43
hostport, self._path = urllib.splithost(loc)
93
(self._username, hostport) = urllib.splituser(hostport)
94
(self._host, self._port) = urllib.splitnport(hostport, None)
95
self._client = _client
97
def external_url(self):
100
def has(self, relpath):
103
def _get_client(self):
104
raise NotImplementedError(self._get_client)
44
(self._host, self._port) = urllib.splitnport(hostport, git.protocol.TCP_GIT_PORT)
45
if _client is not None:
46
self._client = _client
48
self._client = git.client.TCPGitClient(self._host, self._port)
109
50
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
110
51
if progress is None:
111
52
def progress(text):
112
53
info("git: %s" % text)
113
client = self._get_client()
115
return client.fetch_pack(self._get_path(), determine_wants,
116
graph_walker, pack_data, progress)
117
except GitProtocolError, e:
54
self._client.fetch_pack(self._path, determine_wants, graph_walker,
120
def send_pack(self, get_changed_refs, generate_pack_contents):
121
client = self._get_client()
57
def fetch_objects(self, determine_wants, graph_walker, progress=None):
58
fd, path = tempfile.mkstemp(dir=self.pack_dir(), suffix=".pack")
59
self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
123
return client.send_pack(self._get_path(), get_changed_refs,
124
generate_pack_contents)
125
except GitProtocolError, e:
63
for o in p.iterobjects():
128
68
def get(self, path):
129
69
raise NoSuchFile(path)
131
def abspath(self, relpath):
132
return urlutils.join(self.base, relpath)
134
71
def clone(self, offset=None):
135
72
"""See Transport.clone()."""
136
73
if offset is None:
139
76
newurl = urlutils.join(self.base, offset)
141
return self.__class__(newurl, self._client)
144
class TCPGitSmartTransport(GitSmartTransport):
148
def _get_client(self):
149
if self._client is not None:
153
return git.client.TCPGitClient(self._host, self._port, thin_packs=False,
154
report_activity=self._report_activity)
157
class SSHGitSmartTransport(GitSmartTransport):
162
if self._path.startswith("/~/"):
163
return self._path[3:]
166
def _get_client(self):
167
if self._client is not None:
171
return git.client.SSHGitClient(self._host, self._port, self._username,
172
thin_packs=False, report_activity=self._report_activity)
175
class RemoteGitDir(GitDir):
78
return GitSmartTransport(newurl, self._client)
81
class RemoteGitDir(BzrDir):
177
83
def __init__(self, transport, lockfiles, format):
178
84
self._format = format
179
85
self.root_transport = transport
180
86
self.transport = transport
181
87
self._lockfiles = lockfiles
182
self._mode_check_done = None
89
def is_supported(self):
184
92
def open_repository(self):
185
93
return RemoteGitRepository(self, self._lockfiles)
187
def open_branch(self, ignore_fallbacks=False):
95
def open_branch(self):
188
96
repo = self.open_repository()
189
97
# TODO: Support for multiple branches in one bzrdir in bzrlib!
190
98
return RemoteGitBranch(self, repo, "HEAD", self._lockfiles)
192
100
def open_workingtree(self):
193
101
raise NotLocalUrl(self.transport.base)
196
class EmptyObjectStoreIterator(dict):
198
def iterobjects(self):
202
class TemporaryPackIterator(Pack):
204
def __init__(self, path, resolve_ext_ref):
205
super(TemporaryPackIterator, self).__init__(path)
206
self.resolve_ext_ref = resolve_ext_ref
210
if self._idx is None:
211
pb = ui.ui_factory.nested_progress_bar()
213
def report_progress(cur, total):
214
pb.update("generating index", cur, total)
215
self.data.create_index(self._idx_path, self.resolve_ext_ref,
216
progress=report_progress)
219
self._idx = load_pack_index(self._idx_path)
223
os.remove(self._data_path)
224
os.remove(self._idx_path)
103
def cloning_metadir(self, stacked=False):
104
"""Produce a metadir suitable for cloning with."""
106
return bzrlib.bzrdir.format_registry.make_bzrdir("1.6.1-rich-root")
108
return bzrlib.bzrdir.format_registry.make_bzrdir("rich-root-pack")
227
111
class RemoteGitRepository(GitRepository):
229
113
def __init__(self, gitdir, lockfiles):
230
114
GitRepository.__init__(self, gitdir, lockfiles)
234
def inventories(self):
235
raise GitSmartRemoteNotSupported()
239
raise GitSmartRemoteNotSupported()
243
raise GitSmartRemoteNotSupported()
246
if self._refs is not None:
248
self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
249
lambda x: None, lambda x: mutter("git: %s" % x))
252
def fetch_pack(self, determine_wants, graph_walker, pack_data,
254
return self._transport.fetch_pack(determine_wants, graph_walker,
257
def send_pack(self, get_changed_refs, generate_pack_contents):
258
return self._transport.send_pack(get_changed_refs, generate_pack_contents)
260
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref, progress=None):
261
fd, path = tempfile.mkstemp(suffix=".pack")
262
self.fetch_pack(determine_wants, graph_walker, lambda x: os.write(fd, x), progress)
264
if os.path.getsize(path) == 0:
265
return EmptyObjectStoreIterator()
266
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
268
def lookup_git_revid(self, bzr_revid):
269
# This won't work for any round-tripped bzr revisions, but it's a start..
271
return mapping_registry.revision_id_bzr_to_foreign(bzr_revid)
272
except InvalidRevisionId:
273
raise NoSuchRevision(self, bzr_revid)
276
class RemoteGitTagDict(tag.BasicTags):
278
def __init__(self, branch):
280
self.repository = branch.repository
282
def get_tag_dict(self):
283
return extract_tags(self.repository.get_refs(), self.branch.mapping)
285
def set_tag(self, name, revid):
286
# FIXME: Not supported yet, should do a push of a new ref
287
raise NotImplementedError(self.set_tag)
116
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
117
self._transport.fetch_pack(determine_wants, graph_walker, pack_data, progress)
290
120
class RemoteGitBranch(GitBranch):
292
122
def __init__(self, bzrdir, repository, name, lockfiles):
294
super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
297
def revision_history(self):
298
raise GitSmartRemoteNotSupported()
123
def determine_wants(heads):
124
self._ref = heads[name]
125
bzrdir.root_transport.fetch_pack(determine_wants, None, lambda x: None,
126
lambda x: mutter("git: %s" % x))
127
super(RemoteGitBranch, self).__init__(bzrdir, repository, name, self._ref, lockfiles)
300
129
def last_revision(self):
301
return self.mapping.revision_id_foreign_to_bzr(self.head)
305
if self._ref is not None:
307
heads = self.repository.get_refs()
308
if not self.name in heads:
309
raise NoSuchRef(name)
310
self._ref = heads[self.name]
313
def _synchronize_history(self, destination, revision_id):
314
"""See Branch._synchronize_history()."""
315
destination.generate_revision_history(self.last_revision())
317
def get_push_location(self):
320
def set_push_location(self, url):
130
return self.mapping.revision_id_foreign_to_bzr(self._ref)