Patchwork [4,of,9] mdiff: distinguish diff headers from hunks in unidiff()

login
register
mail settings
Submitter Denis Laxalde
Date March 6, 2017, 9:38 a.m.
Message ID <3fce2b5c21f362f10829.1488793102@sh77.tls.logilab.fr>
Download mbox | patch
Permalink /patch/18927/
State Accepted
Headers show

Comments

Denis Laxalde - March 6, 2017, 9:38 a.m.
# HG changeset patch
# User Denis Laxalde <denis.laxalde@logilab.fr>
# Date 1488545482 -3600
#      Fri Mar 03 13:51:22 2017 +0100
# Node ID 3fce2b5c21f362f1082940786b92ca8794e029ce
# Parent  539c8f94f4d878173ee105fc2628f1b899299d82
# Available At http://hg.logilab.org/users/dlaxalde/hg
#              hg pull http://hg.logilab.org/users/dlaxalde/hg -r 3fce2b5c21f3
# EXP-Topic diffhunks
mdiff: distinguish diff headers from hunks in unidiff()

Let unidiff return the list of headers it produces (lines '--- <original>' and
'+++ <new>') apart from diff hunks. In patch.diff(), we combine headers
generated there (not specific to unified format) with those from unidiff().
By returning a list of header lines, we do not append new lines in datetag
inner function of unidiff() so that all header lines are '\n'.join-ed in a
similar way.

Patch

diff --git a/mercurial/mdiff.py b/mercurial/mdiff.py
--- a/mercurial/mdiff.py
+++ b/mercurial/mdiff.py
@@ -196,15 +196,23 @@  def allblocks(text1, text2, opts=None, l
         yield s1, '='
 
 def unidiff(a, ad, b, bd, fn1, fn2, opts=defaultopts):
+    """Return a unified diff as a (headers, hunkstext) tuple.
+
+    If the diff is not null, `headers` is a list with unified diff header
+    lines "--- <original>" and "+++ <new>" and `hunkstext` is a string
+    containing diff hunks. Otherwise, both `headers` and `hunkstext` are
+    empty.
+    """
     def datetag(date, fn=None):
         if not opts.git and not opts.nodates:
-            return '\t%s\n' % date
+            return '\t%s' % date
         if fn and ' ' in fn:
-            return '\t\n'
-        return '\n'
+            return '\t'
+        return ''
 
+    sentinel = [], ""
     if not a and not b:
-        return ""
+        return sentinel
 
     if opts.noprefix:
         aprefix = bprefix = ''
@@ -219,7 +227,8 @@  def unidiff(a, ad, b, bd, fn1, fn2, opts
 
     if not opts.text and (util.binary(a) or util.binary(b)):
         if a and b and len(a) == len(b) and a == b:
-            return ""
+            return sentinel
+        headerlines = []
         l = ['Binary file %s has changed\n' % fn1]
     elif not a:
         b = splitnewlines(b)
@@ -228,8 +237,8 @@  def unidiff(a, ad, b, bd, fn1, fn2, opts
         else:
             l1 = "--- %s%s%s" % (aprefix, fn1, datetag(ad, fn1))
         l2 = "+++ %s%s" % (bprefix + fn2, datetag(bd, fn2))
-        l3 = "@@ -0,0 +1,%d @@\n" % len(b)
-        l = [l1, l2, l3] + ["+" + e for e in b]
+        headerlines = [l1, l2]
+        l = ["@@ -0,0 +1,%d @@\n" % len(b)] + ["+" + e for e in b]
     elif not b:
         a = splitnewlines(a)
         l1 = "--- %s%s%s" % (aprefix, fn1, datetag(ad, fn1))
@@ -237,21 +246,23 @@  def unidiff(a, ad, b, bd, fn1, fn2, opts
             l2 = '+++ /dev/null%s' % datetag(epoch)
         else:
             l2 = "+++ %s%s%s" % (bprefix, fn2, datetag(bd, fn2))
-        l3 = "@@ -1,%d +0,0 @@\n" % len(a)
-        l = [l1, l2, l3] + ["-" + e for e in a]
+        headerlines = [l1, l2]
+        l = ["@@ -1,%d +0,0 @@\n" % len(a)] + ["-" + e for e in a]
     else:
         l = sum((hlines for hrange, hlines in _unidiff(a, b, opts=opts)), [])
         if not l:
-            return ""
+            return sentinel
 
-        l.insert(0, "--- %s%s%s" % (aprefix, fn1, datetag(ad, fn1)))
-        l.insert(1, "+++ %s%s%s" % (bprefix, fn2, datetag(bd, fn2)))
+        headerlines = [
+            "--- %s%s%s" % (aprefix, fn1, datetag(ad, fn1)),
+            "+++ %s%s%s" % (bprefix, fn2, datetag(bd, fn2)),
+        ]
 
     for ln in xrange(len(l)):
         if l[ln][-1] != '\n':
             l[ln] += "\n\ No newline at end of file\n"
 
-    return "".join(l)
+    return headerlines, "".join(l)
 
 def _unidiff(t1, t2, opts=defaultopts):
     """Yield hunks of a headerless unified diff from t1 and t2 texts.
diff --git a/mercurial/patch.py b/mercurial/patch.py
--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -2547,9 +2547,10 @@  def trydiff(repo, revs, ctx1, ctx2, modi
                                gitindex(content2)[0:opts.index],
                                gitmode[flag]))
 
-            text = mdiff.unidiff(content1, date1,
-                                 content2, date2,
-                                 path1, path2, opts=opts)
+            uheaders, text = mdiff.unidiff(content1, date1,
+                                           content2, date2,
+                                           path1, path2, opts=opts)
+            header.extend(uheaders)
         if header and (text or len(header) > 1):
             yield '\n'.join(header) + '\n'
         if text: