118
143
raise NotImplementedError(self._get_client)
120
145
def _get_path(self):
123
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
126
trace.info("git: %s" % text)
127
client = self._get_client(thin_packs=False)
129
return client.fetch_pack(self._get_path(), determine_wants,
130
graph_walker, pack_data, progress)
131
except GitProtocolError, e:
134
def send_pack(self, get_changed_refs, generate_pack_contents):
135
client = self._get_client(thin_packs=False)
137
return client.send_pack(self._get_path(), get_changed_refs,
138
generate_pack_contents)
139
except GitProtocolError, e:
146
return self._stripped_path
142
148
def get(self, path):
143
149
raise NoSuchFile(path)
198
205
class RemoteGitDir(GitDir):
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
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
217
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
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)
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)
229
except GitProtocolError, e:
230
raise parse_git_error(self.transport.external_url(), e)
232
def send_pack(self, get_changed_refs, generate_pack_contents):
233
client = self._get_client(thin_packs=False)
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)
240
def destroy_branch(self, name=None):
241
refname = self._get_selected_ref(name)
244
def get_changed_refs(old_refs):
246
if not refname in ret:
247
raise NotBranchError(self.user_url)
248
ret[refname] = "00" * 20
250
self.send_pack(get_changed_refs, lambda have, want: [])
254
return self.control_url
257
def user_transport(self):
258
return self.root_transport
261
def control_url(self):
262
return self.control_transport.base
265
def control_transport(self):
266
return self.root_transport
210
268
def open_repository(self):
211
return RemoteGitRepository(self, self._lockfiles)
269
return RemoteGitRepository(self)
213
def _open_branch(self, name=None, ignore_fallbacks=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)
219
277
def open_workingtree(self, recommend_upgrade=False):
220
278
raise NotLocalUrl(self.transport.base)
280
def get_peeled(self, name):
281
return self.get_refs_container().get_peeled(name)
283
def get_refs_container(self):
284
if self._refs is not None:
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)
223
292
class EmptyObjectStoreIterator(dict):
262
331
os.remove(self._data_path)
334
class BzrGitHttpClient(dulwich.client.HttpGitClient):
336
def __init__(self, transport, *args, **kwargs):
337
self.transport = transport
338
super(BzrGitHttpClient, self).__init__(transport.external_url(), *args, **kwargs)
340
self._http_perform = getattr(self.transport, "_perform", urllib2.urlopen)
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)
349
class RemoteGitControlDirFormat(GitControlDirFormat):
350
"""The .git directory control format."""
352
supports_workingtrees = False
355
def _known_formats(self):
356
return set([RemoteGitControlDirFormat()])
358
def is_initializable(self):
361
def is_supported(self):
364
def open(self, transport, _found=None):
365
"""Open this directory.
368
# we dont grok readonly - git isn't integrated with transport.
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
380
raise NotBranchError(transport.base)
381
return RemoteGitDir(transport, self, get_client, client_path)
383
def get_format_description(self):
384
return "Remote Git Repository"
386
def initialize_on_transport(self, transport):
387
raise UninitializableFormat(self)
389
def supports_transport(self, transport):
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:"))
265
400
class RemoteGitRepository(GitRepository):
267
def __init__(self, gitdir, lockfiles):
268
GitRepository.__init__(self, gitdir, lockfiles)
272
def inventories(self):
273
raise GitSmartRemoteNotSupported()
277
raise GitSmartRemoteNotSupported()
281
raise GitSmartRemoteNotSupported()
284
if self._refs is not None:
286
self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
287
lambda x: None, lambda x: trace.mutter("git: %s" % x))
404
return self.control_url
406
def get_parent_map(self, revids):
407
raise GitSmartRemoteNotSupported(self.get_parent_map, self)
290
409
def fetch_pack(self, determine_wants, graph_walker, pack_data,
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)
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)
298
417
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref,
300
419
fd, path = tempfile.mkstemp(suffix=".pack")
301
self.fetch_pack(determine_wants, graph_walker,
302
lambda x: os.write(fd, x), progress)
421
self.fetch_pack(determine_wants, graph_walker,
422
lambda x: os.write(fd, x), progress)
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)
325
class RemoteGitTagDict(tag.BasicTags):
327
def __init__(self, branch):
329
self.repository = branch.repository
331
def get_tag_dict(self):
333
for k, v in extract_tags(self.repository.get_refs()).iteritems():
334
tags[k] = self.branch.mapping.revision_id_foreign_to_bzr(v)
445
def revision_tree(self, revid):
446
raise GitSmartRemoteNotSupported(self.revision_tree, self)
448
def get_revisions(self, revids):
449
raise GitSmartRemoteNotSupported(self.get_revisions, self)
452
class RemoteGitTagDict(GitTags):
454
def get_refs_container(self):
455
return self.repository.bzrdir.get_refs_container()
337
457
def set_tag(self, name, revid):
338
458
# FIXME: Not supported yet, should do a push of a new ref
342
462
class RemoteGitBranch(GitBranch):
344
def __init__(self, bzrdir, repository, name, lockfiles):
464
def __init__(self, bzrdir, repository, name):
346
super(RemoteGitBranch, self).__init__(bzrdir, repository, name,
466
super(RemoteGitBranch, self).__init__(bzrdir, repository, name)
468
def last_revision_info(self):
469
raise GitSmartRemoteNotSupported(self.last_revision_info, self)
473
return self.control_url
476
def control_url(self):
349
479
def revision_history(self):
350
raise GitSmartRemoteNotSupported()
480
raise GitSmartRemoteNotSupported(self.revision_history, self)
482
def revision_id_to_revno(self, revision_id):
483
raise GitSmartRemoteNotSupported(self.revision_id_to_revno, self)
352
485
def last_revision(self):
353
486
return self.lookup_foreign_revision_id(self.head)
355
def _get_config(self):
356
class EmptyConfig(object):
358
def _get_configobj(self):
359
return config.ConfigObj()
365
490
if self._sha is not None:
367
heads = self.repository.get_refs()
368
name = self.bzrdir._branch_name_to_ref(self.name, "HEAD")
370
self._sha = heads[name]
372
raise NoSuchRef(self.name)
492
refs = self.bzrdir.get_refs_container()
493
name = branch_name_to_ref(self.name, "HEAD")
495
self._sha = refs[name]
497
raise NoSuchRef(name, self.repository.user_url, refs)
375
500
def _synchronize_history(self, destination, revision_id):