1
# Copyright (C) 2008 Jelmer Vernooij <jelmer@samba.org>
1
# Copyright (C) 2008 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
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 StringIO
19
from dulwich.client import (
20
SimpleFetchGraphWalker,
22
from dulwich.objects import (
32
from bzrlib.errors import (
36
from bzrlib.inventory import (
39
from bzrlib.repository import (
17
from bzrlib import osutils, ui, urlutils
18
from bzrlib.errors import InvalidRevisionId, NoSuchRevision
19
from bzrlib.inventory import Inventory
20
from bzrlib.repository import InterRepository
21
from bzrlib.trace import info
42
22
from bzrlib.tsort import topo_sort
44
from bzrlib.plugins.git.converter import (
47
24
from bzrlib.plugins.git.repository import (
52
from bzrlib.plugins.git.remote import (
29
from bzrlib.plugins.git.shamap import GitObjectConverter
30
from bzrlib.plugins.git.remote import RemoteGitRepository
33
from dulwich.client import SimpleFetchGraphWalker
34
from dulwich.objects import Commit
36
from cStringIO import StringIO
57
39
class BzrFetchGraphWalker(object):
96
def import_git_blob(texts, mapping, path, blob, inv, parent_invs, shagitmap,
78
def import_git_blob(repo, mapping, path, blob, inv, parent_invs, executable):
98
79
"""Import a git blob object into a bzr repository.
100
:param texts: VersionedFiles to add to
81
:param repo: bzr repository
101
82
:param path: Path in the tree
102
83
:param blob: A git blob
104
85
file_id = mapping.generate_file_id(path)
105
86
text_revision = inv.revision_id
106
assert file_id is not None
107
assert text_revision is not None
108
texts.add_lines((file_id, text_revision),
87
repo.texts.add_lines((file_id, text_revision),
109
88
[(file_id, p[file_id].revision) for p in parent_invs if file_id in p],
110
89
osutils.split_lines(blob.data))
111
90
ie = inv.add_path(path, "file", file_id)
113
92
ie.text_size = len(blob.data)
114
93
ie.text_sha1 = osutils.sha_string(blob.data)
115
94
ie.executable = executable
116
shagitmap.add_entry(blob.sha().hexdigest(), "blob",
117
(ie.file_id, ie.revision))
120
def import_git_tree(texts, mapping, path, tree, inv, parent_invs, shagitmap,
97
def import_git_tree(repo, mapping, path, tree, inv, parent_invs, lookup_object):
122
98
"""Import a git tree object into a bzr repository.
124
:param texts: VersionedFiles object to add to
100
:param repo: A Bzr repository object
125
101
:param path: Path in the tree
126
102
:param tree: A git tree object
127
103
:param inv: Inventory object
129
105
file_id = mapping.generate_file_id(path)
130
106
text_revision = inv.revision_id
131
texts.add_lines((file_id, text_revision),
107
repo.texts.add_lines((file_id, text_revision),
132
108
[(file_id, p[file_id].revision) for p in parent_invs if file_id in p],
134
110
ie = inv.add_path(path, "directory", file_id)
135
111
ie.revision = text_revision
136
shagitmap.add_entry(tree.id, "tree", (file_id, text_revision))
137
112
for mode, name, hexsha in tree.entries():
138
113
entry_kind = (mode & 0700000) / 0100000
139
114
basename = name.decode("utf-8")
141
116
child_path = name
143
118
child_path = urlutils.join(path, name)
144
obj = lookup_object(hexsha)
145
119
if entry_kind == 0:
146
import_git_tree(texts, mapping, child_path, obj, inv, parent_invs,
147
shagitmap, lookup_object)
120
tree = lookup_object(hexsha)
121
import_git_tree(repo, mapping, child_path, tree, inv, parent_invs, lookup_object)
148
122
elif entry_kind == 1:
123
blob = lookup_object(hexsha)
149
124
fs_mode = mode & 0777
150
import_git_blob(texts, mapping, child_path, obj, inv, parent_invs,
151
shagitmap, bool(fs_mode & 0111))
125
import_git_blob(repo, mapping, child_path, blob, inv, parent_invs, bool(fs_mode & 0111))
153
127
raise AssertionError("Unknown blob kind, perms=%r." % (mode,))
172
146
root_trees[rev.revision_id] = object_iter[o.tree]
173
147
revisions[rev.revision_id] = rev
174
148
graph.append((rev.revision_id, rev.parent_ids))
175
target_git_object_retriever._idmap.add_entry(o.sha().hexdigest(),
176
"commit", (rev.revision_id, o._tree))
177
149
# Order the revisions
178
150
# Create the inventory objects
179
151
for i, revid in enumerate(topo_sort(graph)):
189
161
def lookup_object(sha):
190
162
if sha in object_iter:
191
163
return object_iter[sha]
192
return target_git_object_retriever[sha]
164
return target_git_object_retriever(sha)
193
165
parent_invs = [repo.get_inventory(r) for r in rev.parent_ids]
194
import_git_tree(repo.texts, mapping, "", root_tree, inv, parent_invs,
195
target_git_object_retriever._idmap, lookup_object)
166
import_git_tree(repo, mapping, "", root_tree, inv, parent_invs,
196
168
repo.add_revision(rev.revision_id, rev, inv)
171
def reconstruct_git_object(repo, mapping, sha):
172
import pdb; pdb.set_trace()
176
raise KeyError("No such object %s" % sha)
199
179
class InterGitNonGitRepository(InterRepository):
201
181
_matching_repo_format = GitFormat()
237
217
create_pb.finished()
239
219
def fetch(self, revision_id=None, pb=None, find_ghosts=False,
240
mapping=None, fetch_spec=None):
241
self.fetch_refs(revision_id=revision_id, pb=pb, find_ghosts=find_ghosts,
242
mapping=mapping, fetch_spec=fetch_spec)
244
def fetch_refs(self, revision_id=None, pb=None, find_ghosts=False,
245
mapping=None, fetch_spec=None):
246
221
if mapping is None:
247
222
mapping = self.source.get_mapping()
248
if revision_id is not None:
249
interesting_heads = [revision_id]
250
elif fetch_spec is not None:
251
interesting_heads = fetch_spec.heads
253
interesting_heads = None
255
def determine_wants(refs):
257
if interesting_heads is None:
258
ret = [sha for (ref, sha) in refs.iteritems() if not ref.endswith("^{}")]
223
def determine_wants(heads):
224
if revision_id is None:
260
ret = [mapping.revision_id_bzr_to_foreign(revid)[0] for revid in interesting_heads]
227
ret = [mapping.revision_id_bzr_to_foreign(revision_id)[0]]
261
228
return [rev for rev in ret if not self.target.has_revision(mapping.revision_id_foreign_to_bzr(rev))]
262
self.fetch_objects(determine_wants, mapping, pb)
229
return self.fetch_objects(determine_wants, mapping, pb)
266
232
def is_compatible(source, target):
284
250
self.fetch(revision_id, pb, find_ghosts=False)
286
252
def fetch(self, revision_id=None, pb=None, find_ghosts=False,
287
mapping=None, fetch_spec=None):
288
254
if mapping is None:
289
255
mapping = self.source.get_mapping()
290
256
def progress(text):
291
trace.info("git: %s", text)
257
info("git: %s", text)
292
258
r = self.target._git
293
if revision_id is not None:
259
if revision_id is None:
260
determine_wants = lambda x: [y for y in x.values() if not y in r.object_store]
294
262
args = [mapping.revision_id_bzr_to_foreign(revision_id)[0]]
295
elif fetch_spec is not None:
296
args = [mapping.revision_id_bzr_to_foreign(revid)[0] for revid in fetch_spec.heads]
297
if fetch_spec is None and revision_id is None:
298
determine_wants = r.object_store.determine_wants_all
300
263
determine_wants = lambda x: [y for y in args if not y in r.object_store]
302
265
graphwalker = SimpleFetchGraphWalker(r.heads().values(), r.get_parents)