116
119
super(BzrGitMapping, self).__init__(foreign_git)
118
121
def __eq__(self, other):
119
return type(self) == type(other) and self.revid_prefix == other.revid_prefix
122
return (type(self) == type(other) and
123
self.revid_prefix == other.revid_prefix)
122
126
def revision_id_foreign_to_bzr(cls, git_rev_id):
123
127
"""Convert a git revision id handle to a Bazaar revision id."""
128
if git_rev_id == "0" * 40:
124
130
return "%s:%s" % (cls.revid_prefix, git_rev_id)
145
151
def import_unusual_file_modes(self, rev, unusual_file_modes):
146
152
if unusual_file_modes:
147
ret = [(name, unusual_file_modes[name]) for name in sorted(unusual_file_modes.keys())]
153
ret = [(name, unusual_file_modes[name])
154
for name in sorted(unusual_file_modes.keys())]
148
155
rev.properties['file-modes'] = bencode.bencode(ret)
150
157
def export_unusual_file_modes(self, rev):
156
def _generate_git_svn_metadata(self, rev):
163
def _generate_git_svn_metadata(self, rev, encoding):
158
return "\ngit-svn-id: %s\n" % rev.properties["git-svn-id"].encode("utf-8")
165
return "\ngit-svn-id: %s\n" % rev.properties["git-svn-id"].encode(encoding)
197
204
rev.properties['hg:renames'] = base64.b64encode(bencode.bencode([(new, old) for (old, new) in renames.iteritems()]))
200
def _decode_commit_message(self, rev, message):
201
return message.decode("utf-8", "replace")
207
def _decode_commit_message(self, rev, message, encoding):
208
return message.decode(encoding)
203
def _encode_commit_message(self, rev, message):
204
return message.encode("utf-8")
210
def _encode_commit_message(self, rev, message, encoding):
211
return message.encode(encoding)
206
213
def export_commit(self, rev, tree_sha, parent_lookup):
207
214
"""Turn a Bazaar revision in to a Git commit
214
221
commit = Commit()
215
222
commit.tree = tree_sha
216
223
for p in rev.parent_ids:
217
git_p = parent_lookup(p)
225
git_p = parent_lookup(p)
218
228
if git_p is not None:
219
229
assert len(git_p) == 40, "unexpected length for %r" % git_p
220
230
commit.parents.append(git_p)
221
commit.committer = fix_person_identifier(rev.committer.encode("utf-8"))
222
commit.author = fix_person_identifier(rev.get_apparent_authors()[0].encode("utf-8"))
232
encoding = rev.properties['git-explicit-encoding']
234
encoding = rev.properties.get('git-implicit-encoding', 'utf-8')
235
commit.encoding = rev.properties.get('git-explicit-encoding')
236
commit.committer = fix_person_identifier(rev.committer.encode(
238
commit.author = fix_person_identifier(
239
rev.get_apparent_authors()[0].encode(encoding))
223
240
commit.commit_time = long(rev.timestamp)
224
241
if 'author-timestamp' in rev.properties:
225
242
commit.author_time = long(rev.properties['author-timestamp'])
230
247
commit.author_timezone = int(rev.properties['author-timezone'])
232
249
commit.author_timezone = commit.commit_timezone
233
commit.message = self._encode_commit_message(rev, rev.message)
250
commit.message = self._encode_commit_message(rev, rev.message,
236
254
def import_commit(self, commit):
242
260
raise AssertionError("Commit object can't be None")
243
261
rev = ForeignRevision(commit.id, self, self.revision_id_foreign_to_bzr(commit.id))
244
262
rev.parent_ids = tuple([self.revision_id_foreign_to_bzr(p) for p in commit.parents])
245
rev.committer = str(commit.committer).decode("utf-8", "replace")
246
if commit.committer != commit.author:
247
rev.properties['author'] = str(commit.author).decode("utf-8", "replace")
263
def decode_using_encoding(rev, commit, encoding):
264
rev.committer = str(commit.committer).decode(encoding)
265
if commit.committer != commit.author:
266
rev.properties['author'] = str(commit.author).decode(encoding)
267
rev.message = self._decode_commit_message(rev, commit.message,
269
if commit.encoding is not None:
270
rev.properties['git-explicit-encoding'] = commit.encoding
271
decode_using_encoding(rev, commit, commit.encoding)
273
for encoding in ('utf-8', 'latin1'):
275
decode_using_encoding(rev, commit, encoding)
276
except UnicodeDecodeError:
279
if encoding != 'utf-8':
280
rev.properties['git-implicit-encoding'] = encoding
249
282
if commit.commit_time != commit.author_time:
250
283
rev.properties['author-timestamp'] = str(commit.author_time)
251
284
if commit.commit_timezone != commit.author_timezone:
252
285
rev.properties['author-timezone'] = "%d" % (commit.author_timezone, )
253
286
rev.timestamp = commit.commit_time
254
287
rev.timezone = commit.commit_timezone
255
rev.message = self._decode_commit_message(rev, commit.message)
268
300
revid_prefix = 'git-experimental'
269
301
experimental = True
271
def _decode_commit_message(self, rev, message):
303
def _decode_commit_message(self, rev, message, encoding):
272
304
message = self._extract_hg_metadata(rev, message)
273
305
message = self._extract_git_svn_metadata(rev, message)
274
return message.decode("utf-8", "replace")
306
return message.decode(encoding)
276
def _encode_commit_message(self, rev, message):
277
ret = message.encode("utf-8")
308
def _encode_commit_message(self, rev, message, encoding):
309
ret = message.encode(encoding)
278
310
ret += self._generate_hg_message_tail(rev)
279
ret += self._generate_git_svn_metadata(rev)
311
ret += self._generate_git_svn_metadata(rev, encoding)
282
314
def import_commit(self, commit):
289
321
"""Registry with available git mappings."""
291
323
def revision_id_bzr_to_foreign(self, bzr_revid):
324
if bzr_revid == NULL_REVISION:
325
return "0" * 20, None
292
326
if not bzr_revid.startswith("git-"):
293
327
raise errors.InvalidRevisionId(bzr_revid, None)
294
328
(mapping_version, git_sha) = bzr_revid.split(":", 1)
336
370
default_mapping = mapping_registry.get_default()()
339
def text_to_blob(texts, entry):
340
from dulwich.objects import Blob
341
text = texts.get_record_stream([(entry.file_id, entry.revision)], 'unordered', True).next().get_bytes_as('fulltext')
347
373
def symlink_to_blob(entry):
348
374
from dulwich.objects import Blob
350
blob._text = entry.symlink_target
376
symlink_target = entry.symlink_target
377
if type(symlink_target) == unicode:
378
symlink_target = symlink_target.encode('utf-8')
379
blob.data = symlink_target
402
434
def directory_to_tree(entry, lookup_ie_sha1, unusual_modes):
403
435
from dulwich.objects import Tree
405
for name in sorted(entry.children.keys()):
437
for name, value in entry.children.iteritems():
406
438
ie = entry.children[name]
408
440
mode = unusual_modes[ie.file_id]
444
475
for path, entry in inventory.iter_entries():
445
476
while stack and not path.startswith(osutils.pathjoin(cur, "")):
446
477
# We've hit a file that's not a child of the previous path
449
479
yield sha, tree, cur.encode("utf-8")
450
480
mode = unusual_modes.get(cur.encode("utf-8"), stat.S_IFDIR)
460
490
if entry.kind == "file":
461
blob = text_to_blob(texts, entry)
491
from dulwich.objects import Blob
492
text = texts.get_record_stream([(entry.file_id, entry.revision)], 'unordered', True).next().get_bytes_as('fulltext')
462
495
elif entry.kind == "symlink":
463
496
blob = symlink_to_blob(entry)
470
503
tree.add(mode, name, sha)
472
505
while len(stack) > 1:
475
507
yield sha, tree, cur.encode("utf-8")
476
508
mode = unusual_modes.get(cur.encode('utf-8'), stat.S_IFDIR)