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 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
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 (
22
42
from bzrlib.tsort import topo_sort
44
from bzrlib.plugins.git.converter import (
24
47
from bzrlib.plugins.git.repository import (
29
from bzrlib.plugins.git.converter 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
52
from bzrlib.plugins.git.remote import (
39
57
class BzrFetchGraphWalker(object):
78
def import_git_blob(repo, mapping, path, blob, inv, parent_invs, gitmap, executable):
96
def import_git_blob(texts, mapping, path, blob, inv, parent_invs, shagitmap,
79
98
"""Import a git blob object into a bzr repository.
81
:param repo: bzr repository
100
:param texts: VersionedFiles to add to
82
101
:param path: Path in the tree
83
102
:param blob: A git blob
103
:return: Inventory entry
85
105
file_id = mapping.generate_file_id(path)
86
text_revision = inv.revision_id
87
repo.texts.add_lines((file_id, text_revision),
88
[(file_id, p[file_id].revision) for p in parent_invs if file_id in p],
89
osutils.split_lines(blob.data))
90
106
ie = inv.add_path(path, "file", file_id)
91
ie.revision = text_revision
92
107
ie.text_size = len(blob.data)
93
108
ie.text_sha1 = osutils.sha_string(blob.data)
94
109
ie.executable = executable
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):
110
# See if this is the same revision as one of the parents unchanged
112
for pinv in parent_invs:
113
if not file_id in pinv:
115
if pinv[file_id].text_sha1 == ie.text_sha1:
116
ie.revision = pinv[file_id].revision
118
parent_keys.append((file_id, pinv[file_id].revision))
119
ie.revision = inv.revision_id
120
assert file_id is not None
121
assert ie.revision is not None
122
texts.add_lines((file_id, ie.revision), parent_keys,
123
osutils.split_lines(blob.data))
124
shagitmap.add_entry(blob.sha().hexdigest(), "blob",
125
(ie.file_id, ie.revision))
129
def import_git_tree(texts, mapping, path, tree, inv, parent_invs, shagitmap,
100
131
"""Import a git tree object into a bzr repository.
102
:param repo: A Bzr repository object
133
:param texts: VersionedFiles object to add to
103
134
:param path: Path in the tree
104
135
:param tree: A git tree object
105
136
:param inv: Inventory object
107
138
file_id = mapping.generate_file_id(path)
108
text_revision = inv.revision_id
109
repo.texts.add_lines((file_id, text_revision),
110
[(file_id, p[file_id].revision) for p in parent_invs if file_id in p],
112
139
ie = inv.add_path(path, "directory", file_id)
113
ie.revision = text_revision
114
gitmap._idmap.add_entry(tree.sha().hexdigest(), "tree", (file_id, text_revision))
142
for pinv in parent_invs:
143
if not file_id in pinv:
146
tree_sha = shagitmap.lookup_tree(path, pinv[file_id].revision)
150
if tree_sha == tree.id:
151
ie.revision = pinv[file_id].revision
153
parent_keys.append((file_id, pinv[file_id].revision))
154
if ie.revision is None:
155
ie.revision = inv.revision_id
156
texts.add_lines((file_id, ie.revision), parent_keys, [])
157
shagitmap.add_entry(tree.id, "tree", (file_id, ie.revision))
115
158
for mode, name, hexsha in tree.entries():
116
159
entry_kind = (mode & 0700000) / 0100000
117
160
basename = name.decode("utf-8")
119
162
child_path = name
121
164
child_path = urlutils.join(path, name)
165
obj = lookup_object(hexsha)
122
166
if entry_kind == 0:
123
tree = lookup_object(hexsha)
124
import_git_tree(repo, mapping, child_path, tree, inv, parent_invs, gitmap, lookup_object)
167
import_git_tree(texts, mapping, child_path, obj, inv, parent_invs,
168
shagitmap, lookup_object)
125
169
elif entry_kind == 1:
126
blob = lookup_object(hexsha)
127
170
fs_mode = mode & 0777
128
import_git_blob(repo, mapping, child_path, blob, inv, parent_invs, gitmap, bool(fs_mode & 0111))
171
import_git_blob(texts, mapping, child_path, obj, inv, parent_invs,
172
shagitmap, bool(fs_mode & 0111))
130
174
raise AssertionError("Unknown blob kind, perms=%r." % (mode,))
133
178
def import_git_objects(repo, mapping, object_iter, target_git_object_retriever,
167
213
return object_iter[sha]
168
214
return target_git_object_retriever[sha]
169
215
parent_invs = [repo.get_inventory(r) for r in rev.parent_ids]
170
import_git_tree(repo, mapping, "", root_tree, inv, parent_invs,
171
target_git_object_retriever, lookup_object)
216
import_git_tree(repo.texts, mapping, "", root_tree, inv, parent_invs,
217
target_git_object_retriever._idmap, lookup_object)
172
218
repo.add_revision(rev.revision_id, rev, inv)
219
target_git_object_retriever._idmap.commit()
175
222
class InterGitNonGitRepository(InterRepository):
177
_matching_repo_format = GitFormat()
224
_matching_repo_format = GitRepositoryFormat()
180
227
def _get_repo_format_to_test():
213
260
create_pb.finished()
215
262
def fetch(self, revision_id=None, pb=None, find_ghosts=False,
263
mapping=None, fetch_spec=None):
264
self.fetch_refs(revision_id=revision_id, pb=pb, find_ghosts=find_ghosts,
265
mapping=mapping, fetch_spec=fetch_spec)
267
def fetch_refs(self, revision_id=None, pb=None, find_ghosts=False,
268
mapping=None, fetch_spec=None):
217
269
if mapping is None:
218
270
mapping = self.source.get_mapping()
219
def determine_wants(heads):
220
if revision_id is None:
271
if revision_id is not None:
272
interesting_heads = [revision_id]
273
elif fetch_spec is not None:
274
interesting_heads = fetch_spec.heads
276
interesting_heads = None
278
def determine_wants(refs):
280
if interesting_heads is None:
281
ret = [sha for (ref, sha) in refs.iteritems() if not ref.endswith("^{}")]
223
ret = [mapping.revision_id_bzr_to_foreign(revision_id)[0]]
283
ret = [mapping.revision_id_bzr_to_foreign(revid)[0] for revid in interesting_heads]
224
284
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)
285
self.fetch_objects(determine_wants, mapping, pb)
228
289
def is_compatible(source, target):
246
307
self.fetch(revision_id, pb, find_ghosts=False)
248
309
def fetch(self, revision_id=None, pb=None, find_ghosts=False,
310
mapping=None, fetch_spec=None):
250
311
if mapping is None:
251
312
mapping = self.source.get_mapping()
252
313
def progress(text):
253
info("git: %s", text)
314
trace.info("git: %s", text)
254
315
r = self.target._git
255
if revision_id is None:
256
determine_wants = lambda x: [y for y in x.values() if not y in r.object_store]
316
if revision_id is not None:
258
317
args = [mapping.revision_id_bzr_to_foreign(revision_id)[0]]
318
elif fetch_spec is not None:
319
args = [mapping.revision_id_bzr_to_foreign(revid)[0] for revid in fetch_spec.heads]
320
if fetch_spec is None and revision_id is None:
321
determine_wants = r.object_store.determine_wants_all
259
323
determine_wants = lambda x: [y for y in args if not y in r.object_store]
261
325
graphwalker = SimpleFetchGraphWalker(r.heads().values(), r.get_parents)