[PATCH 1 of 2 STABLE] diffhelpers: add canstripcr=True to fix_newline

Sean Farley sean at farley.io
Mon Apr 24 21:41:41 UTC 2017


Phil Cohen <phillco at fb.com> writes:

> # HG changeset patch
> # User Phil Cohen <phillco at fb.com>
> # Date 1493055298 25200
> #      Mon Apr 24 10:34:58 2017 -0700
> # Branch stable
> # Node ID 7f413064263ff1b3cf98d1b23ae35e4c098da482
> # Parent  0537d2d94c0fb747e75272f9f950cc29b6e0dce8
> diffhelpers: add canstripcr=True to fix_newline
>
> When processing a patch ending in "\ No newline at end of file", we used to
> remove the \n from the end of that line, and if a \r was present before the \n,
> we would remove that as well, probably assuming the patch was from a Windows
> system.
>
> However, this isn't always correct: patches created on Unix can legitimately end
> in a CR, and so this logic will falsely strip the CR and fail to import.

Huh.

> A better way to determine if the CR is part of the patch, or part of the newline
> inserted by the patcher, is to see what the "\ No newline" line itself ends
> with. If CRLF, then CRLFs may be stripped; if only LF, then only LFs may be.

I guess that makes sense (though, I'd like someone else to confirm).

> This is needed to fix issue4042.
>
> diff --git a/mercurial/diffhelpers.c b/mercurial/diffhelpers.c
> --- a/mercurial/diffhelpers.c
> +++ b/mercurial/diffhelpers.c
> @@ -18,8 +18,9 @@
>  
>  
>  /* fixup the last lines of a and b when the patch has no newline at eof */
> -static void _fix_newline(PyObject *hunk, PyObject *a, PyObject *b)
> -{
> +static void _fix_newline(PyObject *hunk, PyObject *a, PyObject *b,
> +			 bool canstripcr)
> + {

Very minor nit: is that an extra space in front of '{'? Not sure about
our C-style.

>  	Py_ssize_t hunksz = PyList_Size(hunk);
>  	PyObject *s = PyList_GET_ITEM(hunk, hunksz-1);
>  	char *l = PyBytes_AsString(s);
> @@ -29,7 +30,7 @@
>  	PyObject *hline;
>  	Py_ssize_t sz = PyBytes_GET_SIZE(s);
>  
> -	if (sz > 1 && l[sz-2] == '\r')
> +	if (sz > 1 && l[sz-2] == '\r' && canstripcr)
>  		/* tolerate CRLF in last line */
>  		sz -= 1;
>  
> @@ -54,9 +55,10 @@
>  fix_newline(PyObject *self, PyObject *args)
>  {
>  	PyObject *hunk, *a, *b;
> -	if (!PyArg_ParseTuple(args, "OOO", &hunk, &a, &b))
> +	bool canstripcr = true;
> +	if (!PyArg_ParseTuple(args, "OOO|B", &hunk, &a, &b, &canstripcr))
>  		return NULL;
> -	_fix_newline(hunk, a, b);
> +	_fix_newline(hunk, a, b, canstripcr);
>  	return Py_BuildValue("l", 0);
>  }
>  
> @@ -97,8 +99,18 @@
>  			x = PyFile_GetLine(fp, 0);
>  			s = PyBytes_AsString(x);
>  			c = *s;
> -			if (strcmp(s, "\\ No newline at end of file\n") == 0) {
> -				_fix_newline(hunk, a, b);
> +			char *prefix = "\\ No newline at end of file";
> +
> +			if (strncmp(s, prefix, strlen(prefix)) == 0) {
> +				bool canstripcr = true;
> +				size_t len = strlen(s);
> +				/* The "\\ No newline" line must end in CRLF to
> +				strip CRs -- see comment in diffhelpers.py */
> +				if (len > 2 && s[len - 2] != '\r') {
> +					canstripcr = false;
> +				}
> +
> +				_fix_newline(hunk, a, b, canstripcr);
>  				continue;
>  			}
>  			if (c == '\n') {
> diff --git a/mercurial/pure/diffhelpers.py b/mercurial/pure/diffhelpers.py
> --- a/mercurial/pure/diffhelpers.py
> +++ b/mercurial/pure/diffhelpers.py
> @@ -34,10 +34,18 @@
>                  a.append(s)
>      return 0
>  
> -def fix_newline(hunk, a, b):
> +# fix_newline removes the newline from the last line of a patch that, while
> +# currently ends in a newline, did not originally as indicated by a subsequent
> +# "\ No newline at end of file" line.
> +#
> +# canstripcr should be true only if the "\ No newline" line itself ends with a
> +# CRLF. If so, a CRLF in the last line of the patch can also be removed (in
> +# addition to just a LF). If not, it is likely the CR was part of the original
> +# patch and should remain.
> +def fix_newline(hunk, a, b, canstripcr=True):
>      l = hunk[-1]
>      # tolerate CRLF in last line
> -    if l.endswith('\r\n'):
> +    if l.endswith('\r\n') and canstripcr:
>          hline = l[:-2]
>      else:
>          hline = l[:-1]

First patch seems fine to me. I'd like more reviewers since I'm a little
shaky on our C code.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 800 bytes
Desc: not available
URL: <http://lists.mercurial-scm.org/pipermail/mercurial-devel/attachments/20170424/a337f75e/attachment.asc>


More information about the Mercurial-devel mailing list