Forráskód Böngészése

Fix exporting fastimport streams using python-fastimport.

Jelmer Vernooij 14 éve
szülő
commit
95516db0ac
2 módosított fájl, 51 hozzáadás és 39 törlés
  1. 43 29
      dulwich/fastexport.py
  2. 8 10
      dulwich/tests/test_fastexport.py

+ 43 - 29
dulwich/fastexport.py

@@ -27,7 +27,6 @@ from dulwich.objects import (
     Blob,
     Commit,
     Tag,
-    format_timezone,
     parse_timezone,
     )
 from fastimport import (
@@ -39,6 +38,11 @@ from fastimport import (
 import stat
 
 
+def split_email(text):
+    (name, email) = text.rsplit(" <", 1)
+    return (name, email.rstrip(">"))
+
+
 class GitFastExporter(object):
     """Generate a fast-export output stream for Git objects."""
 
@@ -48,48 +52,58 @@ class GitFastExporter(object):
         self.markers = {}
         self._marker_idx = 0
 
+    def print_cmd(self, cmd):
+        self.outf.write("%r\n" % cmd)
+
     def _allocate_marker(self):
         self._marker_idx+=1
         return str(self._marker_idx)
 
-    def _dump_blob(self, blob, mark):
-        cmd = commands.BlobCommand(mark, blob.data)
-        self.outf.write(str(cmd)+"\n")
+    def _export_blob(self, blob):
+        marker = self._allocate_marker()
+        self.markers[marker] = blob.id
+        return (commands.BlobCommand(marker, blob.data), marker)
+
+    def emit_blob(self, blob):
+        (cmd, marker) = self._export_blob(blob)
+        self.print_cmd(cmd)
+        return marker
 
-    def export_blob(self, blob):
-        i = self._allocate_marker()
-        self.markers[i] = blob.id
-        self._dump_blob(blob, i)
-        return i
+    def _iter_files(self, base_tree, new_tree):
+        for (old_path, new_path), (old_mode, new_mode), (old_hexsha, new_hexsha) in \
+                self.store.tree_changes(base_tree, new_tree):
+            if new_path is None:
+                yield commands.FileDeleteCommand(old_path)
+                continue
+            if not stat.S_ISDIR(new_mode):
+                blob = self.store[new_hexsha]
+                marker = self.emit_blob(blob)
+            if old_path != new_path and old_path is not None:
+                yield commands.FileRenameCommand(old_path, new_path)
+            if old_mode != new_mode or old_hexsha != new_hexsha:
+                yield commands.FileModifyCommand(new_path, new_mode, marker, None)
 
-    def _dump_commit(self, commit, mark, ref, file_cmds):
+    def _export_commit(self, commit, ref, base_tree=None):
+        file_cmds = list(self._iter_files(base_tree, commit.tree))
+        marker = self._allocate_marker()
         if commit.parents:
             from_ = commit.parents[0]
             merges = commit.parents[1:]
         else:
             from_ = None
             merges = []
-        cmd = commands.CommitCommand(ref, mark,
-            commit.author, commit.committer,
+        author, author_email = split_email(commit.author)
+        committer, committer_email = split_email(commit.committer)
+        cmd = commands.CommitCommand(ref, marker,
+            (author, author_email, commit.author_time, commit.author_timezone),
+            (committer, committer_email, commit.commit_time, commit.commit_timezone),
             commit.message, from_, merges, file_cmds)
-        self.outf.write(str(cmd))
+        return (cmd, marker)
 
-    def export_commit(self, commit, ref, base_tree=None):
-        file_cmds = []
-        for (old_path, new_path), (old_mode, new_mode), (old_hexsha, new_hexsha) in \
-                self.store.tree_changes(base_tree, commit.tree):
-            if new_path is None:
-                file_cmds.append(commands.FileDeleteCommand(old_path))
-                continue
-            if not stat.S_ISDIR(new_mode):
-                marker = self.export_blob(self.store[new_hexsha])
-            if old_path != new_path and old_path is not None:
-                file_cmds.append(commands.FileRenameCommand(old_path, new_path))
-            if old_mode != new_mode or old_hexsha != new_hexsha:
-                file_cmds.append(commands.FileModifyCommand(new_mode, marker, new_path))
-        i = self._allocate_marker()
-        self._dump_commit(commit, i, ref, file_cmds)
-        return i
+    def emit_commit(self, commit, ref, base_tree=None):
+        cmd, marker = self._export_commit(commit, ref, base_tree)
+        self.print_cmd(cmd)
+        return marker
 
 
 class FastImporter(object):

+ 8 - 10
dulwich/tests/test_fastexport.py

@@ -46,37 +46,35 @@ class GitFastExporterTests(TestCase):
             raise TestSkipped("python-fastimport not available")
         self.fastexporter = GitFastExporter(self.stream, self.store)
 
-    def test_export_blob(self):
+    def test_emit_blob(self):
         b = Blob()
         b.data = "fooBAR"
-        self.assertEquals('1', self.fastexporter.export_blob(b))
+        self.fastexporter.emit_blob(b)
         self.assertEquals('blob\nmark :1\ndata 6\nfooBAR\n',
             self.stream.getvalue())
 
-    def test_export_commit(self):
+    def test_emit_commit(self):
         b = Blob()
         b.data = "FOO"
         t = Tree()
         t.add(stat.S_IFREG | 0644, "foo", b.id)
         c = Commit()
         c.committer = c.author = "Jelmer <jelmer@host>"
-        c.author_time = c.commit_time = 1271345553.47
+        c.author_time = c.commit_time = 1271345553
         c.author_timezone = c.commit_timezone = 0
         c.message = "msg"
         c.tree = t.id
         self.store.add_objects([(b, None), (t, None), (c, None)])
-        self.assertEquals(2,
-                self.fastexporter.export_commit(c, "refs/heads/master"))
+        self.fastexporter.emit_commit(c, "refs/heads/master")
         self.assertEquals("""blob
 mark :1
 data 3
 FOO
 commit refs/heads/master
 mark :2
-author Jelmer <jelmer@host> 1271345553.47 +0000
-committer Jelmer <jelmer@host> 1271345553.47 +0000
+author Jelmer <jelmer@host> 1271345553 +0000
+committer Jelmer <jelmer@host> 1271345553 +0000
 data 3
 msg
-M 100644 :1 foo
-
+M 644 1 foo
 """, self.stream.getvalue())