126
138
# Check what revision we should store
128
140
for ptree in parent_bzr_trees:
129
intertree = InterTree.get(ptree, base_bzr_tree)
131
ppath = intertree.find_source_paths(decoded_path, recurse='none')
132
except errors.NoSuchFile:
136
pkind = ptree.kind(ppath)
142
ppath = ptree.id2path(file_id)
143
except errors.NoSuchId:
145
pkind = ptree.kind(ppath, file_id)
137
146
if (pkind == ie.kind and
138
((pkind == "symlink" and ptree.get_symlink_target(ppath) == ie.symlink_target) or
139
(pkind == "file" and ptree.get_file_sha1(ppath) == ie.text_sha1 and
140
ptree.is_executable(ppath) == ie.executable))):
147
((pkind == "symlink" and ptree.get_symlink_target(ppath, file_id) == ie.symlink_target) or
148
(pkind == "file" and ptree.get_file_sha1(ppath, file_id) == ie.text_sha1 and
149
ptree.is_executable(ppath, file_id) == ie.executable))):
141
150
# found a revision in one of the parents to use
142
ie.revision = ptree.get_file_revision(ppath)
151
ie.revision = ptree.get_file_revision(ppath, file_id)
144
parent_key = (file_id, ptree.get_file_revision(ppath))
145
if parent_key not in parent_keys:
153
parent_key = (file_id, ptree.get_file_revision(ppath, file_id))
154
if not parent_key in parent_keys:
146
155
parent_keys.append(parent_key)
147
156
if ie.revision is None:
148
157
# Need to store a new revision
155
164
chunks = blob.chunked
156
165
texts.insert_record_stream([
157
166
ChunkedContentFactory((file_id, ie.revision),
158
tuple(parent_keys), ie.text_sha1, chunks)])
167
tuple(parent_keys), ie.text_sha1, chunks)])
160
169
if base_hexsha is not None:
161
old_path = decoded_path # Renames are not supported yet
170
old_path = path.decode("utf-8") # Renames are not supported yet
162
171
if stat.S_ISDIR(base_mode):
163
invdelta.extend(remove_disappeared_children(
164
base_bzr_tree, old_path, lookup_object(base_hexsha), [],
172
invdelta.extend(remove_disappeared_children(base_bzr_tree, old_path,
173
lookup_object(base_hexsha), [], lookup_object))
168
invdelta.append((old_path, decoded_path, file_id, ie))
176
new_path = path.decode("utf-8")
177
invdelta.append((old_path, new_path, file_id, ie))
169
178
if base_hexsha != hexsha:
170
179
store_updater.add_object(blob, (ie.file_id, ie.revision), path)
180
189
def import_git_submodule(texts, mapping, path, name, hexshas,
181
base_bzr_tree, parent_id, revision_id,
182
parent_bzr_trees, lookup_object,
183
modes, store_updater, lookup_file_id):
190
base_bzr_tree, parent_id, revision_id, parent_bzr_trees, lookup_object,
191
modes, store_updater, lookup_file_id):
184
192
"""Import a git submodule."""
185
193
(base_hexsha, hexsha) = hexshas
186
194
(base_mode, mode) = modes
187
195
if base_hexsha == hexsha and base_mode == mode:
189
path = path.decode('utf-8')
190
197
file_id = lookup_file_id(path)
192
199
ie = TreeReference(file_id, name.decode("utf-8"), parent_id)
193
200
ie.revision = revision_id
194
201
if base_hexsha is not None:
195
old_path = path # Renames are not supported yet
202
old_path = path.decode("utf-8") # Renames are not supported yet
196
203
if stat.S_ISDIR(base_mode):
197
invdelta.extend(remove_disappeared_children(
198
base_bzr_tree, old_path, lookup_object(base_hexsha), [],
204
invdelta.extend(remove_disappeared_children(base_bzr_tree, old_path,
205
lookup_object(base_hexsha), [], lookup_object))
202
208
ie.reference_revision = mapping.revision_id_foreign_to_bzr(hexsha)
231
237
ret.append((c_path, None, file_id, None))
232
238
if stat.S_ISDIR(mode):
233
239
ret.extend(remove_disappeared_children(
234
base_bzr_tree, c_path, lookup_object(hexsha), [],
240
base_bzr_tree, c_path, lookup_object(hexsha), [], lookup_object))
239
244
def import_git_tree(texts, mapping, path, name, hexshas,
240
base_bzr_tree, parent_id, revision_id, parent_bzr_trees,
241
lookup_object, modes, store_updater,
242
lookup_file_id, allow_submodules=False):
245
base_bzr_tree, parent_id, revision_id, parent_bzr_trees,
246
lookup_object, modes, store_updater,
247
lookup_file_id, allow_submodules=False):
243
248
"""Import a git tree object into a bzr repository.
245
250
:param texts: VersionedFiles object to add to
246
251
:param path: Path in the tree (str)
247
252
:param name: Name of the tree (str)
248
253
:param tree: A git tree object
249
:param base_bzr_tree: Base inventory against which to return inventory
254
:param base_bzr_tree: Base inventory against which to return inventory delta
251
255
:return: Inventory delta for this subtree
253
257
(base_hexsha, hexsha) = hexshas
254
258
(base_mode, mode) = modes
255
if not isinstance(path, bytes):
259
if type(path) is not str:
256
260
raise TypeError(path)
257
if not isinstance(name, bytes):
261
if type(name) is not str:
258
262
raise TypeError(name)
259
263
if base_hexsha == hexsha and base_mode == mode:
260
264
# If nothing has changed since the base revision, we're done
263
file_id = lookup_file_id(osutils.safe_unicode(path))
267
file_id = lookup_file_id(path)
264
268
# We just have to hope this is indeed utf-8:
265
269
ie = InventoryDirectory(file_id, name.decode("utf-8"), parent_id)
266
270
tree = lookup_object(hexsha)
267
271
if base_hexsha is None:
269
old_path = None # Newly appeared here
273
old_path = None # Newly appeared here
271
275
base_tree = lookup_object(base_hexsha)
272
old_path = path.decode("utf-8") # Renames aren't supported yet
276
old_path = path.decode("utf-8") # Renames aren't supported yet
273
277
new_path = path.decode("utf-8")
274
278
if base_tree is None or type(base_tree) is not Tree:
275
279
ie.revision = revision_id
292
296
child_base_hexsha = None
293
297
child_base_mode = 0
294
298
if stat.S_ISDIR(child_mode):
295
subinvdelta, grandchildmodes = import_git_tree(
296
texts, mapping, child_path, name,
297
(child_base_hexsha, child_hexsha), base_bzr_tree, file_id,
298
revision_id, parent_bzr_trees, lookup_object,
299
(child_base_mode, child_mode), store_updater, lookup_file_id,
300
allow_submodules=allow_submodules)
301
elif S_ISGITLINK(child_mode): # submodule
299
subinvdelta, grandchildmodes = import_git_tree(texts, mapping,
300
child_path, name, (child_base_hexsha, child_hexsha),
301
base_bzr_tree, file_id, revision_id, parent_bzr_trees,
302
lookup_object, (child_base_mode, child_mode), store_updater,
303
lookup_file_id, allow_submodules=allow_submodules)
304
elif S_ISGITLINK(child_mode): # submodule
302
305
if not allow_submodules:
303
306
raise SubmodulesRequireSubtrees()
304
subinvdelta, grandchildmodes = import_git_submodule(
305
texts, mapping, child_path, name,
306
(child_base_hexsha, child_hexsha),
307
subinvdelta, grandchildmodes = import_git_submodule(texts, mapping,
308
child_path, name, (child_base_hexsha, child_hexsha),
307
309
base_bzr_tree, file_id, revision_id, parent_bzr_trees,
308
310
lookup_object, (child_base_mode, child_mode), store_updater,
311
313
if not mapping.is_special_file(name):
312
subinvdelta = import_git_blob(
313
texts, mapping, child_path, name,
314
subinvdelta = import_git_blob(texts, mapping, child_path, name,
314
315
(child_base_hexsha, child_hexsha), base_bzr_tree, file_id,
315
316
revision_id, parent_bzr_trees, lookup_object,
316
(child_base_mode, child_mode), store_updater,
317
(child_base_mode, child_mode), store_updater, lookup_file_id)
320
320
grandchildmodes = {}
321
321
child_modes.update(grandchildmodes)
322
322
invdelta.extend(subinvdelta)
323
323
if child_mode not in (stat.S_IFDIR, DEFAULT_FILE_MODE,
324
stat.S_IFLNK, DEFAULT_FILE_MODE | 0o111,
324
stat.S_IFLNK, DEFAULT_FILE_MODE|0o111,
326
326
child_modes[child_path] = child_mode
327
327
# Remove any children that have disappeared
328
328
if base_tree is not None and type(base_tree) is Tree:
329
invdelta.extend(remove_disappeared_children(
330
base_bzr_tree, old_path, base_tree, existing_children,
329
invdelta.extend(remove_disappeared_children(base_bzr_tree, old_path,
330
base_tree, existing_children, lookup_object))
332
331
store_updater.add_object(tree, (file_id, revision_id), path)
333
332
return invdelta, child_modes
336
335
def verify_commit_reconstruction(target_git_object_retriever, lookup_object,
337
o, rev, ret_tree, parent_trees, mapping,
338
unusual_modes, verifiers):
336
o, rev, ret_tree, parent_trees, mapping, unusual_modes, verifiers):
339
337
new_unusual_modes = mapping.export_unusual_file_modes(rev)
340
338
if new_unusual_modes != unusual_modes:
341
339
raise AssertionError("unusual modes don't match: %r != %r" % (
342
340
unusual_modes, new_unusual_modes))
343
341
# Verify that we can reconstruct the commit properly
344
342
rec_o = target_git_object_retriever._reconstruct_commit(rev, o.tree, True,
347
345
raise AssertionError("Reconstructed commit differs: %r != %r" % (
351
for path, obj, ie in _tree_to_objects(
352
ret_tree, parent_trees, target_git_object_retriever._cache.idmap,
353
unusual_modes, mapping.BZR_DUMMY_FILE):
349
for path, obj, ie in _tree_to_objects(ret_tree, parent_trees,
350
target_git_object_retriever._cache.idmap, unusual_modes,
351
mapping.BZR_DUMMY_FILE):
354
352
old_obj_id = tree_lookup_path(lookup_object, o.tree, path)[1]
355
353
new_objs[path] = obj
356
354
if obj.id != old_obj_id:
357
355
diff.append((path, lookup_object(old_obj_id), obj))
358
356
for (path, old_obj, new_obj) in diff:
359
while (old_obj.type_name == "tree"
360
and new_obj.type_name == "tree"
361
and sorted(old_obj) == sorted(new_obj)):
357
while (old_obj.type_name == "tree" and
358
new_obj.type_name == "tree" and
359
sorted(old_obj) == sorted(new_obj)):
362
360
for name in old_obj:
363
361
if old_obj[name][0] != new_obj[name][0]:
364
raise AssertionError(
365
"Modes for %s differ: %o != %o" %
362
raise AssertionError("Modes for %s differ: %o != %o" %
366
363
(path, old_obj[name][0], new_obj[name][0]))
367
364
if old_obj[name][1] != new_obj[name][1]:
368
365
# Found a differing child, delve deeper
407
404
base_tree = lookup_object(o.parents[0]).tree
408
405
base_mode = stat.S_IFDIR
409
406
store_updater = target_git_object_retriever._get_updater(rev)
410
inv_delta, unusual_modes = import_git_tree(
411
repo.texts, mapping, b"", b"", (base_tree, o.tree), base_bzr_tree,
412
None, rev.revision_id, parent_trees, lookup_object,
413
(base_mode, stat.S_IFDIR), store_updater,
414
mapping.generate_file_id,
415
allow_submodules=repo._format.supports_tree_reference)
407
tree_supplement = mapping.get_fileid_map(lookup_object, o.tree)
408
inv_delta, unusual_modes = import_git_tree(repo.texts,
409
mapping, "", "", (base_tree, o.tree), base_bzr_tree,
410
None, rev.revision_id, parent_trees,
411
lookup_object, (base_mode, stat.S_IFDIR), store_updater,
412
tree_supplement.lookup_file_id,
413
allow_submodules=repo._format.supports_tree_reference)
416
414
if unusual_modes != {}:
417
415
for path, mode in unusual_modes.iteritems():
418
416
warn_unusual_mode(rev.foreign_revid, path, mode)
424
422
base_bzr_inventory = None
426
424
base_bzr_inventory = base_bzr_tree.root_inventory
427
rev.inventory_sha1, inv = repo.add_inventory_by_delta(
428
basis_id, inv_delta, rev.revision_id, rev.parent_ids,
425
rev.inventory_sha1, inv = repo.add_inventory_by_delta(basis_id,
426
inv_delta, rev.revision_id, rev.parent_ids,
430
428
ret_tree = InventoryRevisionTree(repo, inv, rev.revision_id)
431
429
# Check verifiers
432
430
if verifiers and roundtrip_revid is not None:
433
431
testament = StrictTestament3(rev, ret_tree)
434
calculated_verifiers = {"testament3-sha1": testament.as_sha1()}
432
calculated_verifiers = { "testament3-sha1": testament.as_sha1() }
435
433
if calculated_verifiers != verifiers:
436
434
trace.mutter("Testament SHA1 %r for %r did not match %r.",
437
435
calculated_verifiers["testament3-sha1"],
438
436
rev.revision_id, verifiers["testament3-sha1"])
439
437
rev.revision_id = original_revid
440
rev.inventory_sha1, inv = repo.add_inventory_by_delta(
441
basis_id, inv_delta, rev.revision_id, rev.parent_ids,
438
rev.inventory_sha1, inv = repo.add_inventory_by_delta(basis_id,
439
inv_delta, rev.revision_id, rev.parent_ids, base_bzr_tree)
443
440
ret_tree = InventoryRevisionTree(repo, inv, rev.revision_id)
445
442
calculated_verifiers = {}
448
445
trees_cache.add(ret_tree)
449
446
repo.add_revision(rev.revision_id, rev)
450
447
if "verify" in debug.debug_flags:
451
verify_commit_reconstruction(
452
target_git_object_retriever, lookup_object, o, rev, ret_tree,
453
parent_trees, mapping, unusual_modes, verifiers)
448
verify_commit_reconstruction(target_git_object_retriever,
449
lookup_object, o, rev, ret_tree, parent_trees, mapping,
450
unusual_modes, verifiers)
456
453
def import_git_objects(repo, mapping, object_iter,
457
target_git_object_retriever, heads, pb=None,
454
target_git_object_retriever, heads, pb=None, limit=None):
459
455
"""Import a set of git objects into a bzr repository.
461
457
:param repo: Target Bazaar repository