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,20 +472,22 @@ class DiffParser(object):
472 472
         """
473 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 480
                 self._type = 'udiff'
486 481
                 break
487 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 492
     def get_diff_generator(self):
491 493
         """parse all diff lines, construct a list of Diff objects"""
@@ -552,18 +554,20 @@ class DiffParser(object):
552 554
                 #
553 555
                 headers.append(line)
554 556
 
555
-        if headers:
556
-            raise RuntimeError('dangling header(s):\n%s' % ''.join(headers))
557
-
558 557
         # Validate and yield the last patch set if it is not yielded yet
559 558
         if diff._old_path:
560 559
             assert diff._new_path is not None
561
-            assert len(diff._hunks) > 0
562 560
             if diff._hunks:
563 561
                 assert len(diff._hunks[-1]._hunk_meta) > 0
564 562
                 assert len(diff._hunks[-1]._hunk_list) > 0
565 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 572
 class DiffMarkup(object):
569 573
 

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

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

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

@@ -0,0 +1,4 @@
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

@@ -0,0 +1,4 @@
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

@@ -0,0 +1,4 @@
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

@@ -0,0 +1,10 @@
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

@@ -0,0 +1,11 @@
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

@@ -0,0 +1,11 @@
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

@@ -0,0 +1,11 @@
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,8 +439,8 @@ spam
439 439
         patch = r"""\
440 440
 spam
441 441
 --- a
442
-+++ b
443 442
 spam
443
++++ b
444 444
 """
445 445
         items = patch.splitlines(True)
446 446
         stream = cdiff.PatchStream(Sequential(items))
@@ -472,7 +472,14 @@ spam
472 472
         items = patch.splitlines(True)
473 473
         stream = cdiff.PatchStream(Sequential(items))
474 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 484
     def test_parse_missing_new_path(self):
478 485
         patch = r"""\
@@ -503,7 +510,13 @@ spam
503 510
         items = patch.splitlines(True)
504 511
         stream = cdiff.PatchStream(Sequential(items))
505 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 521
     def test_parse_missing_hunk_list(self):
509 522
         patch = r"""\