test_fastexport.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. # test_fastexport.py -- Fast export/import functionality
  2. # Copyright (C) 2010 Jelmer Vernooij <jelmer@jelmer.uk>
  3. #
  4. # Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
  5. # General Public License as public by the Free Software Foundation; version 2.0
  6. # or (at your option) any later version. You can redistribute it and/or
  7. # modify it under the terms of either of these two licenses.
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. #
  15. # You should have received a copy of the licenses; if not, see
  16. # <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
  17. # and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
  18. # License, Version 2.0.
  19. #
  20. from io import BytesIO
  21. import stat
  22. from dulwich.object_store import (
  23. MemoryObjectStore,
  24. )
  25. from dulwich.objects import (
  26. Blob,
  27. Commit,
  28. Tree,
  29. ZERO_SHA,
  30. )
  31. from dulwich.repo import (
  32. MemoryRepo,
  33. )
  34. from dulwich.tests import (
  35. SkipTest,
  36. TestCase,
  37. )
  38. from dulwich.tests.utils import (
  39. build_commit_graph,
  40. )
  41. class GitFastExporterTests(TestCase):
  42. """Tests for the GitFastExporter tests."""
  43. def setUp(self):
  44. super(GitFastExporterTests, self).setUp()
  45. self.store = MemoryObjectStore()
  46. self.stream = BytesIO()
  47. try:
  48. from dulwich.fastexport import GitFastExporter
  49. except ImportError as exc:
  50. raise SkipTest("python-fastimport not available") from exc
  51. self.fastexporter = GitFastExporter(self.stream, self.store)
  52. def test_emit_blob(self):
  53. b = Blob()
  54. b.data = b"fooBAR"
  55. self.fastexporter.emit_blob(b)
  56. self.assertEqual(b"blob\nmark :1\ndata 6\nfooBAR\n", self.stream.getvalue())
  57. def test_emit_commit(self):
  58. b = Blob()
  59. b.data = b"FOO"
  60. t = Tree()
  61. t.add(b"foo", stat.S_IFREG | 0o644, b.id)
  62. c = Commit()
  63. c.committer = c.author = b"Jelmer <jelmer@host>"
  64. c.author_time = c.commit_time = 1271345553
  65. c.author_timezone = c.commit_timezone = 0
  66. c.message = b"msg"
  67. c.tree = t.id
  68. self.store.add_objects([(b, None), (t, None), (c, None)])
  69. self.fastexporter.emit_commit(c, b"refs/heads/master")
  70. self.assertEqual(
  71. b"""blob
  72. mark :1
  73. data 3
  74. FOO
  75. commit refs/heads/master
  76. mark :2
  77. author Jelmer <jelmer@host> 1271345553 +0000
  78. committer Jelmer <jelmer@host> 1271345553 +0000
  79. data 3
  80. msg
  81. M 644 :1 foo
  82. """,
  83. self.stream.getvalue(),
  84. )
  85. class GitImportProcessorTests(TestCase):
  86. """Tests for the GitImportProcessor tests."""
  87. def setUp(self):
  88. super(GitImportProcessorTests, self).setUp()
  89. self.repo = MemoryRepo()
  90. try:
  91. from dulwich.fastexport import GitImportProcessor
  92. except ImportError as exc:
  93. raise SkipTest("python-fastimport not available") from exc
  94. self.processor = GitImportProcessor(self.repo)
  95. def test_reset_handler(self):
  96. from fastimport import commands
  97. [c1] = build_commit_graph(self.repo.object_store, [[1]])
  98. cmd = commands.ResetCommand(b"refs/heads/foo", c1.id)
  99. self.processor.reset_handler(cmd)
  100. self.assertEqual(c1.id, self.repo.get_refs()[b"refs/heads/foo"])
  101. self.assertEqual(c1.id, self.processor.last_commit)
  102. def test_reset_handler_marker(self):
  103. from fastimport import commands
  104. [c1, c2] = build_commit_graph(self.repo.object_store, [[1], [2]])
  105. self.processor.markers[b"10"] = c1.id
  106. cmd = commands.ResetCommand(b"refs/heads/foo", b":10")
  107. self.processor.reset_handler(cmd)
  108. self.assertEqual(c1.id, self.repo.get_refs()[b"refs/heads/foo"])
  109. def test_reset_handler_default(self):
  110. from fastimport import commands
  111. [c1, c2] = build_commit_graph(self.repo.object_store, [[1], [2]])
  112. cmd = commands.ResetCommand(b"refs/heads/foo", None)
  113. self.processor.reset_handler(cmd)
  114. self.assertEqual(ZERO_SHA, self.repo.get_refs()[b"refs/heads/foo"])
  115. def test_commit_handler(self):
  116. from fastimport import commands
  117. cmd = commands.CommitCommand(
  118. b"refs/heads/foo",
  119. b"mrkr",
  120. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  121. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  122. b"FOO",
  123. None,
  124. [],
  125. [],
  126. )
  127. self.processor.commit_handler(cmd)
  128. commit = self.repo[self.processor.last_commit]
  129. self.assertEqual(b"Jelmer <jelmer@samba.org>", commit.author)
  130. self.assertEqual(b"Jelmer <jelmer@samba.org>", commit.committer)
  131. self.assertEqual(b"FOO", commit.message)
  132. self.assertEqual([], commit.parents)
  133. self.assertEqual(432432432.0, commit.commit_time)
  134. self.assertEqual(432432432.0, commit.author_time)
  135. self.assertEqual(3600, commit.commit_timezone)
  136. self.assertEqual(3600, commit.author_timezone)
  137. self.assertEqual(commit, self.repo[b"refs/heads/foo"])
  138. def test_commit_handler_markers(self):
  139. from fastimport import commands
  140. [c1, c2, c3] = build_commit_graph(self.repo.object_store, [[1], [2], [3]])
  141. self.processor.markers[b"10"] = c1.id
  142. self.processor.markers[b"42"] = c2.id
  143. self.processor.markers[b"98"] = c3.id
  144. cmd = commands.CommitCommand(
  145. b"refs/heads/foo",
  146. b"mrkr",
  147. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  148. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  149. b"FOO",
  150. b":10",
  151. [b":42", b":98"],
  152. [],
  153. )
  154. self.processor.commit_handler(cmd)
  155. commit = self.repo[self.processor.last_commit]
  156. self.assertEqual(c1.id, commit.parents[0])
  157. self.assertEqual(c2.id, commit.parents[1])
  158. self.assertEqual(c3.id, commit.parents[2])
  159. def test_import_stream(self):
  160. markers = self.processor.import_stream(
  161. BytesIO(
  162. b"""blob
  163. mark :1
  164. data 11
  165. text for a
  166. commit refs/heads/master
  167. mark :2
  168. committer Joe Foo <joe@foo.com> 1288287382 +0000
  169. data 20
  170. <The commit message>
  171. M 100644 :1 a
  172. """
  173. )
  174. )
  175. self.assertEqual(2, len(markers))
  176. self.assertIsInstance(self.repo[markers[b"1"]], Blob)
  177. self.assertIsInstance(self.repo[markers[b"2"]], Commit)
  178. def test_file_add(self):
  179. from fastimport import commands
  180. cmd = commands.BlobCommand(b"23", b"data")
  181. self.processor.blob_handler(cmd)
  182. cmd = commands.CommitCommand(
  183. b"refs/heads/foo",
  184. b"mrkr",
  185. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  186. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  187. b"FOO",
  188. None,
  189. [],
  190. [commands.FileModifyCommand(b"path", 0o100644, b":23", None)],
  191. )
  192. self.processor.commit_handler(cmd)
  193. commit = self.repo[self.processor.last_commit]
  194. self.assertEqual(
  195. [(b"path", 0o100644, b"6320cd248dd8aeaab759d5871f8781b5c0505172")],
  196. self.repo[commit.tree].items(),
  197. )
  198. def simple_commit(self):
  199. from fastimport import commands
  200. cmd = commands.BlobCommand(b"23", b"data")
  201. self.processor.blob_handler(cmd)
  202. cmd = commands.CommitCommand(
  203. b"refs/heads/foo",
  204. b"mrkr",
  205. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  206. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  207. b"FOO",
  208. None,
  209. [],
  210. [commands.FileModifyCommand(b"path", 0o100644, b":23", None)],
  211. )
  212. self.processor.commit_handler(cmd)
  213. commit = self.repo[self.processor.last_commit]
  214. return commit
  215. def make_file_commit(self, file_cmds):
  216. """Create a trivial commit with the specified file commands.
  217. Args:
  218. file_cmds: File commands to run.
  219. Returns: The created commit object
  220. """
  221. from fastimport import commands
  222. cmd = commands.CommitCommand(
  223. b"refs/heads/foo",
  224. b"mrkr",
  225. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  226. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  227. b"FOO",
  228. None,
  229. [],
  230. file_cmds,
  231. )
  232. self.processor.commit_handler(cmd)
  233. return self.repo[self.processor.last_commit]
  234. def test_file_copy(self):
  235. from fastimport import commands
  236. self.simple_commit()
  237. commit = self.make_file_commit([commands.FileCopyCommand(b"path", b"new_path")])
  238. self.assertEqual(
  239. [
  240. (
  241. b"new_path",
  242. 0o100644,
  243. b"6320cd248dd8aeaab759d5871f8781b5c0505172",
  244. ),
  245. (
  246. b"path",
  247. 0o100644,
  248. b"6320cd248dd8aeaab759d5871f8781b5c0505172",
  249. ),
  250. ],
  251. self.repo[commit.tree].items(),
  252. )
  253. def test_file_move(self):
  254. from fastimport import commands
  255. self.simple_commit()
  256. commit = self.make_file_commit(
  257. [commands.FileRenameCommand(b"path", b"new_path")]
  258. )
  259. self.assertEqual(
  260. [
  261. (
  262. b"new_path",
  263. 0o100644,
  264. b"6320cd248dd8aeaab759d5871f8781b5c0505172",
  265. ),
  266. ],
  267. self.repo[commit.tree].items(),
  268. )
  269. def test_file_delete(self):
  270. from fastimport import commands
  271. self.simple_commit()
  272. commit = self.make_file_commit([commands.FileDeleteCommand(b"path")])
  273. self.assertEqual([], self.repo[commit.tree].items())
  274. def test_file_deleteall(self):
  275. from fastimport import commands
  276. self.simple_commit()
  277. commit = self.make_file_commit([commands.FileDeleteAllCommand()])
  278. self.assertEqual([], self.repo[commit.tree].items())