Browse Source

Merge fix for treatment of empty chunks in unified diff writer. Fixes #543

Jelmer Vernooij 7 years ago
parent
commit
51760013dd
6 changed files with 57 additions and 22 deletions
  1. 1 0
      AUTHORS
  2. 2 0
      NEWS
  3. 1 1
      docs/tutorial/object-store.txt
  4. 43 11
      dulwich/patch.py
  5. 8 8
      dulwich/tests/test_patch.py
  6. 2 2
      dulwich/tests/test_porcelain.py

+ 1 - 0
AUTHORS

@@ -128,5 +128,6 @@ Segev Finer <segev208@gmail.com>
 fviolette <fviolette@talend.com>
 dzhuang <dzhuang.scut@gmail.com>
 Antoine Pietri <antoine.pietri1@gmail.com>
+Taras Postument <trane9991@gmail.com>
 
 If you contributed but are missing from this list, please send me an e-mail.

+ 2 - 0
NEWS

@@ -5,6 +5,8 @@
   * Read config during porcelain operations that involve remotes.
     (Jelmer Vernooij, #545)
 
+  * Fix headers of empty chunks in unified diffs. (Taras Postument, #543)
+
 0.18.2	2017-08-01
 
  TEST FIXES

+ 1 - 1
docs/tutorial/object-store.txt

@@ -175,7 +175,7 @@ write_tree_diff::
   index c55063a..16ee268 100644
   --- a/spam
   +++ b/spam
-  @@ -1,1 +1,1 @@
+  @@ -1 +1 @@
   -My file content
   +My new file content
 

+ 43 - 11
dulwich/patch.py

@@ -86,31 +86,63 @@ def get_summary(commit):
     return commit.message.splitlines()[0].replace(" ", "-")
 
 
-def unified_diff(a, b, fromfile, tofile, n=3):
-    """difflib.unified_diff that doesn't write any dates or trailing spaces.
-
-    Based on the same function in Python2.6.5-rc2's difflib.py
+#  Unified Diff
+def _format_range_unified(start, stop):
+    'Convert range to the "ed" format'
+    # Per the diff spec at http://www.unix.org/single_unix_specification/
+    beginning = start + 1  # lines start numbering with one
+    length = stop - start
+    if length == 1:
+        return '{}'.format(beginning)
+    if not length:
+        beginning -= 1  # empty ranges begin at line just before the range
+    return '{},{}'.format(beginning, length)
+
+
+def unified_diff(a, b, fromfile='', tofile='', fromfiledate='',
+                 tofiledate='', n=3, lineterm='\n'):
+    """difflib.unified_diff that can detect "No newline at end of file" as
+    original "git diff" does.
+
+    Based on the same function in Python2.7 difflib.py
     """
     started = False
     for group in SequenceMatcher(None, a, b).get_grouped_opcodes(n):
         if not started:
-            yield b'--- ' + fromfile + b'\n'
-            yield b'+++ ' + tofile + b'\n'
             started = True
-        i1, i2, j1, j2 = group[0][1], group[-1][2], group[0][3], group[-1][4]
-        sizes = "@@ -%d,%d +%d,%d @@\n" % (i1+1, i2-i1, j1+1, j2-j1)
-        yield sizes.encode('ascii')
+            fromdate = '\t{}'.format(fromfiledate) if fromfiledate else ''
+            todate = '\t{}'.format(tofiledate) if tofiledate else ''
+            yield '--- {}{}{}'.format(
+                fromfile.decode("ascii"),
+                fromdate,
+                lineterm
+                ).encode('ascii')
+            yield '+++ {}{}{}'.format(
+                tofile.decode("ascii"),
+                todate,
+                lineterm
+                ).encode('ascii')
+
+        first, last = group[0], group[-1]
+        file1_range = _format_range_unified(first[1], last[2])
+        file2_range = _format_range_unified(first[3], last[4])
+        yield '@@ -{} +{} @@{}'.format(
+            file1_range,
+            file2_range,
+            lineterm
+             ).encode('ascii')
+
         for tag, i1, i2, j1, j2 in group:
             if tag == 'equal':
                 for line in a[i1:i2]:
                     yield b' ' + line
                 continue
-            if tag == 'replace' or tag == 'delete':
+            if tag in ('replace', 'delete'):
                 for line in a[i1:i2]:
                     if not line[-1:] == b'\n':
                         line += b'\n\\ No newline at end of file\n'
                     yield b'-' + line
-            if tag == 'replace' or tag == 'insert':
+            if tag in ('replace', 'insert'):
                 for line in b[j1:j2]:
                     if not line[-1:] == b'\n':
                         line += b'\n\\ No newline at end of file\n'

+ 8 - 8
dulwich/tests/test_patch.py

@@ -281,7 +281,7 @@ class DiffTests(TestCase):
              b'index 0000000..a116b51 644',
              b'--- /dev/null',
              b'+++ b/bar.txt',
-             b'@@ -1,0 +1,2 @@',
+             b'@@ -0,0 +1,2 @@',
              b'+new',
              b'+same'
             ], f.getvalue().splitlines())
@@ -297,7 +297,7 @@ class DiffTests(TestCase):
             b'index a116b51..0000000',
             b'--- a/bar.txt',
             b'+++ /dev/null',
-            b'@@ -1,2 +1,0 @@',
+            b'@@ -1,2 +0,0 @@',
             b'-new',
             b'-same'
             ], f.getvalue().splitlines())
@@ -327,7 +327,7 @@ class DiffTests(TestCase):
             b'index 0000000..76d4bb8 644',
             b'--- /dev/null',
             b'+++ b/added.txt',
-            b'@@ -1,0 +1,1 @@',
+            b'@@ -0,0 +1 @@',
             b'+add',
             b'diff --git a/changed.txt b/changed.txt',
             b'index bf84e48..1be2436 644',
@@ -342,7 +342,7 @@ class DiffTests(TestCase):
             b'index 2c3f0b3..0000000',
             b'--- a/removed.txt',
             b'+++ /dev/null',
-            b'@@ -1,1 +1,0 @@',
+            b'@@ -1 +0,0 @@',
             b'-removed',
             ], f.getvalue().splitlines())
 
@@ -362,7 +362,7 @@ class DiffTests(TestCase):
             b'index 06d0bdd..cc97564 160000',
             b'--- a/asubmodule',
             b'+++ b/asubmodule',
-            b'@@ -1,1 +1,1 @@',
+            b'@@ -1 +1 @@',
             b'-Submodule commit 06d0bdd9e2e20377b3180e4986b14c8549b393e4',
             b'+Submodule commit cc975646af69f279396d4d5e1379ac6af80ee637',
             ], f.getvalue().splitlines())
@@ -399,7 +399,7 @@ class DiffTests(TestCase):
              b'index 0000000..a116b51 644',
              b'--- /dev/null',
              b'+++ b/bar.txt',
-             b'@@ -1,0 +1,2 @@',
+             b'@@ -0,0 +1,2 @@',
              b'+new',
              b'+same'
             ], f.getvalue().splitlines())
@@ -417,7 +417,7 @@ class DiffTests(TestCase):
             b'index a116b51..0000000',
             b'--- a/bar.txt',
             b'+++ /dev/null',
-            b'@@ -1,2 +1,0 @@',
+            b'@@ -1,2 +0,0 @@',
             b'-new',
             b'-same'
             ], f.getvalue().splitlines())
@@ -532,7 +532,7 @@ class DiffTests(TestCase):
             b'index a116b51..06d0bdd 160000',
             b'--- a/bar.txt',
             b'+++ b/bar.txt',
-            b'@@ -1,2 +1,1 @@',
+            b'@@ -1,2 +1 @@',
             b'-new',
             b'-same',
             b'+Submodule commit 06d0bdd9e2e20377b3180e4986b14c8549b393e4',

+ 2 - 2
dulwich/tests/test_porcelain.py

@@ -399,7 +399,7 @@ new mode 100644
 index 0000000..ea5c7bf 100644
 --- /dev/null
 +++ b/somename
-@@ -1,0 +1,1 @@
+@@ -0,0 +1 @@
 +The Foo
 """)
 
@@ -430,7 +430,7 @@ diff --git a/somename b/somename
 index ea5c7bf..fd38bcb 100644
 --- a/somename
 +++ b/somename
-@@ -1,1 +1,1 @@
+@@ -1 +1 @@
 -The Foo
 +The Bar
 """)