patch: make parsepatch optionally trim context lines
authorJun Wu <quark@fb.com>
Tue, 04 Jul 2017 16:41:28 -0700
changeset 33270 f7b635716ef2
parent 33269 ead6749354e1
child 33271 02299a28ba34
patch: make parsepatch optionally trim context lines Previously there is a suspicious `if False and delta > 0` which dates back to the beginning of hgext/record.py (b2607267236d). The "trimming context lines" feature could be useful (and is used by the next patch). So let's enable it. This patch adds a new `maxcontext` parameter to `recordhunk` and `parsepatch`, changing the `if False` condition to respect it. The old `trimcontext` implementation is also wrong - it does not update `toline` correctly and it does not do the right thing for `before` context. A doctest was added to guard us from making a similar mistake again. Since `maxcontext` is set to `None` (unlimited), there is no behavior change.
mercurial/patch.py
--- a/mercurial/patch.py	Tue Jul 04 16:36:48 2017 -0700
+++ b/mercurial/patch.py	Tue Jul 04 16:41:28 2017 -0700
@@ -922,18 +922,24 @@
 
     XXX shouldn't we merge this with the other hunk class?
     """
-    maxcontext = 3
 
-    def __init__(self, header, fromline, toline, proc, before, hunk, after):
-        def trimcontext(number, lines):
-            delta = len(lines) - self.maxcontext
-            if False and delta > 0:
-                return number + delta, lines[:self.maxcontext]
-            return number, lines
+    def __init__(self, header, fromline, toline, proc, before, hunk, after,
+                 maxcontext=None):
+        def trimcontext(lines, reverse=False):
+            if maxcontext is not None:
+                delta = len(lines) - maxcontext
+                if delta > 0:
+                    if reverse:
+                        return delta, lines[delta:]
+                    else:
+                        return delta, lines[:maxcontext]
+            return 0, lines
 
         self.header = header
-        self.fromline, self.before = trimcontext(fromline, before)
-        self.toline, self.after = trimcontext(toline, after)
+        trimedbefore, self.before = trimcontext(before, True)
+        self.fromline = fromline + trimedbefore
+        self.toline = toline + trimedbefore
+        _trimedafter, self.after = trimcontext(after, False)
         self.proc = proc
         self.hunk = hunk
         self.added, self.removed = self.countchanges(self.hunk)
@@ -1527,8 +1533,49 @@
         newhunks.append(c)
     return newhunks
 
-def parsepatch(originalchunks):
-    """patch -> [] of headers -> [] of hunks """
+def parsepatch(originalchunks, maxcontext=None):
+    """patch -> [] of headers -> [] of hunks
+
+    If maxcontext is not None, trim context lines if necessary.
+
+    >>> rawpatch = '''diff --git a/folder1/g b/folder1/g
+    ... --- a/folder1/g
+    ... +++ b/folder1/g
+    ... @@ -1,8 +1,10 @@
+    ...  1
+    ...  2
+    ... -3
+    ...  4
+    ...  5
+    ...  6
+    ... +6.1
+    ... +6.2
+    ...  7
+    ...  8
+    ... +9'''
+    >>> out = util.stringio()
+    >>> headers = parsepatch([rawpatch], maxcontext=1)
+    >>> for header in headers:
+    ...     header.write(out)
+    ...     for hunk in header.hunks:
+    ...         hunk.write(out)
+    >>> print(out.getvalue())
+    diff --git a/folder1/g b/folder1/g
+    --- a/folder1/g
+    +++ b/folder1/g
+    @@ -2,3 +2,2 @@
+     2
+    -3
+     4
+    @@ -6,2 +5,4 @@
+     6
+    +6.1
+    +6.2
+     7
+    @@ -8,1 +9,2 @@
+     8
+    +9
+    """
     class parser(object):
         """patch parsing state machine"""
         def __init__(self):
@@ -1550,7 +1597,7 @@
         def addcontext(self, context):
             if self.hunk:
                 h = recordhunk(self.header, self.fromline, self.toline,
-                        self.proc, self.before, self.hunk, context)
+                        self.proc, self.before, self.hunk, context, maxcontext)
                 self.header.hunks.append(h)
                 self.fromline += len(self.before) + h.removed
                 self.toline += len(self.before) + h.added