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

Merge support for empty messages in git commits and tags by Nicolas Dandrimont.

Jelmer Vernooij 9 éve
szülő
commit
cf6b56cdde
3 módosított fájl, 55 hozzáadás és 4 törlés
  1. 3 0
      NEWS
  2. 26 3
      dulwich/objects.py
  3. 26 1
      dulwich/tests/test_objects.py

+ 3 - 0
NEWS

@@ -5,6 +5,9 @@
   * Support `ssh://` URLs in get_transport_and_path_from_url().
     (Jelmer Vernooij, #402)
 
+  * Support missing empty line after headers in Git commits and tags.
+    (Nicolas Dandrimont, #413)
+
 0.12.0	2015-12-13
 
  IMPROVEMENTS

+ 26 - 3
dulwich/objects.py

@@ -602,17 +602,39 @@ def _parse_message(chunks):
     f = BytesIO(b''.join(chunks))
     k = None
     v = ""
+    eof = False
+
+    # Parse the headers
+    #
+    # Headers can contain newlines. The next line is indented with a space.
+    # We store the latest key as 'k', and the accumulated value as 'v'.
     for l in f:
         if l.startswith(b' '):
+            # Indented continuation of the previous line
             v += l[1:]
         else:
             if k is not None:
+                # We parsed a new header, return its value
                 yield (k, v.rstrip(b'\n'))
             if l == b'\n':
                 # Empty line indicates end of headers
                 break
             (k, v) = l.split(b' ', 1)
-    yield (None, f.read())
+
+    else:
+        # We reached end of file before the headers ended. We still need to
+        # return the previous header, then we need to return a None field for
+        # the text.
+        eof = True
+        if k is not None:
+            yield (k, v.rstrip(b'\n'))
+        yield (None, None)
+
+    if not eof:
+        # We didn't reach the end of file while parsing headers. We can return
+        # the rest of the file as a message.
+        yield (None, f.read())
+
     f.close()
 
 
@@ -679,8 +701,9 @@ class Tag(ShaFile):
                 chunks.append(git_line(
                     _TAGGER_HEADER, self._tagger, str(self._tag_time).encode('ascii'),
                     format_timezone(self._tag_timezone, self._tag_timezone_neg_utc)))
-        chunks.append(b'\n') # To close headers
-        chunks.append(self._message)
+        if self._message is not None:
+            chunks.append(b'\n') # To close headers
+            chunks.append(self._message)
         return chunks
 
     def _deserialize(self, chunks):

+ 26 - 1
dulwich/tests/test_objects.py

@@ -818,6 +818,20 @@ class TagSerializeTests(TestCase):
                           b'\n'
                           b'Tag 0.1'), x.as_raw_string())
 
+    def test_serialize_none_message(self):
+        x = make_object(Tag,
+                        tagger=b'Jelmer Vernooij <jelmer@samba.org>',
+                        name=b'0.1',
+                        message=None,
+                        object=(Blob, b'd80c186a03f423a81b39df39dc87fd269736ca86'),
+                        tag_time=423423423,
+                        tag_timezone=0)
+        self.assertEqual((b'object d80c186a03f423a81b39df39dc87fd269736ca86\n'
+                          b'type blob\n'
+                          b'tag 0.1\n'
+                          b'tagger Jelmer Vernooij <jelmer@samba.org> '
+                          b'423423423 +0000\n'), x.as_raw_string())
+
 
 default_tagger = (b'Linus Torvalds <torvalds@woody.linux-foundation.org> '
                   b'1183319674 -0700')
@@ -849,8 +863,8 @@ class TagParseTests(ShaFileCheckTests):
             lines.append(b'tag ' + name)
         if tagger is not None:
             lines.append(b'tagger ' + tagger)
-        lines.append(b'')
         if message is not None:
+            lines.append(b'')
             lines.append(message)
         return lines
 
@@ -877,6 +891,17 @@ class TagParseTests(ShaFileCheckTests):
         self.assertEqual(None, x.tagger)
         self.assertEqual(b'v2.6.22-rc7', x.name)
 
+    def test_parse_no_message(self):
+        x = Tag()
+        x.set_raw_string(self.make_tag_text(message=None))
+        self.assertEqual(None, x.message)
+        self.assertEqual(
+            b'Linus Torvalds <torvalds@woody.linux-foundation.org>', x.tagger)
+        self.assertEqual(datetime.datetime.utcfromtimestamp(x.tag_time),
+                          datetime.datetime(2007, 7, 1, 19, 54, 34))
+        self.assertEqual(-25200, x.tag_timezone)
+        self.assertEqual(b'v2.6.22-rc7', x.name)
+
     def test_check(self):
         self.assertCheckSucceeds(Tag, self.make_tag_text())
         self.assertCheckFails(Tag, self.make_tag_text(object_sha=None))