15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
17
from bzrlib import osutils, ui, urlutils
18
from bzrlib.errors import InvalidRevisionId
18
from bzrlib.errors import InvalidRevisionId, NoSuchRevision
19
19
from bzrlib.inventory import Inventory
20
20
from bzrlib.repository import InterRepository
21
21
from bzrlib.trace import info
77
def import_git_blob(repo, mapping, path, blob, inv, parent_invs, executable):
78
def import_git_blob(repo, mapping, path, blob, inv, parent_invs, gitmap, executable):
78
79
"""Import a git blob object into a bzr repository.
80
81
:param repo: bzr repository
91
92
ie.text_size = len(blob.data)
92
93
ie.text_sha1 = osutils.sha_string(blob.data)
93
94
ie.executable = executable
96
def import_git_tree(repo, mapping, path, tree, inv, parent_invs, lookup_object):
95
gitmap._idmap.add_entry(blob.sha().hexdigest(), "blob", (ie.file_id, ie.revision))
98
def import_git_tree(repo, mapping, path, tree, inv, parent_invs,
99
gitmap, lookup_object):
97
100
"""Import a git tree object into a bzr repository.
99
102
:param repo: A Bzr repository object
109
112
ie = inv.add_path(path, "directory", file_id)
110
113
ie.revision = text_revision
114
gitmap._idmap.add_entry(tree.sha().hexdigest(), "tree", (file_id, text_revision))
111
115
for mode, name, hexsha in tree.entries():
112
116
entry_kind = (mode & 0700000) / 0100000
113
117
basename = name.decode("utf-8")
117
121
child_path = urlutils.join(path, name)
118
122
if entry_kind == 0:
119
123
tree = lookup_object(hexsha)
120
import_git_tree(repo, mapping, child_path, tree, inv, parent_invs, lookup_object)
124
import_git_tree(repo, mapping, child_path, tree, inv, parent_invs, gitmap, lookup_object)
121
125
elif entry_kind == 1:
122
126
blob = lookup_object(hexsha)
123
127
fs_mode = mode & 0777
124
import_git_blob(repo, mapping, child_path, blob, inv, parent_invs, bool(fs_mode & 0111))
128
import_git_blob(repo, mapping, child_path, blob, inv, parent_invs, gitmap, bool(fs_mode & 0111))
126
130
raise AssertionError("Unknown blob kind, perms=%r." % (mode,))
129
def import_git_objects(repo, mapping, num_objects, object_iter, pb=None):
133
def import_git_objects(repo, mapping, object_iter, target_git_object_retriever,
130
135
"""Import a set of git objects into a bzr repository.
132
137
:param repo: Bazaar repository
133
138
:param mapping: Mapping to use
134
:param num_objects: Number of objects.
135
139
:param object_iter: Iterator over Git objects.
137
141
# TODO: a more (memory-)efficient implementation of this
139
for i, (o, _) in enumerate(object_iter):
141
pb.update("fetching objects", i, num_objects)
146
145
# Find and convert commit objects
147
for o in objects.itervalues():
146
for o in object_iter.iterobjects():
148
147
if isinstance(o, Commit):
149
148
rev = mapping.import_commit(o)
150
root_trees[rev.revision_id] = objects[o.tree]
149
root_trees[rev.revision_id] = object_iter[o.tree]
151
150
revisions[rev.revision_id] = rev
152
151
graph.append((rev.revision_id, rev.parent_ids))
152
target_git_object_retriever._idmap.add_entry(o.sha().hexdigest(), "commit", (rev.revision_id, o._tree))
153
153
# Order the revisions
154
154
# Create the inventory objects
155
155
for i, revid in enumerate(topo_sort(graph)):
163
163
inv = Inventory()
164
164
inv.revision_id = rev.revision_id
165
165
def lookup_object(sha):
168
return reconstruct_git_object(repo, mapping, sha)
166
if sha in object_iter:
167
return object_iter[sha]
168
return target_git_object_retriever[sha]
169
169
parent_invs = [repo.get_inventory(r) for r in rev.parent_ids]
170
170
import_git_tree(repo, mapping, "", root_tree, inv, parent_invs,
171
target_git_object_retriever, lookup_object)
172
172
repo.add_revision(rev.revision_id, rev, inv)
175
def reconstruct_git_commit(repo, rev):
176
raise NotImplementedError(self.reconstruct_git_commit)
179
def reconstruct_git_object(repo, mapping, sha):
181
revid = mapping.revision_id_foreign_to_bzr(sha)
183
rev = repo.get_revision(revid)
184
except NoSuchRevision:
187
return reconstruct_git_commit(rev)
191
raise KeyError("No such object %s" % sha)
194
175
class InterGitNonGitRepository(InterRepository):
196
177
_matching_repo_format = GitFormat()
203
184
"""See InterRepository.copy_content."""
204
185
self.fetch(revision_id, pb, find_ghosts=False)
206
def fetch(self, revision_id=None, pb=None, find_ghosts=False,
209
mapping = self.source.get_mapping()
187
def fetch_objects(self, determine_wants, mapping, pb=None):
210
188
def progress(text):
211
189
pb.update("git: %s" % text.rstrip("\r\n"), 0, 0)
212
def determine_wants(heads):
213
if revision_id is None:
216
ret = [mapping.revision_id_bzr_to_foreign(revision_id)[0]]
217
return [rev for rev in ret if not self.target.has_revision(mapping.revision_id_foreign_to_bzr(rev))]
218
190
graph_walker = BzrFetchGraphWalker(self.target, mapping)
221
193
create_pb = pb = ui.ui_factory.nested_progress_bar()
194
target_git_object_retriever = GitObjectConverter(self.target, mapping)
223
197
self.target.lock_write()
225
199
self.target.start_write_group()
227
(num_objects, objects_iter) = \
228
self.source.fetch_objects(determine_wants,
229
graph_walker, progress)
230
import_git_objects(self.target, mapping, num_objects,
201
objects_iter = self.source.fetch_objects(determine_wants,
203
target_git_object_retriever.__getitem__,
205
import_git_objects(self.target, mapping, objects_iter,
206
target_git_object_retriever, pb)
233
208
self.target.commit_write_group()
238
213
create_pb.finished()
215
def fetch(self, revision_id=None, pb=None, find_ghosts=False,
218
mapping = self.source.get_mapping()
219
def determine_wants(heads):
220
if revision_id is None:
223
ret = [mapping.revision_id_bzr_to_foreign(revision_id)[0]]
224
return [rev for rev in ret if not self.target.has_revision(mapping.revision_id_foreign_to_bzr(rev))]
225
return self.fetch_objects(determine_wants, mapping, pb)
241
228
def is_compatible(source, target):
242
229
"""Be compatible with GitRepository."""