2
0

test_fastexport.py 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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. import stat
  21. from io import BytesIO
  22. from dulwich.object_store import MemoryObjectStore
  23. from dulwich.objects import ZERO_SHA, Blob, Commit, Tree
  24. from dulwich.repo import MemoryRepo
  25. from dulwich.tests.utils import build_commit_graph
  26. from . import SkipTest, TestCase
  27. class GitFastExporterTests(TestCase):
  28. """Tests for the GitFastExporter tests."""
  29. def setUp(self):
  30. super().setUp()
  31. self.store = MemoryObjectStore()
  32. self.stream = BytesIO()
  33. try:
  34. from dulwich.fastexport import GitFastExporter
  35. except ImportError as exc:
  36. raise SkipTest("python-fastimport not available") from exc
  37. self.fastexporter = GitFastExporter(self.stream, self.store)
  38. def test_emit_blob(self):
  39. b = Blob()
  40. b.data = b"fooBAR"
  41. self.fastexporter.emit_blob(b)
  42. self.assertEqual(b"blob\nmark :1\ndata 6\nfooBAR\n", self.stream.getvalue())
  43. def test_emit_commit(self):
  44. b = Blob()
  45. b.data = b"FOO"
  46. t = Tree()
  47. t.add(b"foo", stat.S_IFREG | 0o644, b.id)
  48. c = Commit()
  49. c.committer = c.author = b"Jelmer <jelmer@host>"
  50. c.author_time = c.commit_time = 1271345553
  51. c.author_timezone = c.commit_timezone = 0
  52. c.message = b"msg"
  53. c.tree = t.id
  54. self.store.add_objects([(b, None), (t, None), (c, None)])
  55. self.fastexporter.emit_commit(c, b"refs/heads/master")
  56. self.assertEqual(
  57. b"""blob
  58. mark :1
  59. data 3
  60. FOO
  61. commit refs/heads/master
  62. mark :2
  63. author Jelmer <jelmer@host> 1271345553 +0000
  64. committer Jelmer <jelmer@host> 1271345553 +0000
  65. data 3
  66. msg
  67. M 644 :1 foo
  68. """,
  69. self.stream.getvalue(),
  70. )
  71. class GitImportProcessorTests(TestCase):
  72. """Tests for the GitImportProcessor tests."""
  73. def setUp(self):
  74. super().setUp()
  75. self.repo = MemoryRepo()
  76. try:
  77. from dulwich.fastexport import GitImportProcessor
  78. except ImportError as exc:
  79. raise SkipTest("python-fastimport not available") from exc
  80. self.processor = GitImportProcessor(self.repo)
  81. def test_reset_handler(self):
  82. from fastimport import commands
  83. [c1] = build_commit_graph(self.repo.object_store, [[1]])
  84. cmd = commands.ResetCommand(b"refs/heads/foo", c1.id)
  85. self.processor.reset_handler(cmd)
  86. self.assertEqual(c1.id, self.repo.get_refs()[b"refs/heads/foo"])
  87. self.assertEqual(c1.id, self.processor.last_commit)
  88. def test_reset_handler_marker(self):
  89. from fastimport import commands
  90. [c1, c2] = build_commit_graph(self.repo.object_store, [[1], [2]])
  91. self.processor.markers[b"10"] = c1.id
  92. cmd = commands.ResetCommand(b"refs/heads/foo", b":10")
  93. self.processor.reset_handler(cmd)
  94. self.assertEqual(c1.id, self.repo.get_refs()[b"refs/heads/foo"])
  95. def test_reset_handler_default(self):
  96. from fastimport import commands
  97. [c1, c2] = build_commit_graph(self.repo.object_store, [[1], [2]])
  98. cmd = commands.ResetCommand(b"refs/heads/foo", None)
  99. self.processor.reset_handler(cmd)
  100. self.assertEqual(ZERO_SHA, self.repo.get_refs()[b"refs/heads/foo"])
  101. def test_commit_handler(self):
  102. from fastimport import commands
  103. cmd = commands.CommitCommand(
  104. b"refs/heads/foo",
  105. b"mrkr",
  106. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  107. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  108. b"FOO",
  109. None,
  110. [],
  111. [],
  112. )
  113. self.processor.commit_handler(cmd)
  114. commit = self.repo[self.processor.last_commit]
  115. self.assertEqual(b"Jelmer <jelmer@samba.org>", commit.author)
  116. self.assertEqual(b"Jelmer <jelmer@samba.org>", commit.committer)
  117. self.assertEqual(b"FOO", commit.message)
  118. self.assertEqual([], commit.parents)
  119. self.assertEqual(432432432.0, commit.commit_time)
  120. self.assertEqual(432432432.0, commit.author_time)
  121. self.assertEqual(3600, commit.commit_timezone)
  122. self.assertEqual(3600, commit.author_timezone)
  123. self.assertEqual(commit, self.repo[b"refs/heads/foo"])
  124. def test_commit_handler_markers(self):
  125. from fastimport import commands
  126. [c1, c2, c3] = build_commit_graph(self.repo.object_store, [[1], [2], [3]])
  127. self.processor.markers[b"10"] = c1.id
  128. self.processor.markers[b"42"] = c2.id
  129. self.processor.markers[b"98"] = c3.id
  130. cmd = commands.CommitCommand(
  131. b"refs/heads/foo",
  132. b"mrkr",
  133. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  134. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  135. b"FOO",
  136. b":10",
  137. [b":42", b":98"],
  138. [],
  139. )
  140. self.processor.commit_handler(cmd)
  141. commit = self.repo[self.processor.last_commit]
  142. self.assertEqual(c1.id, commit.parents[0])
  143. self.assertEqual(c2.id, commit.parents[1])
  144. self.assertEqual(c3.id, commit.parents[2])
  145. def test_import_stream(self):
  146. markers = self.processor.import_stream(
  147. BytesIO(
  148. b"""blob
  149. mark :1
  150. data 11
  151. text for a
  152. commit refs/heads/master
  153. mark :2
  154. committer Joe Foo <joe@foo.com> 1288287382 +0000
  155. data 20
  156. <The commit message>
  157. M 100644 :1 a
  158. """
  159. )
  160. )
  161. self.assertEqual(2, len(markers))
  162. self.assertIsInstance(self.repo[markers[b"1"]], Blob)
  163. self.assertIsInstance(self.repo[markers[b"2"]], Commit)
  164. def test_file_add(self):
  165. from fastimport import commands
  166. cmd = commands.BlobCommand(b"23", b"data")
  167. self.processor.blob_handler(cmd)
  168. cmd = commands.CommitCommand(
  169. b"refs/heads/foo",
  170. b"mrkr",
  171. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  172. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  173. b"FOO",
  174. None,
  175. [],
  176. [commands.FileModifyCommand(b"path", 0o100644, b":23", None)],
  177. )
  178. self.processor.commit_handler(cmd)
  179. commit = self.repo[self.processor.last_commit]
  180. self.assertEqual(
  181. [(b"path", 0o100644, b"6320cd248dd8aeaab759d5871f8781b5c0505172")],
  182. self.repo[commit.tree].items(),
  183. )
  184. def simple_commit(self):
  185. from fastimport import commands
  186. cmd = commands.BlobCommand(b"23", b"data")
  187. self.processor.blob_handler(cmd)
  188. cmd = commands.CommitCommand(
  189. b"refs/heads/foo",
  190. b"mrkr",
  191. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  192. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  193. b"FOO",
  194. None,
  195. [],
  196. [commands.FileModifyCommand(b"path", 0o100644, b":23", None)],
  197. )
  198. self.processor.commit_handler(cmd)
  199. commit = self.repo[self.processor.last_commit]
  200. return commit
  201. def make_file_commit(self, file_cmds):
  202. """Create a trivial commit with the specified file commands.
  203. Args:
  204. file_cmds: File commands to run.
  205. Returns: The created commit object
  206. """
  207. from fastimport import commands
  208. cmd = commands.CommitCommand(
  209. b"refs/heads/foo",
  210. b"mrkr",
  211. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  212. (b"Jelmer", b"jelmer@samba.org", 432432432.0, 3600),
  213. b"FOO",
  214. None,
  215. [],
  216. file_cmds,
  217. )
  218. self.processor.commit_handler(cmd)
  219. return self.repo[self.processor.last_commit]
  220. def test_file_copy(self):
  221. from fastimport import commands
  222. self.simple_commit()
  223. commit = self.make_file_commit([commands.FileCopyCommand(b"path", b"new_path")])
  224. self.assertEqual(
  225. [
  226. (
  227. b"new_path",
  228. 0o100644,
  229. b"6320cd248dd8aeaab759d5871f8781b5c0505172",
  230. ),
  231. (
  232. b"path",
  233. 0o100644,
  234. b"6320cd248dd8aeaab759d5871f8781b5c0505172",
  235. ),
  236. ],
  237. self.repo[commit.tree].items(),
  238. )
  239. def test_file_move(self):
  240. from fastimport import commands
  241. self.simple_commit()
  242. commit = self.make_file_commit(
  243. [commands.FileRenameCommand(b"path", b"new_path")]
  244. )
  245. self.assertEqual(
  246. [
  247. (
  248. b"new_path",
  249. 0o100644,
  250. b"6320cd248dd8aeaab759d5871f8781b5c0505172",
  251. ),
  252. ],
  253. self.repo[commit.tree].items(),
  254. )
  255. def test_file_delete(self):
  256. from fastimport import commands
  257. self.simple_commit()
  258. commit = self.make_file_commit([commands.FileDeleteCommand(b"path")])
  259. self.assertEqual([], self.repo[commit.tree].items())
  260. def test_file_deleteall(self):
  261. from fastimport import commands
  262. self.simple_commit()
  263. commit = self.make_file_commit([commands.FileDeleteAllCommand()])
  264. self.assertEqual([], self.repo[commit.tree].items())