1
# Copyright (C) 2009 Jelmer Vernooij <jelmer@samba.org>
2
# -*- coding: utf-8 -*-
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
from dulwich.objects import (
24
from dulwich.repo import (
36
from bzrlib.branch import (
39
from bzrlib.bzrdir import (
42
from bzrlib.inventory import (
45
from bzrlib.repository import (
48
from bzrlib.tests import (
49
TestCaseWithTransport,
52
from bzrlib.plugins.git.fetch import (
57
from bzrlib.plugins.git.mapping import (
61
from bzrlib.plugins.git.tests import (
66
class RepositoryFetchTests(object):
68
def make_git_repo(self, path):
70
return GitRepo.init(os.path.abspath(path))
72
def clone_git_repo(self, from_url, to_url, revision_id=None):
73
oldrepos = self.open_git_repo(from_url)
74
dir = BzrDir.create(to_url)
75
newrepos = dir.create_repository()
76
oldrepos.copy_content_into(newrepos, revision_id=revision_id)
80
self.make_git_repo("d")
81
newrepos = self.clone_git_repo("d", "f")
82
self.assertEquals([], newrepos.all_revision_ids())
84
def make_onerev_branch(self):
85
self.make_git_repo("d")
87
bb = GitBranchBuilder()
88
bb.set_file("foobar", "foo\nbar\n", False)
89
mark = bb.commit("Somebody <somebody@someorg.org>", "mymsg")
90
gitsha = bb.finish()[mark]
94
def test_single_rev(self):
95
path, gitsha = self.make_onerev_branch()
96
oldrepo = self.open_git_repo(path)
97
newrepo = self.clone_git_repo(path, "f")
98
revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)
99
self.assertEquals([revid], newrepo.all_revision_ids())
101
def test_single_rev_specific(self):
102
path, gitsha = self.make_onerev_branch()
103
oldrepo = self.open_git_repo(path)
104
revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)
105
newrepo = self.clone_git_repo(path, "f", revision_id=revid)
106
self.assertEquals([revid], newrepo.all_revision_ids())
108
def test_incremental(self):
109
self.make_git_repo("d")
111
bb = GitBranchBuilder()
112
bb.set_file("foobar", "foo\nbar\n", False)
113
mark1 = bb.commit("Somebody <somebody@someorg.org>", "mymsg")
114
bb.set_file("foobar", "fooll\nbar\n", False)
115
mark2 = bb.commit("Somebody <somebody@someorg.org>", "nextmsg")
117
gitsha1 = marks[mark1]
118
gitsha2 = marks[mark2]
120
oldrepo = self.open_git_repo("d")
121
revid1 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha1)
122
newrepo = self.clone_git_repo("d", "f", revision_id=revid1)
123
self.assertEquals([revid1], newrepo.all_revision_ids())
124
revid2 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha2)
125
newrepo.fetch(oldrepo, revision_id=revid2)
126
self.assertEquals(set([revid1, revid2]), set(newrepo.all_revision_ids()))
128
def test_dir_becomes_symlink(self):
129
self.make_git_repo("d")
131
bb = GitBranchBuilder()
132
bb.set_file("mylink/somefile", "foo\nbar\n", False)
133
mark1 = bb.commit("Somebody <somebody@someorg.org>", "mymsg1")
134
bb.set_symlink("mylink", "target/")
135
mark2 = bb.commit("Somebody <somebody@someorg.org>", "mymsg2")
137
gitsha1 = marks[mark1]
138
gitsha2 = marks[mark2]
140
oldrepo = self.open_git_repo("d")
141
newrepo = self.clone_git_repo("d", "f")
142
revid1 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha1)
143
revid2 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha2)
144
tree1 = newrepo.revision_tree(revid1)
145
tree2 = newrepo.revision_tree(revid2)
146
fileid = tree1.path2id("mylink")
147
self.assertEquals(revid1, tree1.get_file_revision(fileid))
148
self.assertEquals("directory", tree1.kind(fileid))
149
self.assertEquals(None, tree1.get_symlink_target(fileid))
150
self.assertEquals(revid2, tree2.get_file_revision(fileid))
151
self.assertEquals("symlink", tree2.kind(fileid))
152
self.assertEquals("target/", tree2.get_symlink_target(fileid))
154
def test_symlink_becomes_dir(self):
155
self.make_git_repo("d")
157
bb = GitBranchBuilder()
158
bb.set_symlink("mylink", "target/")
159
mark1 = bb.commit("Somebody <somebody@someorg.org>", "mymsg1")
160
bb.set_file("mylink/somefile", "foo\nbar\n", False)
161
mark2 = bb.commit("Somebody <somebody@someorg.org>", "mymsg2")
163
gitsha1 = marks[mark1]
164
gitsha2 = marks[mark2]
166
oldrepo = self.open_git_repo("d")
167
newrepo = self.clone_git_repo("d", "f")
168
revid1 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha1)
169
revid2 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha2)
170
tree1 = newrepo.revision_tree(revid1)
171
tree2 = newrepo.revision_tree(revid2)
172
fileid = tree1.path2id("mylink")
173
self.assertEquals(revid1, tree1.get_file_revision(fileid))
174
self.assertEquals("symlink", tree1.kind(fileid))
175
self.assertEquals("target/", tree1.get_symlink_target(fileid))
176
self.assertEquals(revid2, tree2.get_file_revision(fileid))
177
self.assertEquals("directory", tree2.kind(fileid))
178
self.assertEquals(None, tree2.get_symlink_target(fileid))
180
def test_changing_symlink(self):
181
self.make_git_repo("d")
183
bb = GitBranchBuilder()
184
bb.set_symlink("mylink", "target")
185
mark1 = bb.commit("Somebody <somebody@someorg.org>", "mymsg1")
186
bb.set_symlink("mylink", "target/")
187
mark2 = bb.commit("Somebody <somebody@someorg.org>", "mymsg2")
189
gitsha1 = marks[mark1]
190
gitsha2 = marks[mark2]
192
oldrepo = self.open_git_repo("d")
193
newrepo = self.clone_git_repo("d", "f")
194
revid1 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha1)
195
revid2 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha2)
196
tree1 = newrepo.revision_tree(revid1)
197
tree2 = newrepo.revision_tree(revid2)
198
fileid = tree1.path2id("mylink")
199
self.assertEquals(revid1, tree1.get_file_revision(fileid))
200
self.assertEquals("target", tree1.get_symlink_target(fileid))
201
self.assertEquals(revid2, tree2.get_file_revision(fileid))
202
self.assertEquals("target/", tree2.get_symlink_target(fileid))
204
def test_executable(self):
205
self.make_git_repo("d")
207
bb = GitBranchBuilder()
208
bb.set_file("foobar", "foo\nbar\n", True)
209
bb.set_file("notexec", "foo\nbar\n", False)
210
mark = bb.commit("Somebody <somebody@someorg.org>", "mymsg")
211
gitsha = bb.finish()[mark]
213
oldrepo = self.open_git_repo("d")
214
newrepo = self.clone_git_repo("d", "f")
215
revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)
216
tree = newrepo.revision_tree(revid)
217
self.assertTrue(tree.has_filename("foobar"))
218
self.assertEquals(True, tree.is_executable(tree.path2id("foobar")))
219
self.assertTrue(tree.has_filename("notexec"))
220
self.assertEquals(False, tree.is_executable(tree.path2id("notexec")))
222
def test_becomes_executable(self):
223
self.make_git_repo("d")
225
bb = GitBranchBuilder()
226
bb.set_file("foobar", "foo\nbar\n", False)
227
mark1 = bb.commit("Somebody <somebody@someorg.org>", "mymsg")
228
bb.set_file("foobar", "foo\nbar\n", True)
229
mark2 = bb.commit("Somebody <somebody@someorg.org>", "mymsg")
230
gitsha2 = bb.finish()[mark2]
232
oldrepo = self.open_git_repo("d")
233
newrepo = self.clone_git_repo("d", "f")
234
revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha2)
235
tree = newrepo.revision_tree(revid)
236
self.assertTrue(tree.has_filename("foobar"))
237
fileid = tree.path2id("foobar")
238
self.assertEquals(True, tree.is_executable(fileid))
239
self.assertEquals(revid, tree.get_file_revision(fileid))
241
def test_into_stacked_on(self):
242
r = self.make_git_repo("d")
244
bb = GitBranchBuilder()
245
bb.set_file(u"foobar", "foo\n", False)
246
mark1 = bb.commit("Somebody <somebody@someorg.org>", "mymsg1")
247
gitsha1 = bb.finish()[mark1]
249
stacked_on = self.clone_git_repo("d", "stacked-on")
250
oldrepo = Repository.open("d")
251
revid1 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha1)
252
self.assertEquals([revid1], stacked_on.all_revision_ids())
253
b = stacked_on.bzrdir.create_branch()
254
b.generate_revision_history(revid1)
255
self.assertEquals(b.last_revision(), revid1)
256
tree = self.make_branch_and_tree("stacked")
257
tree.branch.set_stacked_on_url(b.user_url)
259
bb = GitBranchBuilder()
260
bb.set_file(u"barbar", "bar\n", False)
261
bb.set_file(u"foo/blie/bla", "bla\n", False)
262
mark2 = bb.commit("Somebody <somebody@someorg.org>", "mymsg2")
263
gitsha2 = bb.finish()[mark2]
264
revid2 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha2)
266
tree.branch.fetch(Branch.open("d"))
267
tree.branch.repository.check()
268
self.addCleanup(tree.lock_read().unlock)
271
tree.branch.repository.revisions.without_fallbacks().keys())
273
set([revid1, revid2]),
274
set(tree.branch.repository.all_revision_ids()))
276
def test_non_ascii_characters(self):
277
self.make_git_repo("d")
279
bb = GitBranchBuilder()
280
bb.set_file(u"foőbar", "foo\nbar\n", False)
281
mark = bb.commit("Somebody <somebody@someorg.org>", "mymsg")
282
gitsha = bb.finish()[mark]
284
oldrepo = self.open_git_repo("d")
285
newrepo = self.clone_git_repo("d", "f")
286
revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)
287
tree = newrepo.revision_tree(revid)
288
self.assertTrue(tree.has_filename(u"foőbar"))
290
def test_tagged_tree(self):
291
r = self.make_git_repo("d")
293
bb = GitBranchBuilder()
294
bb.set_file("foobar", "fooll\nbar\n", False)
295
mark = bb.commit("Somebody <somebody@someorg.org>", "nextmsg")
300
tag.tag_time = time.time()
302
tag.tagger = "Somebody <somebody@example.com>"
303
tag.message = "Created tag pointed at tree"
304
tag.object = (Tree, r[gitsha].tree)
305
r.object_store.add_object(tag)
306
r["refs/tags/sometag"] = tag
308
oldrepo = self.open_git_repo("d")
309
revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)
310
newrepo = self.clone_git_repo("d", "f")
311
self.assertEquals(set([revid]), set(newrepo.all_revision_ids()))
314
class LocalRepositoryFetchTests(RepositoryFetchTests, TestCaseWithTransport):
316
def open_git_repo(self, path):
317
return Repository.open(path)
320
class DummyStoreUpdater(object):
322
def add_object(self, obj, ie, path):
329
class ImportObjects(TestCaseWithTransport):
332
super(ImportObjects, self).setUp()
333
self._mapping = BzrGitMappingv1()
334
factory = knit.make_file_factory(True, versionedfile.PrefixMapper())
335
self._texts = factory(self.get_transport('texts'))
337
def test_import_blob_simple(self):
338
blob = Blob.from_string("bar")
339
base_inv = Inventory()
340
objs = { "blobname": blob}
341
ret = import_git_blob(self._texts, self._mapping, "bla", "bla",
343
base_inv, None, "somerevid", [], objs.__getitem__,
344
(None, DEFAULT_FILE_MODE), DummyStoreUpdater(),
345
self._mapping.generate_file_id)
346
self.assertEquals(set([('bla', 'somerevid')]), self._texts.keys())
347
self.assertEquals(self._texts.get_record_stream([('bla', 'somerevid')],
348
"unordered", True).next().get_bytes_as("fulltext"), "bar")
349
self.assertEquals(1, len(ret))
350
self.assertEquals(None, ret[0][0])
351
self.assertEquals("bla", ret[0][1])
353
self.assertEquals(False, ie.executable)
354
self.assertEquals("file", ie.kind)
355
self.assertEquals("somerevid", ie.revision)
356
self.assertEquals(osutils.sha_strings(["bar"]), ie.text_sha1)
358
def test_import_tree_empty_root(self):
359
base_inv = Inventory(root_id=None)
361
ret, child_modes = import_git_tree(self._texts, self._mapping, "", "",
362
(None, tree.id), base_inv,
363
None, "somerevid", [], {tree.id: tree}.__getitem__,
364
(None, stat.S_IFDIR), DummyStoreUpdater(),
365
self._mapping.generate_file_id)
366
self.assertEquals(child_modes, {})
367
self.assertEquals(set([("TREE_ROOT", 'somerevid')]), self._texts.keys())
368
self.assertEquals(1, len(ret))
369
self.assertEquals(None, ret[0][0])
370
self.assertEquals("", ret[0][1])
372
self.assertEquals(False, ie.executable)
373
self.assertEquals("directory", ie.kind)
374
self.assertEquals({}, ie.children)
375
self.assertEquals("somerevid", ie.revision)
376
self.assertEquals(None, ie.text_sha1)
378
def test_import_tree_empty(self):
379
base_inv = Inventory()
381
ret, child_modes = import_git_tree(self._texts, self._mapping, "bla", "bla",
382
(None, tree.id), base_inv, None, "somerevid", [],
383
{ tree.id: tree }.__getitem__,
384
(None, stat.S_IFDIR), DummyStoreUpdater(),
385
self._mapping.generate_file_id)
386
self.assertEquals(child_modes, {})
387
self.assertEquals(set([("bla", 'somerevid')]), self._texts.keys())
388
self.assertEquals(1, len(ret))
389
self.assertEquals(None, ret[0][0])
390
self.assertEquals("bla", ret[0][1])
392
self.assertEquals("directory", ie.kind)
393
self.assertEquals(False, ie.executable)
394
self.assertEquals({}, ie.children)
395
self.assertEquals("somerevid", ie.revision)
396
self.assertEquals(None, ie.text_sha1)
398
def test_import_tree_with_file(self):
399
base_inv = Inventory()
400
blob = Blob.from_string("bar1")
402
tree.add("foo", stat.S_IFREG | 0644, blob.id)
403
objects = { blob.id: blob, tree.id: tree }
404
ret, child_modes = import_git_tree(self._texts, self._mapping, "bla", "bla",
405
(None, tree.id), base_inv, None, "somerevid", [],
406
objects.__getitem__, (None, stat.S_IFDIR), DummyStoreUpdater(),
407
self._mapping.generate_file_id)
408
self.assertEquals(child_modes, {})
409
self.assertEquals(2, len(ret))
410
self.assertEquals(None, ret[0][0])
411
self.assertEquals("bla", ret[0][1])
412
self.assertEquals(None, ret[1][0])
413
self.assertEquals("bla/foo", ret[1][1])
415
self.assertEquals("directory", ie.kind)
417
self.assertEquals("file", ie.kind)
418
self.assertEquals("bla/foo", ie.file_id)
419
self.assertEquals("somerevid", ie.revision)
420
self.assertEquals(osutils.sha_strings(["bar1"]), ie.text_sha1)
421
self.assertEquals(False, ie.executable)
423
def test_import_tree_with_unusual_mode_file(self):
424
base_inv = Inventory()
425
blob = Blob.from_string("bar1")
427
tree.add("foo", stat.S_IFREG | 0664, blob.id)
428
objects = { blob.id: blob, tree.id: tree }
429
ret, child_modes = import_git_tree(self._texts, self._mapping,
430
"bla", "bla", (None, tree.id), base_inv, None, "somerevid", [],
431
objects.__getitem__, (None, stat.S_IFDIR), DummyStoreUpdater(),
432
self._mapping.generate_file_id)
433
self.assertEquals(child_modes, { "bla/foo": stat.S_IFREG | 0664 })
435
def test_import_tree_with_file_exe(self):
436
base_inv = Inventory(root_id=None)
437
blob = Blob.from_string("bar")
439
tree.add("foo", 0100755, blob.id)
440
objects = { blob.id: blob, tree.id: tree }
441
ret, child_modes = import_git_tree(self._texts, self._mapping, "", "",
442
(None, tree.id), base_inv, None, "somerevid", [],
443
objects.__getitem__, (None, stat.S_IFDIR), DummyStoreUpdater(),
444
self._mapping.generate_file_id)
445
self.assertEquals(child_modes, {})
446
self.assertEquals(2, len(ret))
447
self.assertEquals(None, ret[0][0])
448
self.assertEquals("", ret[0][1])
449
self.assertEquals(None, ret[1][0])
450
self.assertEquals("foo", ret[1][1])
452
self.assertEquals("directory", ie.kind)
454
self.assertEquals("file", ie.kind)
455
self.assertEquals(True, ie.executable)
457
def test_directory_converted_to_submodule(self):
458
base_inv = Inventory()
459
base_inv.add_path("foo", "directory")
460
base_inv.add_path("foo/bar", "file")
461
othertree = Blob.from_string("someotherthing")
462
blob = Blob.from_string("bar")
464
tree.add("bar", 0160000, blob.id)
465
objects = { tree.id: tree }
466
ret, child_modes = import_git_submodule(self._texts, self._mapping, "foo", "foo",
467
(tree.id, othertree.id), base_inv, base_inv.root.file_id, "somerevid", [],
468
objects.__getitem__, (stat.S_IFDIR | 0755, S_IFGITLINK), DummyStoreUpdater(),
469
self._mapping.generate_file_id)
470
self.assertEquals(child_modes, {})
471
self.assertEquals(2, len(ret))
472
self.assertEquals(ret[0], ("foo/bar", None, base_inv.path2id("foo/bar"), None))
473
self.assertEquals(ret[1][:3], ("foo", "foo", self._mapping.generate_file_id("foo")))
475
self.assertEquals(ie.kind, "tree-reference")