Patchwork D8686: extdiff: refactor logic which does diff of patches

login
register
mail settings
Submitter phabricator
Date July 7, 2020, 9:27 a.m.
Message ID <differential-rev-PHID-DREV-ci6nwqtilm3kkhqmpxxj-req@mercurial-scm.org>
Download mbox | patch
Permalink /patch/46638/
State Superseded
Headers show

Comments

phabricator - July 7, 2020, 9:27 a.m.
pulkit created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  The current extdiff code is hard to understand on first look. Took me few hours
  to grasp the code. Before adding more things, decided to do some refactoring.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D8686

AFFECTED FILES
  hgext/extdiff.py

CHANGE DETAILS




To: pulkit, #hg-reviewers
Cc: mercurial-patches, mercurial-devel

Patch

diff --git a/hgext/extdiff.py b/hgext/extdiff.py
--- a/hgext/extdiff.py
+++ b/hgext/extdiff.py
@@ -350,6 +350,38 @@ 
                 proc.wait()
 
 
+def diffpatch(ui, repo, node1a, node2, tmproot, matcher, cmdline, do3way):
+    template = b'hg-%h.patch'
+    with formatter.nullformatter(ui, b'extdiff', {}) as fm:
+        cmdutil.export(
+            repo,
+            [repo[node1a].rev(), repo[node2].rev()],
+            fm,
+            fntemplate=repo.vfs.reljoin(tmproot, template),
+            match=matcher,
+        )
+    label1a = cmdutil.makefilename(repo[node1a], template)
+    label2 = cmdutil.makefilename(repo[node2], template)
+    dir1a = repo.vfs.reljoin(tmproot, label1a)
+    dir2 = repo.vfs.reljoin(tmproot, label2)
+    dir1b = None
+    label1b = None
+    cmdline = formatcmdline(
+        cmdline,
+        repo.root,
+        do3way=do3way,
+        parent1=dir1a,
+        plabel1=label1a,
+        parent2=dir1b,
+        plabel2=label1b,
+        child=dir2,
+        clabel=label2,
+    )
+    ui.debug(b'running %r in %s\n' % (pycompat.bytestr(cmdline), tmproot))
+    ui.system(cmdline, cwd=tmproot, blockedtag=b'extdiff')
+    return 1
+
+
 def dodiff(ui, repo, cmdline, pats, opts, guitool=False):
     '''Do the actual diff:
 
@@ -389,6 +421,7 @@ 
     subrepos = opts.get(b'subrepos')
 
     matcher = scmutil.match(repo[node2], pats, opts)
+    tmproot = pycompat.mkdtemp(prefix=b'extdiff.')
 
     if opts.get(b'patch'):
         if subrepos:
@@ -414,82 +447,66 @@ 
         if not common:
             return 0
 
-    tmproot = pycompat.mkdtemp(prefix=b'extdiff.')
     try:
-        if not opts.get(b'patch'):
-            # Always make a copy of node1a (and node1b, if applicable)
-            dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a)
-            dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot, subrepos)[
+        if opts.get(b'patch'):
+            return diffpatch(
+                ui, repo, node1a, node2, tmproot, matcher, cmdline, do3way
+            )
+
+        # Always make a copy of node1a (and node1b, if applicable)
+        dir1a_files = mod_a | rem_a | ((mod_b | add_b) - add_a)
+        dir1a = snapshot(ui, repo, dir1a_files, node1a, tmproot, subrepos)[0]
+        rev1a = b'@%d' % repo[node1a].rev()
+        if do3way:
+            dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b)
+            dir1b = snapshot(ui, repo, dir1b_files, node1b, tmproot, subrepos)[
                 0
             ]
-            rev1a = b'@%d' % repo[node1a].rev()
-            if do3way:
-                dir1b_files = mod_b | rem_b | ((mod_a | add_a) - add_b)
-                dir1b = snapshot(
-                    ui, repo, dir1b_files, node1b, tmproot, subrepos
-                )[0]
-                rev1b = b'@%d' % repo[node1b].rev()
-            else:
-                dir1b = None
-                rev1b = b''
-
-            fnsandstat = []
+            rev1b = b'@%d' % repo[node1b].rev()
+        else:
+            dir1b = None
+            rev1b = b''
 
-            # If node2 in not the wc or there is >1 change, copy it
-            dir2root = b''
-            rev2 = b''
-            if node2:
-                dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0]
-                rev2 = b'@%d' % repo[node2].rev()
-            elif len(common) > 1:
-                # we only actually need to get the files to copy back to
-                # the working dir in this case (because the other cases
-                # are: diffing 2 revisions or single file -- in which case
-                # the file is already directly passed to the diff tool).
-                dir2, fnsandstat = snapshot(
-                    ui, repo, modadd, None, tmproot, subrepos
-                )
-            else:
-                # This lets the diff tool open the changed file directly
-                dir2 = b''
-                dir2root = repo.root
+        fnsandstat = []
 
-            label1a = rev1a
-            label1b = rev1b
-            label2 = rev2
+        # If node2 in not the wc or there is >1 change, copy it
+        dir2root = b''
+        rev2 = b''
+        if node2:
+            dir2 = snapshot(ui, repo, modadd, node2, tmproot, subrepos)[0]
+            rev2 = b'@%d' % repo[node2].rev()
+        elif len(common) > 1:
+            # we only actually need to get the files to copy back to
+            # the working dir in this case (because the other cases
+            # are: diffing 2 revisions or single file -- in which case
+            # the file is already directly passed to the diff tool).
+            dir2, fnsandstat = snapshot(
+                ui, repo, modadd, None, tmproot, subrepos
+            )
+        else:
+            # This lets the diff tool open the changed file directly
+            dir2 = b''
+            dir2root = repo.root
 
-            # If only one change, diff the files instead of the directories
-            # Handle bogus modifies correctly by checking if the files exist
-            if len(common) == 1:
-                common_file = util.localpath(common.pop())
-                dir1a = os.path.join(tmproot, dir1a, common_file)
-                label1a = common_file + rev1a
-                if not os.path.isfile(dir1a):
-                    dir1a = pycompat.osdevnull
-                if do3way:
-                    dir1b = os.path.join(tmproot, dir1b, common_file)
-                    label1b = common_file + rev1b
-                    if not os.path.isfile(dir1b):
-                        dir1b = pycompat.osdevnull
-                dir2 = os.path.join(dir2root, dir2, common_file)
-                label2 = common_file + rev2
-        else:
-            template = b'hg-%h.patch'
-            with formatter.nullformatter(ui, b'extdiff', {}) as fm:
-                cmdutil.export(
-                    repo,
-                    [repo[node1a].rev(), repo[node2].rev()],
-                    fm,
-                    fntemplate=repo.vfs.reljoin(tmproot, template),
-                    match=matcher,
-                )
-            label1a = cmdutil.makefilename(repo[node1a], template)
-            label2 = cmdutil.makefilename(repo[node2], template)
-            dir1a = repo.vfs.reljoin(tmproot, label1a)
-            dir2 = repo.vfs.reljoin(tmproot, label2)
-            dir1b = None
-            label1b = None
-            fnsandstat = []
+        label1a = rev1a
+        label1b = rev1b
+        label2 = rev2
+
+        # If only one change, diff the files instead of the directories
+        # Handle bogus modifies correctly by checking if the files exist
+        if len(common) == 1:
+            common_file = util.localpath(common.pop())
+            dir1a = os.path.join(tmproot, dir1a, common_file)
+            label1a = common_file + rev1a
+            if not os.path.isfile(dir1a):
+                dir1a = pycompat.osdevnull
+            if do3way:
+                dir1b = os.path.join(tmproot, dir1b, common_file)
+                label1b = common_file + rev1b
+                if not os.path.isfile(dir1b):
+                    dir1b = pycompat.osdevnull
+            dir2 = os.path.join(dir2root, dir2, common_file)
+            label2 = common_file + rev2
 
         if not perfile:
             # Run the external tool on the 2 temp directories or the patches