97
103
return (host, port, username, path)
106
def parse_git_error(url, message):
107
"""Parse a remote git server error and return a bzr exception.
109
:param url: URL of the remote repository
110
:param message: Message sent by the remote git server
112
message = str(message).strip()
113
if message.startswith("Could not find Repository "):
114
return NotBranchError(url, message)
115
# Don't know, just return it to the user as-is
116
return BzrError(message)
100
119
class GitSmartTransport(Transport):
102
121
def __init__(self, url, _client=None):
118
137
raise NotImplementedError(self._get_client)
120
139
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:
140
return urlutils.split_segment_parameters_raw(self._path)[0]
142
142
def get(self, path):
143
143
raise NoSuchFile(path)
183
184
self._client = None
185
186
location_config = config.LocationConfig(self.base)
186
client = git.client.SSHGitClient(self._host, self._port, self._username,
187
client = dulwich.client.SSHGitClient(self._host, self._port, self._username,
187
188
thin_packs=thin_packs, report_activity=self._report_activity)
188
189
# Set up alternate pack program paths
189
190
upload_pack = location_config.get_user_option('git_upload_pack')
198
199
class RemoteGitDir(GitDir):
200
def __init__(self, transport, lockfiles, format):
201
def __init__(self, transport, lockfiles, format, get_client, client_path):
201
202
self._format = format
202
203
self.root_transport = transport
203
204
self.transport = transport
204
205
self._lockfiles = lockfiles
205
206
self._mode_check_done = None
207
def _branch_name_to_ref(self, name, default=None):
208
return branch_name_to_ref(name, default=default)
207
self._get_client = get_client
208
self._client_path = client_path
210
def fetch_pack(self, determine_wants, graph_walker, pack_data, progress=None):
213
trace.info("git: %s" % text)
214
client = self._get_client(thin_packs=False)
216
return client.fetch_pack(self._client_path, determine_wants,
217
graph_walker, pack_data, progress)
218
except GitProtocolError, e:
219
raise parse_git_error(self.transport.external_url(), e)
221
def send_pack(self, get_changed_refs, generate_pack_contents):
222
client = self._get_client(thin_packs=False)
224
return client.send_pack(self._client_path, get_changed_refs,
225
generate_pack_contents)
226
except GitProtocolError, e:
227
raise parse_git_error(self.transport.external_url(), e)
231
return self.control_url
234
def user_transport(self):
235
return self.root_transport
210
237
def open_repository(self):
211
238
return RemoteGitRepository(self, self._lockfiles)
213
def _open_branch(self, name=None, ignore_fallbacks=False,
240
def open_branch(self, name=None, unsupported=False,
241
ignore_fallbacks=False):
215
242
repo = self.open_repository()
216
refname = self._branch_name_to_ref(name)
243
refname = self._get_selected_ref(name)
217
244
return RemoteGitBranch(self, repo, refname, self._lockfiles)
219
246
def open_workingtree(self, recommend_upgrade=False):
262
289
os.remove(self._data_path)
292
class BzrGitHttpClient(dulwich.client.HttpGitClient):
294
def __init__(self, transport, *args, **kwargs):
295
self.transport = transport
296
super(BzrGitHttpClient, self).__init__(transport.external_url(), *args, **kwargs)
298
self._http_perform = getattr(self.transport, "_perform", urllib2.urlopen)
300
def _perform(self, req):
301
req.accepted_errors = (200, 404)
302
req.follow_redirections = True
303
req.redirected_to = None
304
return self._http_perform(req)
307
class RemoteGitControlDirFormat(GitControlDirFormat):
308
"""The .git directory control format."""
310
supports_workingtrees = False
313
def _known_formats(self):
314
return set([RemoteGitControlDirFormat()])
316
def open(self, transport, _found=None):
317
"""Open this directory.
320
# we dont grok readonly - git isn't integrated with transport.
322
if url.startswith('readonly+'):
323
url = url[len('readonly+'):]
324
if isinstance(transport, GitSmartTransport):
325
get_client = transport._get_client
326
client_path = transport._get_path()
327
elif urlparse.urlsplit(transport.external_url())[0] in ("http", "https"):
328
def get_client(thin_packs=False):
329
return BzrGitHttpClient(transport, thin_packs=thin_packs)
330
client_path = transport._path
332
raise NotBranchError(transport.base)
333
lockfiles = GitLockableFiles(transport, GitLock())
334
return RemoteGitDir(transport, lockfiles, self, get_client, client_path)
336
def get_format_description(self):
337
return "Remote Git Repository"
339
def initialize_on_transport(self, transport):
340
raise UninitializableFormat(self)
265
343
class RemoteGitRepository(GitRepository):
267
345
def __init__(self, gitdir, lockfiles):
269
347
self._refs = None
272
def inventories(self):
273
raise GitSmartRemoteNotSupported()
277
raise GitSmartRemoteNotSupported()
351
return self.control_url
353
def get_parent_map(self, revids):
281
354
raise GitSmartRemoteNotSupported()
283
356
def get_refs(self):
284
357
if self._refs is not None:
285
358
return self._refs
286
self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
359
self._refs = self.bzrdir.fetch_pack(lambda x: [], None,
287
360
lambda x: None, lambda x: trace.mutter("git: %s" % x))
288
361
return self._refs
290
363
def fetch_pack(self, determine_wants, graph_walker, pack_data,
292
return self._transport.fetch_pack(determine_wants, graph_walker,
365
return self.bzrdir.fetch_pack(determine_wants, graph_walker,
293
366
pack_data, progress)
295
368
def send_pack(self, get_changed_refs, generate_pack_contents):
296
return self._transport.send_pack(get_changed_refs, generate_pack_contents)
369
return self.bzrdir.send_pack(get_changed_refs, generate_pack_contents)
298
371
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref,
300
373
fd, path = tempfile.mkstemp(suffix=".pack")
301
self.fetch_pack(determine_wants, graph_walker,
302
lambda x: os.write(fd, x), progress)
375
self.fetch_pack(determine_wants, graph_walker,
376
lambda x: os.write(fd, x), progress)
304
379
if os.path.getsize(path) == 0:
305
380
return EmptyObjectStoreIterator()
306
381
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
322
397
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)
400
class RemoteGitTagDict(GitTags):
403
return self.repository.get_refs()
405
def _iter_tag_refs(self, refs):
406
for k, (peeled, unpeeled) in extract_tags(refs).iteritems():
407
yield (k, peeled, unpeeled,
408
self.branch.mapping.revision_id_foreign_to_bzr(peeled))
337
410
def set_tag(self, name, revid):
338
411
# FIXME: Not supported yet, should do a push of a new ref