72
73
RemoteGitRepository,
74
75
from bzrlib.plugins.git.repository import (
76
77
GitRepositoryFormat,
77
78
LocalGitRepository,
81
def import_git_blob(texts, mapping, path, hexsha, base_inv, base_ie, parent_id,
82
def import_git_blob(texts, mapping, path, hexsha, base_inv, base_ie, parent_id,
82
83
revision_id, parent_invs, shagitmap, lookup_object, executable, symlink):
83
84
"""Import a git blob object into a bzr repository.
163
164
return (invdelta, shamap)
166
class SubmodulesNotSupported(BzrError):
168
_fmt = """Submodules can not yet be imported (requires nested tree support in Bazaar)."""
167
class SubmodulesRequireSubtrees(BzrError):
168
_fmt = """The repository you are fetching from contains submodules. Please run 'bzr upgrade --development-subtree'."""
172
def import_git_submodule(texts, mapping, path, hexsha, base_inv, base_ie,
172
def import_git_submodule(texts, mapping, path, hexsha, base_inv, base_ie,
173
173
parent_id, revision_id, parent_invs, shagitmap, lookup_object):
174
raise SubmodulesNotSupported()
174
file_id = mapping.generate_file_id(path)
175
ie = TreeReference(file_id, urlutils.basename(path.decode("utf-8")),
177
ie.revision = revision_id
182
if base_ie.kind == ie.kind and base_ie.reference_revision == ie.reference_revision:
183
ie.revision = base_ie.revision
184
ie.reference_revision = mapping.revision_id_foreign_to_bzr(hexsha)
185
texts.insert_record_stream([FulltextContentFactory((file_id, ie.revision), (), None, "")])
186
invdelta = [(oldpath, path, file_id, ie)]
187
return invdelta, {}, {}
177
190
def remove_disappeared_children(path, base_children, existing_children):
189
def import_git_tree(texts, mapping, path, hexsha, base_inv, base_ie, parent_id,
202
def import_git_tree(texts, mapping, path, hexsha, base_inv, base_ie, parent_id,
190
203
revision_id, parent_invs, shagitmap, lookup_object):
191
204
"""Import a git tree object into a bzr repository.
200
213
file_id = mapping.generate_file_id(path)
201
214
# We just have to hope this is indeed utf-8:
202
ie = InventoryDirectory(file_id, urlutils.basename(path.decode("utf-8")),
215
ie = InventoryDirectory(file_id, urlutils.basename(path.decode("utf-8")),
204
217
if base_ie is None:
205
218
# Newly appeared here
235
248
child_path = osutils.pathjoin(path, name)
236
249
if stat.S_ISDIR(mode):
237
250
subinvdelta, grandchildmodes, subshamap = import_git_tree(
238
texts, mapping, child_path, child_hexsha, base_inv,
251
texts, mapping, child_path, child_hexsha, base_inv,
239
252
base_children.get(basename), file_id, revision_id, parent_invs, shagitmap,
241
254
invdelta.extend(subinvdelta)
249
262
child_modes.update(grandchildmodes)
250
263
shamap.extend(subshamap)
252
subinvdelta, subshamap = import_git_blob(texts, mapping,
265
subinvdelta, subshamap = import_git_blob(texts, mapping,
253
266
child_path, child_hexsha, base_inv, base_children.get(basename), file_id,
254
revision_id, parent_invs, shagitmap, lookup_object,
267
revision_id, parent_invs, shagitmap, lookup_object,
255
268
mode_is_executable(mode), stat.S_ISLNK(mode))
256
269
invdelta.extend(subinvdelta)
257
270
shamap.extend(subshamap)
260
273
child_modes[child_path] = mode
261
274
# Remove any children that have disappeared
262
275
if base_ie is not None and base_ie.kind == "directory":
263
invdelta.extend(remove_disappeared_children(base_inv.id2path(file_id),
276
invdelta.extend(remove_disappeared_children(base_inv.id2path(file_id),
264
277
base_children, existing_children))
265
278
shamap.append((hexsha, "tree", (file_id, revision_id)))
266
279
return invdelta, child_modes, shamap
269
def import_git_objects(repo, mapping, object_iter, target_git_object_retriever,
282
def import_git_objects(repo, mapping, object_iter, target_git_object_retriever,
271
284
"""Import a set of git objects into a bzr repository.
305
318
root_trees[rev.revision_id] = o.tree
306
319
revisions[rev.revision_id] = rev
307
320
graph.append((rev.revision_id, rev.parent_ids))
308
target_git_object_retriever._idmap.add_entry(o.id, "commit",
321
target_git_object_retriever._idmap.add_entry(o.id, "commit",
309
322
(rev.revision_id, o.tree))
310
323
heads.extend([p for p in o.parents if p not in checked])
311
324
elif isinstance(o, Tag):
319
332
if pb is not None:
320
333
pb.update("fetching revisions", i, len(graph))
321
334
rev = revisions[revid]
322
# We have to do this here, since we have to walk the tree and
323
# we need to make sure to import the blobs / trees with the right
335
# We have to do this here, since we have to walk the tree and
336
# we need to make sure to import the blobs / trees with the right
324
337
# path; this may involve adding them more than once.
326
339
for parent_id in rev.parent_ids:
337
350
base_inv = parent_invs[0]
338
351
base_ie = base_inv.root
339
inv_delta, unusual_modes, shamap = import_git_tree(repo.texts,
340
mapping, "", root_trees[revid], base_inv, base_ie, None, revid,
352
inv_delta, unusual_modes, shamap = import_git_tree(repo.texts,
353
mapping, "", root_trees[revid], base_inv, base_ie, None, revid,
341
354
parent_invs, target_git_object_retriever._idmap, lookup_object)
342
355
target_git_object_retriever._idmap.add_entries(shamap)
343
356
if unusual_modes != {}:
389
402
class InterGitNonGitRepository(InterGitRepository):
390
"""Base InterRepository that copies revisions from a Git into a non-Git
403
"""Base InterRepository that copies revisions from a Git into a non-Git
393
def fetch_refs(self, revision_id=None, pb=None, find_ghosts=False,
406
def fetch_refs(self, revision_id=None, pb=None, find_ghosts=False,
394
407
mapping=None, fetch_spec=None):
395
408
if mapping is None:
396
409
mapping = self.source.get_mapping()
433
446
class InterRemoteGitNonGitRepository(InterGitNonGitRepository):
434
"""InterRepository that copies revisions from a remote Git into a non-Git
447
"""InterRepository that copies revisions from a remote Git into a non-Git
437
450
def get_target_heads(self):
465
478
self.target.start_write_group()
467
480
objects_iter = self.source.fetch_objects(
468
record_determine_wants, graph_walker,
481
record_determine_wants, graph_walker,
469
482
store.get_raw, progress)
470
import_git_objects(self.target, mapping, objects_iter,
483
import_git_objects(self.target, mapping, objects_iter,
471
484
store, recorded_wants, pb)
473
486
pack_hint = self.target.commit_write_group()
482
495
def is_compatible(source, target):
483
496
"""Be compatible with GitRepository."""
484
497
# FIXME: Also check target uses VersionedFile
485
return (isinstance(source, RemoteGitRepository) and
498
return (isinstance(source, RemoteGitRepository) and
486
499
target.supports_rich_root() and
487
500
not isinstance(target, GitRepository))
490
503
class InterLocalGitNonGitRepository(InterGitNonGitRepository):
491
"""InterRepository that copies revisions from a local Git into a non-Git
504
"""InterRepository that copies revisions from a local Git into a non-Git
494
507
def fetch_objects(self, determine_wants, mapping, pb=None):
503
516
self.target.start_write_group()
505
import_git_objects(self.target, mapping,
506
self.source._git.object_store,
518
import_git_objects(self.target, mapping,
519
self.source._git.object_store,
507
520
target_git_object_retriever, wants, pb)
509
522
pack_hint = self.target.commit_write_group()
518
531
def is_compatible(source, target):
519
532
"""Be compatible with GitRepository."""
520
533
# FIXME: Also check target uses VersionedFile
521
return (isinstance(source, LocalGitRepository) and
534
return (isinstance(source, LocalGitRepository) and
522
535
target.supports_rich_root() and
523
536
not isinstance(target, GitRepository))
531
544
trace.note("git: %s", text)
532
545
graphwalker = self.target._git.get_graph_walker()
533
546
if isinstance(self.source, LocalGitRepository) and isinstance(self.target, LocalGitRepository):
534
return self.source._git.fetch(self.target._git, determine_wants,
547
return self.source._git.fetch(self.target._git, determine_wants,
536
549
elif isinstance(self.source, LocalGitRepository) and isinstance(self.target, RemoteGitRepository):
537
550
raise NotImplementedError
549
562
raise AssertionError
551
def fetch_refs(self, revision_id=None, pb=None, find_ghosts=False,
564
def fetch_refs(self, revision_id=None, pb=None, find_ghosts=False,
552
565
mapping=None, fetch_spec=None, branches=None):
553
566
if mapping is None:
554
567
mapping = self.source.get_mapping()
570
583
def is_compatible(source, target):
571
584
"""Be compatible with GitRepository."""
572
return (isinstance(source, GitRepository) and
585
return (isinstance(source, GitRepository) and
573
586
isinstance(target, GitRepository))