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 (
38
from ....branch import (
41
from ....controldir import (
44
from ....bzr.inventory import (
47
from ....repository import (
50
from ....tests import (
51
TestCaseWithTransport,
59
from ..mapping import (
68
class RepositoryFetchTests(object):
70
def make_git_repo(self, path):
72
return GitRepo.init(os.path.abspath(path))
74
def clone_git_repo(self, from_url, to_url, revision_id=None):
75
oldrepos = self.open_git_repo(from_url)
76
dir = ControlDir.create(to_url)
77
newrepos = dir.create_repository()
78
oldrepos.copy_content_into(newrepos, revision_id=revision_id)
82
self.make_git_repo("d")
83
newrepos = self.clone_git_repo("d", "f")
84
self.assertEquals([], newrepos.all_revision_ids())
86
def make_onerev_branch(self):
87
self.make_git_repo("d")
89
bb = GitBranchBuilder()
90
bb.set_file("foobar", "foo\nbar\n", False)
91
mark = bb.commit("Somebody <somebody@someorg.org>", "mymsg")
92
gitsha = bb.finish()[mark]
96
def test_single_rev(self):
97
path, gitsha = self.make_onerev_branch()
98
oldrepo = self.open_git_repo(path)
99
newrepo = self.clone_git_repo(path, "f")
100
revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)
101
self.assertEquals([revid], newrepo.all_revision_ids())
103
def test_single_rev_specific(self):
104
path, gitsha = self.make_onerev_branch()
105
oldrepo = self.open_git_repo(path)
106
revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)
107
newrepo = self.clone_git_repo(path, "f", revision_id=revid)
108
self.assertEquals([revid], newrepo.all_revision_ids())
110
def test_incremental(self):
111
self.make_git_repo("d")
113
bb = GitBranchBuilder()
114
bb.set_file("foobar", "foo\nbar\n", False)
115
mark1 = bb.commit("Somebody <somebody@someorg.org>", "mymsg")
116
bb.set_file("foobar", "fooll\nbar\n", False)
117
mark2 = bb.commit("Somebody <somebody@someorg.org>", "nextmsg")
119
gitsha1 = marks[mark1]
120
gitsha2 = marks[mark2]
122
oldrepo = self.open_git_repo("d")
123
revid1 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha1)
124
newrepo = self.clone_git_repo("d", "f", revision_id=revid1)
125
self.assertEquals([revid1], newrepo.all_revision_ids())
126
revid2 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha2)
127
newrepo.fetch(oldrepo, revision_id=revid2)
128
self.assertEquals(set([revid1, revid2]), set(newrepo.all_revision_ids()))
130
def test_dir_becomes_symlink(self):
131
self.make_git_repo("d")
133
bb = GitBranchBuilder()
134
bb.set_file("mylink/somefile", "foo\nbar\n", False)
135
mark1 = bb.commit("Somebody <somebody@someorg.org>", "mymsg1")
136
bb.set_symlink("mylink", "target/")
137
mark2 = bb.commit("Somebody <somebody@someorg.org>", "mymsg2")
139
gitsha1 = marks[mark1]
140
gitsha2 = marks[mark2]
142
oldrepo = self.open_git_repo("d")
143
newrepo = self.clone_git_repo("d", "f")
144
revid1 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha1)
145
revid2 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha2)
146
tree1 = newrepo.revision_tree(revid1)
147
tree2 = newrepo.revision_tree(revid2)
148
self.assertEquals(revid1, tree1.get_file_revision("mylink"))
149
self.assertEquals("directory", tree1.kind("mylink"))
150
self.assertEquals(None, tree1.get_symlink_target("mylink"))
151
self.assertEquals(revid2, tree2.get_file_revision("mylink"))
152
self.assertEquals("symlink", tree2.kind("mylink"))
153
self.assertEquals("target/", tree2.get_symlink_target("mylink"))
155
def test_symlink_becomes_dir(self):
156
self.make_git_repo("d")
158
bb = GitBranchBuilder()
159
bb.set_symlink("mylink", "target/")
160
mark1 = bb.commit("Somebody <somebody@someorg.org>", "mymsg1")
161
bb.set_file("mylink/somefile", "foo\nbar\n", False)
162
mark2 = bb.commit("Somebody <somebody@someorg.org>", "mymsg2")
164
gitsha1 = marks[mark1]
165
gitsha2 = marks[mark2]
167
oldrepo = self.open_git_repo("d")
168
newrepo = self.clone_git_repo("d", "f")
169
revid1 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha1)
170
revid2 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha2)
171
tree1 = newrepo.revision_tree(revid1)
172
tree2 = newrepo.revision_tree(revid2)
173
self.assertEquals(revid1, tree1.get_file_revision("mylink"))
174
self.assertEquals("symlink", tree1.kind("mylink"))
175
self.assertEquals("target/", tree1.get_symlink_target("mylink"))
176
self.assertEquals(revid2, tree2.get_file_revision("mylink"))
177
self.assertEquals("directory", tree2.kind("mylink"))
178
self.assertEquals(None, tree2.get_symlink_target("mylink"))
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
self.assertEquals(revid1, tree1.get_file_revision("mylink"))
199
self.assertEquals("target", tree1.get_symlink_target("mylink"))
200
self.assertEquals(revid2, tree2.get_file_revision("mylink"))
201
self.assertEquals("target/", tree2.get_symlink_target("mylink"))
203
def test_executable(self):
204
self.make_git_repo("d")
206
bb = GitBranchBuilder()
207
bb.set_file("foobar", "foo\nbar\n", True)
208
bb.set_file("notexec", "foo\nbar\n", False)
209
mark = bb.commit("Somebody <somebody@someorg.org>", "mymsg")
210
gitsha = bb.finish()[mark]
212
oldrepo = self.open_git_repo("d")
213
newrepo = self.clone_git_repo("d", "f")
214
revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)
215
tree = newrepo.revision_tree(revid)
216
self.assertTrue(tree.has_filename("foobar"))
217
self.assertEquals(True, tree.is_executable("foobar"))
218
self.assertTrue(tree.has_filename("notexec"))
219
self.assertEquals(False, tree.is_executable("notexec"))
221
def test_becomes_executable(self):
222
self.make_git_repo("d")
224
bb = GitBranchBuilder()
225
bb.set_file("foobar", "foo\nbar\n", False)
226
mark1 = bb.commit("Somebody <somebody@someorg.org>", "mymsg")
227
bb.set_file("foobar", "foo\nbar\n", True)
228
mark2 = bb.commit("Somebody <somebody@someorg.org>", "mymsg")
229
gitsha2 = bb.finish()[mark2]
231
oldrepo = self.open_git_repo("d")
232
newrepo = self.clone_git_repo("d", "f")
233
revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha2)
234
tree = newrepo.revision_tree(revid)
235
self.assertTrue(tree.has_filename("foobar"))
236
self.assertEquals(True, tree.is_executable("foobar"))
237
self.assertEquals(revid, tree.get_file_revision("foobar"))
239
def test_into_stacked_on(self):
240
r = self.make_git_repo("d")
242
bb = GitBranchBuilder()
243
bb.set_file(u"foobar", "foo\n", False)
244
mark1 = bb.commit("Somebody <somebody@someorg.org>", "mymsg1")
245
gitsha1 = bb.finish()[mark1]
247
stacked_on = self.clone_git_repo("d", "stacked-on")
248
oldrepo = Repository.open("d")
249
revid1 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha1)
250
self.assertEquals([revid1], stacked_on.all_revision_ids())
251
b = stacked_on.controldir.create_branch()
252
b.generate_revision_history(revid1)
253
self.assertEquals(b.last_revision(), revid1)
254
tree = self.make_branch_and_tree("stacked")
255
tree.branch.set_stacked_on_url(b.user_url)
257
bb = GitBranchBuilder()
258
bb.set_file(u"barbar", "bar\n", False)
259
bb.set_file(u"foo/blie/bla", "bla\n", False)
260
mark2 = bb.commit("Somebody <somebody@someorg.org>", "mymsg2")
261
gitsha2 = bb.finish()[mark2]
262
revid2 = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha2)
264
tree.branch.fetch(Branch.open("d"))
265
tree.branch.repository.check()
266
self.addCleanup(tree.lock_read().unlock)
269
tree.branch.repository.revisions.without_fallbacks().keys())
271
set([revid1, revid2]),
272
set(tree.branch.repository.all_revision_ids()))
274
def test_non_ascii_characters(self):
275
self.make_git_repo("d")
277
bb = GitBranchBuilder()
278
bb.set_file(u"foőbar", "foo\nbar\n", False)
279
mark = bb.commit("Somebody <somebody@someorg.org>", "mymsg")
280
gitsha = bb.finish()[mark]
282
oldrepo = self.open_git_repo("d")
283
newrepo = self.clone_git_repo("d", "f")
284
revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)
285
tree = newrepo.revision_tree(revid)
286
self.assertTrue(tree.has_filename(u"foőbar"))
288
def test_tagged_tree(self):
289
r = self.make_git_repo("d")
291
bb = GitBranchBuilder()
292
bb.set_file("foobar", "fooll\nbar\n", False)
293
mark = bb.commit("Somebody <somebody@someorg.org>", "nextmsg")
298
tag.tag_time = int(time.time())
300
tag.tagger = "Somebody <somebody@example.com>"
301
tag.message = "Created tag pointed at tree"
302
tag.object = (Tree, r[gitsha].tree)
303
r.object_store.add_object(tag)
304
r["refs/tags/sometag"] = tag
306
oldrepo = self.open_git_repo("d")
307
revid = oldrepo.get_mapping().revision_id_foreign_to_bzr(gitsha)
308
newrepo = self.clone_git_repo("d", "f")
309
self.assertEquals(set([revid]), set(newrepo.all_revision_ids()))
312
class LocalRepositoryFetchTests(RepositoryFetchTests, TestCaseWithTransport):
314
def open_git_repo(self, path):
315
return Repository.open(path)
318
class DummyStoreUpdater(object):
320
def add_object(self, obj, ie, path):
327
class ImportObjects(TestCaseWithTransport):
330
super(ImportObjects, self).setUp()
331
self._mapping = BzrGitMappingv1()
332
factory = knit.make_file_factory(True, versionedfile.PrefixMapper())
333
self._texts = factory(self.get_transport('texts'))
335
def test_import_blob_simple(self):
336
blob = Blob.from_string("bar")
337
base_inv = Inventory()
338
objs = { "blobname": blob}
339
ret = import_git_blob(self._texts, self._mapping, "bla", "bla",
341
base_inv, None, "somerevid", [], objs.__getitem__,
342
(None, DEFAULT_FILE_MODE), DummyStoreUpdater(),
343
self._mapping.generate_file_id)
344
self.assertEquals(set([('git:bla', 'somerevid')]), self._texts.keys())
345
self.assertEquals(self._texts.get_record_stream([('git:bla', 'somerevid')],
346
"unordered", True).next().get_bytes_as("fulltext"), "bar")
347
self.assertEquals(1, len(ret))
348
self.assertEquals(None, ret[0][0])
349
self.assertEquals("bla", ret[0][1])
351
self.assertEquals(False, ie.executable)
352
self.assertEquals("file", ie.kind)
353
self.assertEquals("somerevid", ie.revision)
354
self.assertEquals(osutils.sha_strings(["bar"]), ie.text_sha1)
356
def test_import_tree_empty_root(self):
357
base_inv = Inventory(root_id=None)
359
ret, child_modes = import_git_tree(self._texts, self._mapping, "", "",
360
(None, tree.id), base_inv,
361
None, "somerevid", [], {tree.id: tree}.__getitem__,
362
(None, stat.S_IFDIR), DummyStoreUpdater(),
363
self._mapping.generate_file_id)
364
self.assertEquals(child_modes, {})
365
self.assertEquals(set([("TREE_ROOT", 'somerevid')]), self._texts.keys())
366
self.assertEquals(1, len(ret))
367
self.assertEquals(None, ret[0][0])
368
self.assertEquals("", ret[0][1])
370
self.assertEquals(False, ie.executable)
371
self.assertEquals("directory", ie.kind)
372
self.assertEquals({}, ie.children)
373
self.assertEquals("somerevid", ie.revision)
374
self.assertEquals(None, ie.text_sha1)
376
def test_import_tree_empty(self):
377
base_inv = Inventory()
379
ret, child_modes = import_git_tree(self._texts, self._mapping, "bla", "bla",
380
(None, tree.id), base_inv, None, "somerevid", [],
381
{ tree.id: tree }.__getitem__,
382
(None, stat.S_IFDIR), DummyStoreUpdater(),
383
self._mapping.generate_file_id)
384
self.assertEquals(child_modes, {})
385
self.assertEquals(set([("git:bla", 'somerevid')]), self._texts.keys())
386
self.assertEquals(1, len(ret))
387
self.assertEquals(None, ret[0][0])
388
self.assertEquals("bla", ret[0][1])
390
self.assertEquals("directory", ie.kind)
391
self.assertEquals(False, ie.executable)
392
self.assertEquals({}, ie.children)
393
self.assertEquals("somerevid", ie.revision)
394
self.assertEquals(None, ie.text_sha1)
396
def test_import_tree_with_file(self):
397
base_inv = Inventory()
398
blob = Blob.from_string("bar1")
400
tree.add("foo", stat.S_IFREG | 0644, blob.id)
401
objects = { blob.id: blob, tree.id: tree }
402
ret, child_modes = import_git_tree(self._texts, self._mapping, "bla", "bla",
403
(None, tree.id), base_inv, None, "somerevid", [],
404
objects.__getitem__, (None, stat.S_IFDIR), DummyStoreUpdater(),
405
self._mapping.generate_file_id)
406
self.assertEquals(child_modes, {})
407
self.assertEquals(2, len(ret))
408
self.assertEquals(None, ret[0][0])
409
self.assertEquals("bla", ret[0][1])
410
self.assertEquals(None, ret[1][0])
411
self.assertEquals("bla/foo", ret[1][1])
413
self.assertEquals("directory", ie.kind)
415
self.assertEquals("file", ie.kind)
416
self.assertEquals("git:bla/foo", ie.file_id)
417
self.assertEquals("somerevid", ie.revision)
418
self.assertEquals(osutils.sha_strings(["bar1"]), ie.text_sha1)
419
self.assertEquals(False, ie.executable)
421
def test_import_tree_with_unusual_mode_file(self):
422
base_inv = Inventory()
423
blob = Blob.from_string("bar1")
425
tree.add("foo", stat.S_IFREG | 0664, blob.id)
426
objects = { blob.id: blob, tree.id: tree }
427
ret, child_modes = import_git_tree(self._texts, self._mapping,
428
"bla", "bla", (None, tree.id), base_inv, None, "somerevid", [],
429
objects.__getitem__, (None, stat.S_IFDIR), DummyStoreUpdater(),
430
self._mapping.generate_file_id)
431
self.assertEquals(child_modes, { "bla/foo": stat.S_IFREG | 0664 })
433
def test_import_tree_with_file_exe(self):
434
base_inv = Inventory(root_id=None)
435
blob = Blob.from_string("bar")
437
tree.add("foo", 0100755, blob.id)
438
objects = { blob.id: blob, tree.id: tree }
439
ret, child_modes = import_git_tree(self._texts, self._mapping, "", "",
440
(None, tree.id), base_inv, None, "somerevid", [],
441
objects.__getitem__, (None, stat.S_IFDIR), DummyStoreUpdater(),
442
self._mapping.generate_file_id)
443
self.assertEquals(child_modes, {})
444
self.assertEquals(2, len(ret))
445
self.assertEquals(None, ret[0][0])
446
self.assertEquals("", ret[0][1])
447
self.assertEquals(None, ret[1][0])
448
self.assertEquals("foo", ret[1][1])
450
self.assertEquals("directory", ie.kind)
452
self.assertEquals("file", ie.kind)
453
self.assertEquals(True, ie.executable)
455
def test_directory_converted_to_submodule(self):
456
base_inv = Inventory()
457
base_inv.add_path("foo", "directory")
458
base_inv.add_path("foo/bar", "file")
459
othertree = Blob.from_string("someotherthing")
460
blob = Blob.from_string("bar")
462
tree.add("bar", 0160000, blob.id)
463
objects = { tree.id: tree }
464
ret, child_modes = import_git_submodule(self._texts, self._mapping, "foo", "foo",
465
(tree.id, othertree.id), base_inv, base_inv.root.file_id, "somerevid", [],
466
objects.__getitem__, (stat.S_IFDIR | 0755, S_IFGITLINK), DummyStoreUpdater(),
467
self._mapping.generate_file_id)
468
self.assertEquals(child_modes, {})
469
self.assertEquals(2, len(ret))
470
self.assertEquals(ret[0], ("foo/bar", None, base_inv.path2id("foo/bar"), None))
471
self.assertEquals(ret[1][:3], ("foo", "foo", self._mapping.generate_file_id("foo")))
473
self.assertEquals(ie.kind, "tree-reference")