Patchwork [1,of,6] patch: refactor content diffing part in separate fn so extensions can wrap

login
register
mail settings
Submitter Pulkit Goyal
Date July 14, 2020, 6:39 p.m.
Message ID <be7975344fe67437a506.1594751986@workspace>
Download mbox | patch
Permalink /patch/46736/
State Accepted
Headers show

Comments

Pulkit Goyal - July 14, 2020, 6:39 p.m.
# HG changeset patch
# User Pulkit Goyal <7895pulkit@gmail.com>
# Date 1594029713 -19800
#      Mon Jul 06 15:31:53 2020 +0530
# Node ID be7975344fe67437a5068c6a940c33e5ed234917
# Parent  93e8e6e0b5fb8afb863e0aee3d0f8a7ccf3f669d
# EXP-Topic diff-refactor
patch: refactor content diffing part in separate fn so extensions can wrap

Right now extdiff uses it's own logic using archival to diff two versions of
file using external diff tools. This makes the extdiff functionality
non-extensible.

This series is an attempt to refactor core patch and diff functionality so that
extdiff can wrap and reuse it. This will help us in using external diffing tools
at more places and not just extdiff command only then.

Differential Revision: https://phab.mercurial-scm.org/D8685
Yuya Nishihara - July 15, 2020, 11:33 a.m.
On Wed, 15 Jul 2020 00:09:46 +0530, Pulkit Goyal wrote:
> # HG changeset patch
> # User Pulkit Goyal <7895pulkit@gmail.com>
> # Date 1594029713 -19800
> #      Mon Jul 06 15:31:53 2020 +0530
> # Node ID be7975344fe67437a5068c6a940c33e5ed234917
> # Parent  93e8e6e0b5fb8afb863e0aee3d0f8a7ccf3f669d
> # EXP-Topic diff-refactor
> patch: refactor content diffing part in separate fn so extensions can wrap

Queued this, thanks.

Patch

diff --git a/mercurial/patch.py b/mercurial/patch.py
--- a/mercurial/patch.py
+++ b/mercurial/patch.py
@@ -2918,6 +2918,18 @@  def _filepairs(modified, added, removed,
         yield f1, f2, copyop
 
 
+def _gitindex(text):
+    if not text:
+        text = b""
+    l = len(text)
+    s = hashutil.sha1(b'blob %d\0' % l)
+    s.update(text)
+    return hex(s.digest())
+
+
+_gitmode = {b'l': b'120000', b'x': b'100755', b'': b'100644'}
+
+
 def trydiff(
     repo,
     revs,
@@ -2940,14 +2952,6 @@  def trydiff(
     pathfn is applied to every path in the diff output.
     '''
 
-    def gitindex(text):
-        if not text:
-            text = b""
-        l = len(text)
-        s = hashutil.sha1(b'blob %d\0' % l)
-        s.update(text)
-        return hex(s.digest())
-
     if opts.noprefix:
         aprefix = bprefix = b''
     else:
@@ -2964,8 +2968,6 @@  def trydiff(
     date1 = dateutil.datestr(ctx1.date())
     date2 = dateutil.datestr(ctx2.date())
 
-    gitmode = {b'l': b'120000', b'x': b'100755', b'': b'100644'}
-
     if not pathfn:
         pathfn = lambda f: f
 
@@ -3010,7 +3012,6 @@  def trydiff(
                 (f1 and f2 and flag1 != flag2)
             ):
                 losedatafn(f2 or f1)
-
         path1 = pathfn(f1 or f2)
         path2 = pathfn(f2 or f1)
         header = []
@@ -3019,11 +3020,11 @@  def trydiff(
                 b'diff --git %s%s %s%s' % (aprefix, path1, bprefix, path2)
             )
             if not f1:  # added
-                header.append(b'new file mode %s' % gitmode[flag2])
+                header.append(b'new file mode %s' % _gitmode[flag2])
             elif not f2:  # removed
-                header.append(b'deleted file mode %s' % gitmode[flag1])
+                header.append(b'deleted file mode %s' % _gitmode[flag1])
             else:  # modified/copied/renamed
-                mode1, mode2 = gitmode[flag1], gitmode[flag2]
+                mode1, mode2 = _gitmode[flag1], _gitmode[flag2]
                 if mode1 != mode2:
                     header.append(b'old mode %s' % mode1)
                     header.append(b'new mode %s' % mode2)
@@ -3067,39 +3068,66 @@  def trydiff(
             if fctx2 is not None:
                 content2 = fctx2.data()
 
-        if binary and opts.git and not opts.nobinary:
-            text = mdiff.b85diff(content1, content2)
-            if text:
-                header.append(
-                    b'index %s..%s' % (gitindex(content1), gitindex(content2))
+        data1 = (ctx1, fctx1, path1, flag1, content1, date1)
+        data2 = (ctx2, fctx2, path2, flag2, content2, date2)
+        yield diffcontent(data1, data2, header, binary, opts)
+
+
+def diffcontent(data1, data2, header, binary, opts):
+    """ diffs two versions of a file.
+
+    data1 and data2 are tuples containg:
+
+        * ctx: changeset for the file
+        * fctx: file context for that file
+        * path1: name of the file
+        * flag: flags of the file
+        * content: full content of the file (can be null in case of binary)
+        * date: date of the changeset
+
+    header: the patch header
+    binary: whether the any of the version of file is binary or not
+    opts:   user passed options
+
+    It exists as a separate function so that extensions like extdiff can wrap
+    it and use the file content directly.
+    """
+
+    ctx1, fctx1, path1, flag1, content1, date1 = data1
+    ctx2, fctx2, path2, flag2, content2, date2 = data2
+    if binary and opts.git and not opts.nobinary:
+        text = mdiff.b85diff(content1, content2)
+        if text:
+            header.append(
+                b'index %s..%s' % (_gitindex(content1), _gitindex(content2))
+            )
+        hunks = ((None, [text]),)
+    else:
+        if opts.git and opts.index > 0:
+            flag = flag1
+            if flag is None:
+                flag = flag2
+            header.append(
+                b'index %s..%s %s'
+                % (
+                    _gitindex(content1)[0 : opts.index],
+                    _gitindex(content2)[0 : opts.index],
+                    _gitmode[flag],
                 )
-            hunks = ((None, [text]),)
-        else:
-            if opts.git and opts.index > 0:
-                flag = flag1
-                if flag is None:
-                    flag = flag2
-                header.append(
-                    b'index %s..%s %s'
-                    % (
-                        gitindex(content1)[0 : opts.index],
-                        gitindex(content2)[0 : opts.index],
-                        gitmode[flag],
-                    )
-                )
-
-            uheaders, hunks = mdiff.unidiff(
-                content1,
-                date1,
-                content2,
-                date2,
-                path1,
-                path2,
-                binary=binary,
-                opts=opts,
             )
-            header.extend(uheaders)
-        yield fctx1, fctx2, header, hunks
+
+        uheaders, hunks = mdiff.unidiff(
+            content1,
+            date1,
+            content2,
+            date2,
+            path1,
+            path2,
+            binary=binary,
+            opts=opts,
+        )
+        header.extend(uheaders)
+    return fctx1, fctx2, header, hunks
 
 
 def diffstatsum(stats):