103
97
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)
119
100
class GitSmartTransport(Transport):
121
102
def __init__(self, url, _client=None):
137
118
raise NotImplementedError(self._get_client)
139
120
def _get_path(self):
140
return urlutils.split_segment_parameters_raw(self._path)[0]
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:
142
142
def get(self, path):
143
143
raise NoSuchFile(path)
184
183
self._client = None
186
185
location_config = config.LocationConfig(self.base)
187
client = dulwich.client.SSHGitClient(self._host, self._port, self._username,
186
client = git.client.SSHGitClient(self._host, self._port, self._username,
188
187
thin_packs=thin_packs, report_activity=self._report_activity)
189
188
# Set up alternate pack program paths
190
189
upload_pack = location_config.get_user_option('git_upload_pack')
199
198
class RemoteGitDir(GitDir):
201
def __init__(self, transport, lockfiles, format, get_client, client_path):
200
def __init__(self, transport, lockfiles, format):
202
201
self._format = format
203
202
self.root_transport = transport
204
203
self.transport = transport
205
204
self._lockfiles = lockfiles
206
205
self._mode_check_done = None
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
207
def _branch_name_to_ref(self, name, default=None):
208
return branch_name_to_ref(name, default=default)
237
210
def open_repository(self):
238
211
return RemoteGitRepository(self, self._lockfiles)
240
def open_branch(self, name=None, unsupported=False,
241
ignore_fallbacks=False):
213
def _open_branch(self, name=None, ignore_fallbacks=False,
242
215
repo = self.open_repository()
243
refname = self._get_selected_ref(name)
216
refname = self._branch_name_to_ref(name)
244
217
return RemoteGitBranch(self, repo, refname, self._lockfiles)
246
219
def open_workingtree(self, recommend_upgrade=False):
289
262
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)
343
265
class RemoteGitRepository(GitRepository):
345
267
def __init__(self, gitdir, lockfiles):
347
269
self._refs = None
351
return self.control_url
353
def get_parent_map(self, revids):
272
def inventories(self):
273
raise GitSmartRemoteNotSupported()
277
raise GitSmartRemoteNotSupported()
354
281
raise GitSmartRemoteNotSupported()
356
283
def get_refs(self):
357
284
if self._refs is not None:
358
285
return self._refs
359
self._refs = self.bzrdir.fetch_pack(lambda x: [], None,
286
self._refs = self.bzrdir.root_transport.fetch_pack(lambda x: [], None,
360
287
lambda x: None, lambda x: trace.mutter("git: %s" % x))
361
288
return self._refs
363
290
def fetch_pack(self, determine_wants, graph_walker, pack_data,
365
return self.bzrdir.fetch_pack(determine_wants, graph_walker,
292
return self._transport.fetch_pack(determine_wants, graph_walker,
366
293
pack_data, progress)
368
295
def send_pack(self, get_changed_refs, generate_pack_contents):
369
return self.bzrdir.send_pack(get_changed_refs, generate_pack_contents)
296
return self._transport.send_pack(get_changed_refs, generate_pack_contents)
371
298
def fetch_objects(self, determine_wants, graph_walker, resolve_ext_ref,
373
300
fd, path = tempfile.mkstemp(suffix=".pack")
375
self.fetch_pack(determine_wants, graph_walker,
376
lambda x: os.write(fd, x), progress)
301
self.fetch_pack(determine_wants, graph_walker,
302
lambda x: os.write(fd, x), progress)
379
304
if os.path.getsize(path) == 0:
380
305
return EmptyObjectStoreIterator()
381
306
return TemporaryPackIterator(path[:-len(".pack")], resolve_ext_ref)
397
322
return mapping.revision_id_foreign_to_bzr(foreign_revid)
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))
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)
410
337
def set_tag(self, name, revid):
411
338
# FIXME: Not supported yet, should do a push of a new ref