patch: replace "prefix" and "relroot" arguments by "pathfn" (API)
authorMartin von Zweigbergk <martinvonz@google.com>
Wed, 06 Feb 2019 23:12:56 -0800
changeset 41657 d4c9eebdd72d
parent 41656 2306158314e9
child 41658 ec37db02fc72
patch: replace "prefix" and "relroot" arguments by "pathfn" (API) The two arguments serve a very similar purpose: "relroot" is stripped from the front of the path, and then "prefix" (a subrepo path) is added (also to the front). Passing in a function that does that is more generic and will make it easier to respect ui.relative-paths in later patches (don't worry, I'm not going to respect that option for regular patches, only for --stat). I'm deliberately not calling it "uipathfn", because it's generally for producing valid diffs (including when prefix is non-empty), so things like using backslash on Windows is not an option. Differential Revision: https://phab.mercurial-scm.org/D5894
mercurial/context.py
mercurial/logcmdutil.py
mercurial/patch.py
--- a/mercurial/context.py	Sat Feb 09 01:24:32 2019 +0100
+++ b/mercurial/context.py	Wed Feb 06 23:12:56 2019 -0800
@@ -294,7 +294,7 @@
                               listsubrepos=listsubrepos, badfn=badfn)
 
     def diff(self, ctx2=None, match=None, changes=None, opts=None,
-             losedatafn=None, prefix='', relroot='', copy=None,
+             losedatafn=None, pathfn=None, copy=None,
              copysourcematch=None, hunksfilterfn=None):
         """Returns a diff generator for the given contexts and matcher"""
         if ctx2 is None:
@@ -302,9 +302,8 @@
         if ctx2 is not None:
             ctx2 = self._repo[ctx2]
         return patch.diff(self._repo, ctx2, self, match=match, changes=changes,
-                          opts=opts, losedatafn=losedatafn, prefix=prefix,
-                          relroot=relroot, copy=copy,
-                          copysourcematch=copysourcematch,
+                          opts=opts, losedatafn=losedatafn, pathfn=pathfn,
+                          copy=copy, copysourcematch=copysourcematch,
                           hunksfilterfn=hunksfilterfn)
 
     def dirs(self):
--- a/mercurial/logcmdutil.py	Sat Feb 09 01:24:32 2019 +0100
+++ b/mercurial/logcmdutil.py	Wed Feb 06 23:12:56 2019 -0800
@@ -9,6 +9,7 @@
 
 import itertools
 import os
+import posixpath
 
 from .i18n import _
 from .node import (
@@ -65,6 +66,8 @@
     else:
         relroot = ''
     copysourcematch = None
+    def pathfn(f):
+        return posixpath.join(prefix, f)
     if relroot != '':
         # XXX relative roots currently don't work if the root is within a
         # subrepo
@@ -79,14 +82,22 @@
         match = matchmod.intersectmatchers(match, relrootmatch)
         copysourcematch = relrootmatch
 
+        checkroot = (repo.ui.configbool('devel', 'all-warnings') or
+                     repo.ui.configbool('devel', 'check-relroot'))
+        def pathfn(f):
+            if checkroot and not f.startswith(relroot):
+                raise AssertionError(
+                    "file %s doesn't start with relroot %s" % (f, relroot))
+            return posixpath.join(prefix, f[len(relroot):])
+
     if stat:
         diffopts = diffopts.copy(context=0, noprefix=False)
         width = 80
         if not ui.plain():
             width = ui.termwidth() - graphwidth
 
-    chunks = ctx2.diff(ctx1, match, changes, opts=diffopts, prefix=prefix,
-                       relroot=relroot, copysourcematch=copysourcematch,
+    chunks = ctx2.diff(ctx1, match, changes, opts=diffopts, pathfn=pathfn,
+                       copysourcematch=copysourcematch,
                        hunksfilterfn=hunksfilterfn)
 
     if fp is not None or ui.canwritewithoutlabels():
--- a/mercurial/patch.py	Sat Feb 09 01:24:32 2019 +0100
+++ b/mercurial/patch.py	Wed Feb 06 23:12:56 2019 -0800
@@ -15,7 +15,6 @@
 import errno
 import hashlib
 import os
-import posixpath
 import re
 import shutil
 import zlib
@@ -2239,7 +2238,7 @@
 difffeatureopts = diffutil.difffeatureopts
 
 def diff(repo, node1=None, node2=None, match=None, changes=None,
-         opts=None, losedatafn=None, prefix='', relroot='', copy=None,
+         opts=None, losedatafn=None, pathfn=None, copy=None,
          copysourcematch=None, hunksfilterfn=None):
     '''yields diff of changes to files between two nodes, or node and
     working directory.
@@ -2277,9 +2276,8 @@
     ctx2 = repo[node2]
 
     for fctx1, fctx2, hdr, hunks in diffhunks(
-            repo, ctx1=ctx1, ctx2=ctx2,
-            match=match, changes=changes, opts=opts,
-            losedatafn=losedatafn, prefix=prefix, relroot=relroot, copy=copy,
+            repo, ctx1=ctx1, ctx2=ctx2, match=match, changes=changes, opts=opts,
+            losedatafn=losedatafn, pathfn=pathfn, copy=copy,
             copysourcematch=copysourcematch):
         if hunksfilterfn is not None:
             # If the file has been removed, fctx2 is None; but this should
@@ -2294,9 +2292,8 @@
         if text:
             yield text
 
-def diffhunks(repo, ctx1, ctx2, match=None, changes=None,
-              opts=None, losedatafn=None, prefix='', relroot='', copy=None,
-              copysourcematch=None):
+def diffhunks(repo, ctx1, ctx2, match=None, changes=None, opts=None,
+              losedatafn=None, pathfn=None, copy=None, copysourcematch=None):
     """Yield diff of changes to files in the form of (`header`, `hunks`) tuples
     where `header` is a list of diff headers and `hunks` is an iterable of
     (`hunkrange`, `hunklines`) tuples.
@@ -2376,7 +2373,7 @@
 
     def difffn(opts, losedata):
         return trydiff(repo, revs, ctx1, ctx2, modified, added, removed,
-                       copy, getfilectx, opts, losedata, prefix, relroot)
+                       copy, getfilectx, opts, losedata, pathfn)
     if opts.upgrade and not opts.git:
         try:
             def losedata(fn):
@@ -2591,16 +2588,14 @@
         yield f1, f2, copyop
 
 def trydiff(repo, revs, ctx1, ctx2, modified, added, removed,
-            copy, getfilectx, opts, losedatafn, prefix, relroot):
+            copy, getfilectx, opts, losedatafn, pathfn):
     '''given input data, generate a diff and yield it in blocks
 
     If generating a diff would lose data like flags or binary data and
     losedatafn is not None, it will be called.
 
-    relroot is removed and prefix is added to every path in the diff output.
-
-    If relroot is not empty, this function expects every path in modified,
-    added, removed and copy to start with it.'''
+    pathfn is applied to every path in the diff output.
+    '''
 
     def gitindex(text):
         if not text:
@@ -2628,12 +2623,8 @@
 
     gitmode = {'l': '120000', 'x': '100755', '': '100644'}
 
-    if relroot != '' and (repo.ui.configbool('devel', 'all-warnings')
-                          or repo.ui.configbool('devel', 'check-relroot')):
-        for f in modified + added + removed + list(copy) + list(copy.values()):
-            if f is not None and not f.startswith(relroot):
-                raise AssertionError(
-                    "file %s doesn't start with relroot %s" % (f, relroot))
+    if not pathfn:
+        pathfn = lambda f: f
 
     for f1, f2, copyop in _filepairs(modified, added, removed, copy, opts):
         content1 = None
@@ -2670,10 +2661,8 @@
                 (f1 and f2 and flag1 != flag2)):
                 losedatafn(f2 or f1)
 
-        path1 = f1 or f2
-        path2 = f2 or f1
-        path1 = posixpath.join(prefix, path1[len(relroot):])
-        path2 = posixpath.join(prefix, path2[len(relroot):])
+        path1 = pathfn(f1 or f2)
+        path2 = pathfn(f2 or f1)
         header = []
         if opts.git:
             header.append('diff --git %s%s %s%s' %