Support 'gpgsig' property in Commit objects.
authorJelmer Vernooij <jelmer@samba.org>
Wed, 1 Oct 2014 16:47:21 +0000 (18:47 +0200)
committerJelmer Vernooij <jelmer@samba.org>
Wed, 1 Oct 2014 16:47:21 +0000 (18:47 +0200)
NEWS
dulwich/objects.py
dulwich/tests/test_objects.py

diff --git a/NEWS b/NEWS
index 4b6fec2d4193275f6b45388efc0e069258adf4f3..759689cc334d8f83c11ada4a5abfa29d7430e5af 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -25,6 +25,9 @@
 
   * Add 'tag_delete' porcelain. (Jelmer Vernooij)
 
+  * Add support for serializing/deserializing 'gpgsig' attributes in Commit.
+    (Jelmer Vernooij)
+
  CHANGES
 
   * dul-web is now available as 'dulwich web-daemon'.
index 69224159f9ae166989cb7456eab87b9aaba541ce..cdac95ed1896b3acb078954bf4667c90198d8f92 100644 (file)
@@ -48,6 +48,7 @@ _AUTHOR_HEADER = "author"
 _COMMITTER_HEADER = "committer"
 _ENCODING_HEADER = "encoding"
 _MERGETAG_HEADER = "mergetag"
+_GPGSIG_HEADER = "gpgsig"
 
 # Header fields for objects
 _OBJECT_HEADER = "object"
@@ -1029,7 +1030,7 @@ def parse_commit(chunks):
 
     :param chunks: Chunks to parse
     :return: Tuple of (tree, parents, author_info, commit_info,
-        encoding, mergetag, message, extra)
+        encoding, mergetag, gpgsig, message, extra)
     """
     parents = []
     extra = []
@@ -1039,6 +1040,7 @@ def parse_commit(chunks):
     encoding = None
     mergetag = []
     message = None
+    gpgsig = None
 
     for field, value in _parse_message(chunks):
         # TODO(jelmer): Enforce ordering
@@ -1058,12 +1060,14 @@ def parse_commit(chunks):
             encoding = value
         elif field == _MERGETAG_HEADER:
             mergetag.append(Tag.from_string(value + "\n"))
+        elif field == _GPGSIG_HEADER:
+            gpgsig = value
         elif field is None:
             message = value
         else:
             extra.append((field, value))
     return (tree, parents, author_info, commit_info, encoding, mergetag,
-            message, extra)
+            gpgsig, message, extra)
 
 
 class Commit(ShaFile):
@@ -1076,13 +1080,14 @@ class Commit(ShaFile):
                  '_commit_timezone_neg_utc', '_commit_time',
                  '_author_time', '_author_timezone', '_commit_timezone',
                  '_author', '_committer', '_parents', '_extra',
-                 '_encoding', '_tree', '_message', '_mergetag')
+                 '_encoding', '_tree', '_message', '_mergetag', '_gpgsig')
 
     def __init__(self):
         super(Commit, self).__init__()
         self._parents = []
         self._encoding = None
         self._mergetag = []
+        self._gpgsig = None
         self._extra = []
         self._author_timezone_neg_utc = False
         self._commit_timezone_neg_utc = False
@@ -1096,7 +1101,7 @@ class Commit(ShaFile):
 
     def _deserialize(self, chunks):
         (self._tree, self._parents, author_info, commit_info, self._encoding,
-                self._mergetag, self._message, self._extra) = (
+                self._mergetag, self._gpgsig, self._message, self._extra) = (
                         parse_commit(chunks))
         (self._author, self._author_time, (self._author_timezone,
              self._author_timezone_neg_utc)) = author_info
@@ -1169,6 +1174,11 @@ class Commit(ShaFile):
                 raise AssertionError(
                     "newline in extra data: %r -> %r" % (k, v))
             chunks.append("%s %s\n" % (k, v))
+        if self.gpgsig:
+            sig_chunks = self.gpgsig.split("\n")
+            chunks.append("%s %s\n" % (_GPGSIG_HEADER, sig_chunks[0]))
+            for chunk in sig_chunks[1:]:
+                chunks.append(" %s\n" % chunk)
         chunks.append("\n")  # There must be a new line after the headers
         chunks.append(self._message)
         return chunks
@@ -1229,6 +1239,9 @@ class Commit(ShaFile):
     mergetag = serializable_property(
         "mergetag", "Associated signed tag.")
 
+    gpgsig = serializable_property(
+        "gpgsig", "GPG Signature.")
+
 
 OBJECT_CLASSES = (
     Commit,
index 30172f7c98a115df19ba6a437c296769baf3246a..8cb7b73c3bf834f3270a42c482ee7b7ab55c640a 100644 (file)
@@ -315,6 +315,52 @@ class CommitSerializationTests(TestCase):
         d._deserialize(c.as_raw_chunks())
         self.assertEqual(c, d)
 
+    def test_serialize_gpgsig(self):
+        commit = self.make_commit(gpgsig="""-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1
+
+iQIcBAABCgAGBQJULCdfAAoJEACAbyvXKaRXuKwP/RyP9PA49uAvu8tQVCC/uBa8
+vi975+xvO14R8Pp8k2nps7lSxCdtCd+xVT1VRHs0wNhOZo2YCVoU1HATkPejqSeV
+NScTHcxnk4/+bxyfk14xvJkNp7FlQ3npmBkA+lbV0Ubr33rvtIE5jiJPyz+SgWAg
+xdBG2TojV0squj00GoH/euK6aX7GgZtwdtpTv44haCQdSuPGDcI4TORqR6YSqvy3
+GPE+3ZqXPFFb+KILtimkxitdwB7CpwmNse2vE3rONSwTvi8nq3ZoQYNY73CQGkUy
+qoFU0pDtw87U3niFin1ZccDgH0bB6624sLViqrjcbYJeg815Htsu4rmzVaZADEVC
+XhIO4MThebusdk0AcNGjgpf3HRHk0DPMDDlIjm+Oao0cqovvF6VyYmcb0C+RmhJj
+dodLXMNmbqErwTk3zEkW0yZvNIYXH7m9SokPCZa4eeIM7be62X6h1mbt0/IU6Th+
+v18fS0iTMP/Viug5und+05C/v04kgDo0CPphAbXwWMnkE4B6Tl9sdyUYXtvQsL7x
+0+WP1gL27ANqNZiI07Kz/BhbBAQI/+2TFT7oGr0AnFPQ5jHp+3GpUf6OKuT1wT3H
+ND189UFuRuubxb42vZhpcXRbqJVWnbECTKVUPsGZqat3enQUB63uM4i6/RdONDZA
+fDeF1m4qYs+cUXKNUZ03
+=X6RT
+-----END PGP SIGNATURE-----""")
+        self.maxDiff = None
+        self.assertMultiLineEqual("""\
+tree d80c186a03f423a81b39df39dc87fd269736ca86
+parent ab64bbdcc51b170d21588e5c5d391ee5c0c96dfd
+parent 4cffe90e0a41ad3f5190079d7c8f036bde29cbe6
+author James Westby <jw+debian@jameswestby.net> 1174773719 +0000
+committer James Westby <jw+debian@jameswestby.net> 1174773719 +0000
+gpgsig -----BEGIN PGP SIGNATURE-----
+ Version: GnuPG v1
+ iQIcBAABCgAGBQJULCdfAAoJEACAbyvXKaRXuKwP/RyP9PA49uAvu8tQVCC/uBa8
+ vi975+xvO14R8Pp8k2nps7lSxCdtCd+xVT1VRHs0wNhOZo2YCVoU1HATkPejqSeV
+ NScTHcxnk4/+bxyfk14xvJkNp7FlQ3npmBkA+lbV0Ubr33rvtIE5jiJPyz+SgWAg
+ xdBG2TojV0squj00GoH/euK6aX7GgZtwdtpTv44haCQdSuPGDcI4TORqR6YSqvy3
+ GPE+3ZqXPFFb+KILtimkxitdwB7CpwmNse2vE3rONSwTvi8nq3ZoQYNY73CQGkUy
+ qoFU0pDtw87U3niFin1ZccDgH0bB6624sLViqrjcbYJeg815Htsu4rmzVaZADEVC
+ XhIO4MThebusdk0AcNGjgpf3HRHk0DPMDDlIjm+Oao0cqovvF6VyYmcb0C+RmhJj
+ dodLXMNmbqErwTk3zEkW0yZvNIYXH7m9SokPCZa4eeIM7be62X6h1mbt0/IU6Th+
+ v18fS0iTMP/Viug5und+05C/v04kgDo0CPphAbXwWMnkE4B6Tl9sdyUYXtvQsL7x
+ 0+WP1gL27ANqNZiI07Kz/BhbBAQI/+2TFT7oGr0AnFPQ5jHp+3GpUf6OKuT1wT3H
+ ND189UFuRuubxb42vZhpcXRbqJVWnbECTKVUPsGZqat3enQUB63uM4i6/RdONDZA
+ fDeF1m4qYs+cUXKNUZ03
+ =X6RT
+ -----END PGP SIGNATURE-----
+
+Merge ../b
+""", commit.as_raw_string())
+
     def test_serialize_mergetag(self):
         tag = make_object(
             Tag, object=(Commit, "a38d6181ff27824c79fc7df825164a212eff6a3f"),
@@ -532,6 +578,50 @@ class CommitParseTests(ShaFileCheckTests):
             else:
                 self.assertCheckFails(Commit, text)
 
+    def test_parse_gpgsig(self):
+        c = Commit.from_string("""tree aaff74984cccd156a469afa7d9ab10e4777beb24
+author Jelmer Vernooij <jelmer@samba.org> 1412179807 +0200
+committer Jelmer Vernooij <jelmer@samba.org> 1412179807 +0200
+gpgsig -----BEGIN PGP SIGNATURE-----
+ Version: GnuPG v1
+ iQIcBAABCgAGBQJULCdfAAoJEACAbyvXKaRXuKwP/RyP9PA49uAvu8tQVCC/uBa8
+ vi975+xvO14R8Pp8k2nps7lSxCdtCd+xVT1VRHs0wNhOZo2YCVoU1HATkPejqSeV
+ NScTHcxnk4/+bxyfk14xvJkNp7FlQ3npmBkA+lbV0Ubr33rvtIE5jiJPyz+SgWAg
+ xdBG2TojV0squj00GoH/euK6aX7GgZtwdtpTv44haCQdSuPGDcI4TORqR6YSqvy3
+ GPE+3ZqXPFFb+KILtimkxitdwB7CpwmNse2vE3rONSwTvi8nq3ZoQYNY73CQGkUy
+ qoFU0pDtw87U3niFin1ZccDgH0bB6624sLViqrjcbYJeg815Htsu4rmzVaZADEVC
+ XhIO4MThebusdk0AcNGjgpf3HRHk0DPMDDlIjm+Oao0cqovvF6VyYmcb0C+RmhJj
+ dodLXMNmbqErwTk3zEkW0yZvNIYXH7m9SokPCZa4eeIM7be62X6h1mbt0/IU6Th+
+ v18fS0iTMP/Viug5und+05C/v04kgDo0CPphAbXwWMnkE4B6Tl9sdyUYXtvQsL7x
+ 0+WP1gL27ANqNZiI07Kz/BhbBAQI/+2TFT7oGr0AnFPQ5jHp+3GpUf6OKuT1wT3H
+ ND189UFuRuubxb42vZhpcXRbqJVWnbECTKVUPsGZqat3enQUB63uM4i6/RdONDZA
+ fDeF1m4qYs+cUXKNUZ03
+ =X6RT
+ -----END PGP SIGNATURE-----
+
+foo
+""")
+        self.assertEquals("foo\n", c.message)
+        self.assertEquals([], c.extra)
+        self.assertEquals("""-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1
+
+iQIcBAABCgAGBQJULCdfAAoJEACAbyvXKaRXuKwP/RyP9PA49uAvu8tQVCC/uBa8
+vi975+xvO14R8Pp8k2nps7lSxCdtCd+xVT1VRHs0wNhOZo2YCVoU1HATkPejqSeV
+NScTHcxnk4/+bxyfk14xvJkNp7FlQ3npmBkA+lbV0Ubr33rvtIE5jiJPyz+SgWAg
+xdBG2TojV0squj00GoH/euK6aX7GgZtwdtpTv44haCQdSuPGDcI4TORqR6YSqvy3
+GPE+3ZqXPFFb+KILtimkxitdwB7CpwmNse2vE3rONSwTvi8nq3ZoQYNY73CQGkUy
+qoFU0pDtw87U3niFin1ZccDgH0bB6624sLViqrjcbYJeg815Htsu4rmzVaZADEVC
+XhIO4MThebusdk0AcNGjgpf3HRHk0DPMDDlIjm+Oao0cqovvF6VyYmcb0C+RmhJj
+dodLXMNmbqErwTk3zEkW0yZvNIYXH7m9SokPCZa4eeIM7be62X6h1mbt0/IU6Th+
+v18fS0iTMP/Viug5und+05C/v04kgDo0CPphAbXwWMnkE4B6Tl9sdyUYXtvQsL7x
+0+WP1gL27ANqNZiI07Kz/BhbBAQI/+2TFT7oGr0AnFPQ5jHp+3GpUf6OKuT1wT3H
+ND189UFuRuubxb42vZhpcXRbqJVWnbECTKVUPsGZqat3enQUB63uM4i6/RdONDZA
+fDeF1m4qYs+cUXKNUZ03
+=X6RT
+-----END PGP SIGNATURE-----""", c.gpgsig)
+
 
 _TREE_ITEMS = {
   'a.c': (0o100755, 'd80c186a03f423a81b39df39dc87fd269736ca86'),