Browse Source

Fixed #14 by tolerating dangling headers and short patch < 4 lines

Matthew Wang 11 years ago
parent
commit
e191e54ea6

+ 19
- 15
cdiff.py View File

472
         """
472
         """
473
         self._stream = stream
473
         self._stream = stream
474
 
474
 
475
-        flag = 0
476
-        for line in self._stream.read_stream_header(100):
477
-            line = decode(line)
478
-            if line.startswith('--- '):
479
-                flag |= 1
480
-            elif line.startswith('+++ '):
481
-                flag |= 2
482
-            elif line.startswith('@@ ') or line.startswith('## '):
483
-                flag |= 4
484
-            if (flag & 7) == 7:
475
+        header = self._stream.read_stream_header(100)
476
+        size = len(header)
477
+        for n in range(size):
478
+            if decode(header[n]).startswith('--- ') and (n < size - 1) and \
479
+                    decode(header[n+1]).startswith('+++ '):
485
                 self._type = 'udiff'
480
                 self._type = 'udiff'
486
                 break
481
                 break
487
         else:
482
         else:
488
-            raise RuntimeError('unknown diff type')
483
+            if size < 4:
484
+                # It's safe to consider as udiff if patch stream contains no
485
+                # more than 3 lines, happens with `git diff` on a file that
486
+                # only has perm bits changes
487
+                #
488
+                self._type = 'udiff'
489
+            else:
490
+                raise RuntimeError('unknown diff type')
489
 
491
 
490
     def get_diff_generator(self):
492
     def get_diff_generator(self):
491
         """parse all diff lines, construct a list of Diff objects"""
493
         """parse all diff lines, construct a list of Diff objects"""
552
                 #
554
                 #
553
                 headers.append(line)
555
                 headers.append(line)
554
 
556
 
555
-        if headers:
556
-            raise RuntimeError('dangling header(s):\n%s' % ''.join(headers))
557
-
558
         # Validate and yield the last patch set if it is not yielded yet
557
         # Validate and yield the last patch set if it is not yielded yet
559
         if diff._old_path:
558
         if diff._old_path:
560
             assert diff._new_path is not None
559
             assert diff._new_path is not None
561
-            assert len(diff._hunks) > 0
562
             if diff._hunks:
560
             if diff._hunks:
563
                 assert len(diff._hunks[-1]._hunk_meta) > 0
561
                 assert len(diff._hunks[-1]._hunk_meta) > 0
564
                 assert len(diff._hunks[-1]._hunk_list) > 0
562
                 assert len(diff._hunks[-1]._hunk_list) > 0
565
             yield diff
563
             yield diff
566
 
564
 
565
+        if headers:
566
+            # Tolerate dangling headers, just yield a Diff object with only
567
+            # header lines
568
+            #
569
+            yield Diff(headers, '', '', [])
570
+
567
 
571
 
568
 class DiffMarkup(object):
572
 class DiffMarkup(object):
569
 
573
 

+ 3
- 0
tests/git-perm/in.diff View File

1
+diff --git a/CHANGES b/CHANGES
2
+old mode 100644
3
+new mode 100755

+ 4
- 0
tests/git-perm/out.normal View File

1
+diff --git a/CHANGES b/CHANGES
2
+old mode 100644
3
+new mode 100755
4
+

+ 4
- 0
tests/git-perm/out.side-by-side View File

1
+diff --git a/CHANGES b/CHANGES
2
+old mode 100644
3
+new mode 100755
4
+

+ 4
- 0
tests/git-perm/out.w70 View File

1
+diff --git a/CHANGES b/CHANGES
2
+old mode 100644
3
+new mode 100755
4
+

+ 10
- 0
tests/svn-merge/in.diff View File

1
+Index: .
2
+==================================================================
3
+--- .   (revision 10)
4
++++ .   (working copy)
5
+
6
+Property changes on: .
7
+___________________________________________________________________
8
+Modified: svn:mergeinfo
9
+   Merged /repository/foo/branches/foo-bar:r4-9
10
+   Merged /repository/foo/trunk/foo:r2-3

+ 11
- 0
tests/svn-merge/out.normal View File

1
+Index: .
2
+==================================================================
3
+--- .   (revision 10)
4
++++ .   (working copy)
5
+
6
+Property changes on: .
7
+___________________________________________________________________
8
+Modified: svn:mergeinfo
9
+   Merged /repository/foo/branches/foo-bar:r4-9
10
+   Merged /repository/foo/trunk/foo:r2-3
11
+

+ 11
- 0
tests/svn-merge/out.side-by-side View File

1
+Index: .
2
+==================================================================
3
+--- .   (revision 10)
4
++++ .   (working copy)
5
+
6
+Property changes on: .
7
+___________________________________________________________________
8
+Modified: svn:mergeinfo
9
+   Merged /repository/foo/branches/foo-bar:r4-9
10
+   Merged /repository/foo/trunk/foo:r2-3
11
+

+ 11
- 0
tests/svn-merge/out.w70 View File

1
+Index: .
2
+==================================================================
3
+--- .   (revision 10)
4
++++ .   (working copy)
5
+
6
+Property changes on: .
7
+___________________________________________________________________
8
+Modified: svn:mergeinfo
9
+   Merged /repository/foo/branches/foo-bar:r4-9
10
+   Merged /repository/foo/trunk/foo:r2-3
11
+

+ 16
- 3
tests/test_cdiff.py View File

439
         patch = r"""\
439
         patch = r"""\
440
 spam
440
 spam
441
 --- a
441
 --- a
442
-+++ b
443
 spam
442
 spam
443
++++ b
444
 """
444
 """
445
         items = patch.splitlines(True)
445
         items = patch.splitlines(True)
446
         stream = cdiff.PatchStream(Sequential(items))
446
         stream = cdiff.PatchStream(Sequential(items))
472
         items = patch.splitlines(True)
472
         items = patch.splitlines(True)
473
         stream = cdiff.PatchStream(Sequential(items))
473
         stream = cdiff.PatchStream(Sequential(items))
474
         parser = cdiff.DiffParser(stream)
474
         parser = cdiff.DiffParser(stream)
475
-        self.assertRaises(RuntimeError, list, parser.get_diff_generator())
475
+
476
+        out = list(parser.get_diff_generator())
477
+        self.assertEqual(len(out), 2)
478
+        self.assertEqual(len(out[1]._headers), 1)
479
+        self.assertEqual(out[1]._headers[0], 'spam\n')
480
+        self.assertEqual(out[1]._old_path, '')
481
+        self.assertEqual(out[1]._new_path, '')
482
+        self.assertEqual(len(out[1]._hunks), 0)
476
 
483
 
477
     def test_parse_missing_new_path(self):
484
     def test_parse_missing_new_path(self):
478
         patch = r"""\
485
         patch = r"""\
503
         items = patch.splitlines(True)
510
         items = patch.splitlines(True)
504
         stream = cdiff.PatchStream(Sequential(items))
511
         stream = cdiff.PatchStream(Sequential(items))
505
         parser = cdiff.DiffParser(stream)
512
         parser = cdiff.DiffParser(stream)
506
-        self.assertRaises(AssertionError, list, parser.get_diff_generator())
513
+
514
+        out = list(parser.get_diff_generator())
515
+        self.assertEqual(len(out), 2)
516
+        self.assertEqual(len(out[1]._headers), 0)
517
+        self.assertEqual(out[1]._old_path, '--- c\n')
518
+        self.assertEqual(out[1]._new_path, '+++ d\n')
519
+        self.assertEqual(len(out[1]._hunks), 0)
507
 
520
 
508
     def test_parse_missing_hunk_list(self):
521
     def test_parse_missing_hunk_list(self):
509
         patch = r"""\
522
         patch = r"""\