14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
from cStringIO import (
21
17
from dulwich.objects import (
25
22
from dulwich.object_store import (
30
28
from bzrlib import (
84
def import_git_blob(texts, mapping, path, hexsha, base_inv, parent_id,
80
def import_git_blob(texts, mapping, path, hexsha, base_inv, base_ie, parent_id,
85
81
revision_id, parent_invs, shagitmap, lookup_object, executable, symlink):
86
82
"""Import a git blob object into a bzr repository.
98
94
# We just have to hope this is indeed utf-8:
99
95
ie = cls(file_id, urlutils.basename(path).decode("utf-8"), parent_id)
100
96
ie.executable = executable
102
97
# See if this has changed at all
104
base_ie = base_inv[file_id]
109
base_sha = base_ie.text_id
112
base_sha = shagitmap.lookup_blob(file_id, base_ie.revision)
102
base_sha = shagitmap.lookup_blob(file_id, base_ie.revision)
121
111
ie.text_size = base_ie.text_size
122
112
ie.text_sha1 = base_ie.text_sha1
123
113
ie.symlink_target = base_ie.symlink_target
124
ie.revision = base_ie.revision
114
if ie.executable == base_ie.executable:
115
ie.revision = base_ie.revision
117
blob = lookup_object(hexsha)
126
119
blob = lookup_object(hexsha)
127
120
if ie.kind == "symlink":
128
122
ie.symlink_target = blob.data
129
123
ie.text_size = None
130
124
ie.text_sha1 = None
157
151
shamap = [(hexsha, "blob", (ie.file_id, ie.revision))]
160
if file_id in base_inv:
155
if base_ie is not None:
161
156
old_path = base_inv.id2path(file_id)
157
if base_ie.kind == "directory":
158
invdelta.extend(remove_disappeared_children(old_path, base_ie.children, []))
164
return ([(old_path, path, file_id, ie)], shamap)
167
def import_git_tree(texts, mapping, path, hexsha, base_inv, parent_id,
161
invdelta.append((old_path, path, file_id, ie))
162
return (invdelta, shamap)
165
def import_git_submodule(texts, mapping, path, hexsha, base_inv, base_ie, parent_id,
166
revision_id, parent_invs, shagitmap, lookup_object):
167
raise NotImplementedError(import_git_submodule)
170
def remove_disappeared_children(path, base_children, existing_children):
172
deletable = [(osutils.pathjoin(path, k), v) for k,v in base_children.iteritems() if k not in existing_children]
174
(path, ie) = deletable.pop()
175
ret.append((path, None, ie.file_id, None))
176
if ie.kind == "directory":
177
for name, child_ie in ie.children.iteritems():
178
deletable.append((osutils.pathjoin(path, name), child_ie))
182
def import_git_tree(texts, mapping, path, hexsha, base_inv, base_ie, parent_id,
168
183
revision_id, parent_invs, shagitmap, lookup_object):
169
184
"""Import a git tree object into a bzr repository.
179
194
# We just have to hope this is indeed utf-8:
180
195
ie = InventoryDirectory(file_id, urlutils.basename(path.decode("utf-8")),
184
base_ie = base_inv[file_id]
186
198
# Newly appeared here
188
199
ie.revision = revision_id
189
texts.add_lines((file_id, ie.revision), (), [])
200
texts.insert_record_stream([FulltextContentFactory((file_id, ie.revision), (), None, "")])
190
201
invdelta.append((None, path, file_id, ie))
192
base_sha = base_ie.text_id
193
203
# See if this has changed at all
196
base_sha = shagitmap.lookup_tree(file_id, base_inv.revision_id)
205
base_sha = shagitmap.lookup_tree(file_id, base_inv.revision_id)
200
209
if base_sha == hexsha:
201
210
# If nothing has changed since the base revision, we're done
202
211
return [], {}, []
212
if base_ie.kind != "directory":
213
ie.revision = revision_id
214
texts.insert_record_stream([FulltextContentFactory((ie.file_id, ie.revision), (), None, "")])
215
invdelta.append((base_inv.id2path(ie.file_id), path, ie.file_id, ie))
216
if base_ie is not None and base_ie.kind == "directory":
217
base_children = base_ie.children
203
220
# Remember for next time
204
221
existing_children = set()
210
227
existing_children.add(basename)
211
228
child_path = osutils.pathjoin(path, name)
212
229
if stat.S_ISDIR(mode):
213
subinvdelta, grandchildmodes, subshamap = import_git_tree(texts,
214
mapping, child_path, child_hexsha, base_inv, file_id,
215
revision_id, parent_invs, shagitmap, lookup_object)
230
subinvdelta, grandchildmodes, subshamap = import_git_tree(
231
texts, mapping, child_path, child_hexsha, base_inv,
232
base_children.get(basename), file_id, revision_id, parent_invs, shagitmap,
234
invdelta.extend(subinvdelta)
235
child_modes.update(grandchildmodes)
236
shamap.extend(subshamap)
237
elif S_ISGITLINK(mode): # submodule
238
subinvdelta, grandchildmodes, subshamap = import_git_submodule(
239
texts, mapping, child_path, child_hexsha, base_inv, base_ie.get(basename),
240
file_id, revision_id, parent_invs, shagitmap, lookup_object)
216
241
invdelta.extend(subinvdelta)
217
242
child_modes.update(grandchildmodes)
218
243
shamap.extend(subshamap)
220
245
subinvdelta, subshamap = import_git_blob(texts, mapping,
221
child_path, child_hexsha, base_inv, file_id, revision_id,
222
parent_invs, shagitmap, lookup_object,
246
child_path, child_hexsha, base_inv, base_children.get(basename), file_id,
247
revision_id, parent_invs, shagitmap, lookup_object,
223
248
mode_is_executable(mode), stat.S_ISLNK(mode))
224
249
invdelta.extend(subinvdelta)
225
250
shamap.extend(subshamap)
227
252
stat.S_IFLNK, DEFAULT_FILE_MODE|0111):
228
253
child_modes[child_path] = mode
229
254
# Remove any children that have disappeared
230
if base_ie is not None and base_ie.kind == 'directory':
231
deletable = [v for k,v in base_ie.children.iteritems() if k not in existing_children]
234
invdelta.append((base_inv.id2path(ie.file_id), None, ie.file_id, None))
235
if ie.kind == "directory":
236
deletable.extend(ie.children.values())
255
if base_ie is not None and base_ie.kind == "directory":
256
invdelta.extend(remove_disappeared_children(base_inv.id2path(file_id),
257
base_children, existing_children))
237
258
shamap.append((hexsha, "tree", (file_id, revision_id)))
238
259
return invdelta, child_modes, shamap
272
293
rev = mapping.import_commit(o)
273
294
if repo.has_revision(rev.revision_id):
296
squash_revision(repo, rev)
275
297
root_trees[rev.revision_id] = o.tree
276
298
revisions[rev.revision_id] = rev
277
299
graph.append((rev.revision_id, rev.parent_ids))
302
324
parent_invs_cache[parent_id] = parent_inv
303
325
if parent_invs == []:
304
326
base_inv = Inventory(root_id=None)
306
329
base_inv = parent_invs[0]
330
base_ie = base_inv.root
307
331
inv_delta, unusual_modes, shamap = import_git_tree(repo.texts,
308
mapping, "", root_trees[revid], base_inv, None, revid,
332
mapping, "", root_trees[revid], base_inv, base_ie, None, revid,
309
333
parent_invs, target_git_object_retriever._idmap, lookup_object)
310
334
target_git_object_retriever._idmap.add_entries(shamap)
311
335
if unusual_modes != {}:
312
336
for path, mode in unusual_modes.iteritems():
313
337
warn_unusual_mode(rev.foreign_revid, path, mode)
338
mapping.import_unusual_file_modes(rev, unusual_modes)
315
340
basis_id = rev.parent_ids[0]
316
341
except IndexError:
320
345
parent_invs_cache[rev.revision_id] = inv
321
346
repo.add_revision(rev.revision_id, rev)
322
347
if "verify" in debug.debug_flags:
323
objs = inventory_to_tree_and_blobs(inv, repo.texts, mapping)
348
new_unusual_modes = mapping.export_unusual_file_modes(rev)
349
if new_unusual_modes != unusual_modes:
350
raise AssertionError("unusual modes don't match: %r != %r" % (unusual_modes, new_unusual_modes))
351
objs = inventory_to_tree_and_blobs(inv, repo.texts, mapping, unusual_modes)
324
352
for sha1, newobj, path in objs:
325
353
assert path is not None
326
354
oldobj = tree_lookup_path(lookup_object, root_trees[revid], path)
327
assert oldobj == newobj, "%r != %r in %s" % (oldobj, newobj, path)
356
raise AssertionError("%r != %r in %s" % (oldobj, newobj, path))
329
358
target_git_object_retriever._idmap.commit()
370
399
ret = [mapping.revision_id_bzr_to_foreign(revid)[0] for revid in interesting_heads if revid not in (None, NULL_REVISION)]
371
400
return [rev for rev in ret if not self.target.has_revision(mapping.revision_id_foreign_to_bzr(rev))]
372
self.fetch_objects(determine_wants, mapping, pb)
401
pack_hint = self.fetch_objects(determine_wants, mapping, pb)
402
if pack_hint is not None and self.target._format.pack_compresses:
403
self.target.pack(hint=pack_hint)
373
404
return self._refs
407
_GIT_PROGRESS_RE = re.compile(r"(.*?): +(\d+)% \((\d+)/(\d+)\)")
408
def report_git_progress(pb, text):
409
text = text.rstrip("\r\n")
410
g = _GIT_PROGRESS_RE.match(text)
412
(text, pct, current, total) = g.groups()
413
pb.update(text, int(current), int(total))
415
pb.update(text, 0, 0)
376
418
class InterRemoteGitNonGitRepository(InterGitNonGitRepository):
377
419
"""InterRepository that copies revisions from a remote Git into a non-Git
422
def get_target_heads(self):
423
# FIXME: This should be more efficient
424
all_revs = self.target.all_revision_ids()
425
parent_map = self.target.get_parent_map(all_revs)
427
map(all_parents.update, parent_map.itervalues())
428
return set(all_revs) - all_parents
380
430
def fetch_objects(self, determine_wants, mapping, pb=None):
381
431
def progress(text):
382
pb.update("git: %s" % text.rstrip("\r\n"), 0, 0)
432
report_git_progress(pb, text)
383
433
store = BazaarObjectStore(self.target, mapping)
384
434
self.target.lock_write()
386
heads = self.target.get_graph().heads(self.target.all_revision_ids())
436
heads = self.get_target_heads()
387
437
graph_walker = store.get_graph_walker(
388
438
[store._lookup_revision_sha1(head) for head in heads])
389
439
recorded_wants = []