patch: use diffhelpers from Rust bindings

Summary:
Drop other diffhelpers implementations.
The Rust implementation does a better job on type checks and won't segfault.

Reviewed By: xavierd

Differential Revision: D20935367

fbshipit-source-id: f59240f3a661efe1ca6e451922bcb3ca6ee6ae22
This commit is contained in:
Jun Wu 2020-04-09 18:20:36 -07:00 committed by Facebook GitHub Bot
parent 49acaf17b3
commit 514f0141f8
5 changed files with 1 additions and 279 deletions

View File

@ -1,195 +0,0 @@
/*
* Portions Copyright (c) Facebook, Inc. and its affiliates.
*
* This software may be used and distributed according to the terms of the
* GNU General Public License version 2.
*/
/*
* diffhelpers.c - helper routines for mpatch
*
* Copyright 2007 Chris Mason <chris.mason@oracle.com>
*
* This software may be used and distributed according to the terms
* of the GNU General Public License v2, incorporated herein by reference.
*/
#include <Python.h>
#include <stdlib.h>
#include <string.h>
#include "eden/scm/edenscm/mercurial/cext/util.h"
static char diffhelpers_doc[] = "Efficient diff parsing";
static PyObject* diffhelpers_Error;
/* 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) {
Py_ssize_t hunksz = PyList_Size(hunk);
PyObject* s = PyList_GET_ITEM(hunk, hunksz - 1);
char* l = PyBytes_AsString(s);
Py_ssize_t alen = PyList_Size(a);
Py_ssize_t blen = PyList_Size(b);
char c = l[0];
PyObject* hline;
Py_ssize_t sz = PyBytes_GET_SIZE(s);
if (sz > 1 && l[sz - 2] == '\r')
/* tolerate CRLF in last line */
sz -= 1;
hline = PyBytes_FromStringAndSize(l, sz - 1);
if (!hline) {
return;
}
if (c == ' ' || c == '+') {
PyObject* rline = PyBytes_FromStringAndSize(l + 1, sz - 2);
PyList_SetItem(b, blen - 1, rline);
}
if (c == ' ' || c == '-') {
Py_INCREF(hline);
PyList_SetItem(a, alen - 1, hline);
}
PyList_SetItem(hunk, hunksz - 1, hline);
}
/* python callable form of _fix_newline */
static PyObject* fix_newline(PyObject* self, PyObject* args) {
PyObject *hunk, *a, *b;
if (!PyArg_ParseTuple(args, "OOO", &hunk, &a, &b))
return NULL;
_fix_newline(hunk, a, b);
return Py_BuildValue("l", 0);
}
#if (PY_VERSION_HEX < 0x02050000)
static const char* addlines_format = "OOiiOO";
#else
static const char* addlines_format = "OOnnOO";
#endif
/*
* read lines from fp into the hunk. The hunk is parsed into two arrays
* a and b. a gets the old state of the text, b gets the new state
* The control char from the hunk is saved when inserting into a, but not b
* (for performance while deleting files)
*/
static PyObject* addlines(PyObject* self, PyObject* args) {
PyObject *fp, *hunk, *a, *b, *x;
Py_ssize_t i;
Py_ssize_t lena, lenb;
Py_ssize_t num;
Py_ssize_t todoa, todob;
char *s, c;
PyObject* l;
if (!PyArg_ParseTuple(
args, addlines_format, &fp, &hunk, &lena, &lenb, &a, &b))
return NULL;
while (1) {
todoa = lena - PyList_Size(a);
todob = lenb - PyList_Size(b);
num = todoa > todob ? todoa : todob;
if (num == 0)
break;
for (i = 0; i < num; i++) {
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);
continue;
}
if (c == '\n') {
/* Some patches may be missing the control char
* on empty lines. Supply a leading space. */
Py_DECREF(x);
x = PyBytes_FromString(" \n");
}
PyList_Append(hunk, x);
if (c == '+') {
l = PyBytes_FromString(s + 1);
PyList_Append(b, l);
Py_DECREF(l);
} else if (c == '-') {
PyList_Append(a, x);
} else {
l = PyBytes_FromString(s + 1);
PyList_Append(b, l);
Py_DECREF(l);
PyList_Append(a, x);
}
Py_DECREF(x);
}
}
return Py_BuildValue("l", 0);
}
/*
* compare the lines in a with the lines in b. a is assumed to have
* a control char at the start of each line, this char is ignored in the
* compare
*/
static PyObject* testhunk(PyObject* self, PyObject* args) {
PyObject *a, *b;
long bstart;
Py_ssize_t alen, blen;
Py_ssize_t i;
char *sa, *sb;
if (!PyArg_ParseTuple(args, "OOl", &a, &b, &bstart))
return NULL;
alen = PyList_Size(a);
blen = PyList_Size(b);
if (alen > blen - bstart || bstart < 0) {
return Py_BuildValue("l", -1);
}
for (i = 0; i < alen; i++) {
sa = PyBytes_AsString(PyList_GET_ITEM(a, i));
sb = PyBytes_AsString(PyList_GET_ITEM(b, i + bstart));
if (strcmp(sa + 1, sb) != 0)
return Py_BuildValue("l", -1);
}
return Py_BuildValue("l", 0);
}
static PyMethodDef methods[] = {
{"addlines", addlines, METH_VARARGS, "add lines to a hunk\n"},
{"fix_newline", fix_newline, METH_VARARGS, "fixup newline counters\n"},
{"testhunk", testhunk, METH_VARARGS, "test lines in a hunk\n"},
{NULL, NULL}};
static const int version = 1;
#ifdef IS_PY3K
static struct PyModuleDef diffhelpers_module = {PyModuleDef_HEAD_INIT,
"diffhelpers",
diffhelpers_doc,
-1,
methods};
PyMODINIT_FUNC PyInit_diffhelpers(void) {
PyObject* m;
m = PyModule_Create(&diffhelpers_module);
if (m == NULL)
return NULL;
diffhelpers_Error =
PyErr_NewException("diffhelpers.diffhelpersError", NULL, NULL);
Py_INCREF(diffhelpers_Error);
PyModule_AddObject(m, "diffhelpersError", diffhelpers_Error);
PyModule_AddIntConstant(m, "version", version);
return m;
}
#else
PyMODINIT_FUNC initdiffhelpers(void) {
PyObject* m;
m = Py_InitModule3("diffhelpers", methods, diffhelpers_doc);
diffhelpers_Error =
PyErr_NewException("diffhelpers.diffhelpersError", NULL, NULL);
PyModule_AddIntConstant(m, "version", version);
}
#endif

View File

@ -27,7 +27,7 @@ import tempfile
import zlib
from typing import List, Optional, Sequence, Tuple
from edenscmnative import diffhelpers
from bindings import diffhelpers
from . import (
copies,

View File

@ -1,71 +0,0 @@
# Portions Copyright (c) Facebook, Inc. and its affiliates.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2.
# diffhelpers.py - pure Python implementation of diffhelpers.c
#
# Copyright 2009 Matt Mackall <mpm@selenic.com> and others
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from __future__ import absolute_import
from ..pycompat import range
def addlines(fp, hunk, lena, lenb, a, b):
while True:
todoa = lena - len(a)
todob = lenb - len(b)
num = max(todoa, todob)
if num == 0:
break
for i in range(num):
s = fp.readline()
c = s[0]
if s == "\\ No newline at end of file\n":
fix_newline(hunk, a, b)
continue
if c == "\n":
# Some patches may be missing the control char
# on empty lines. Supply a leading space.
s = " \n"
hunk.append(s)
if c == "+":
b.append(s[1:])
elif c == "-":
a.append(s)
else:
b.append(s[1:])
a.append(s)
return 0
def fix_newline(hunk, a, b):
l = hunk[-1]
# tolerate CRLF in last line
if l.endswith("\r\n"):
hline = l[:-2]
else:
hline = l[:-1]
c = hline[0]
if c in " +":
b[-1] = hline[1:]
if c in " -":
a[-1] = hline
hunk[-1] = hline
return 0
def testhunk(a, b, bstart):
alen = len(a)
blen = len(b)
if alen > blen - bstart:
return -1
for i in range(alen):
if a[i][1:] != b[i + bstart]:
return -1
return 0

View File

@ -1535,12 +1535,6 @@ extmodules = [
include_dirs=include_dirs,
depends=common_depends + ["edenscm/mercurial/bdiff.h"],
),
Extension(
"edenscmnative.diffhelpers",
["edenscm/mercurial/cext/diffhelpers.c"],
include_dirs=include_dirs,
depends=common_depends,
),
Extension(
"edenscmnative.mpatch",
["edenscm/mercurial/mpatch.c", "edenscm/mercurial/cext/mpatch.c"],

View File

@ -1371,12 +1371,6 @@ extmodules = [
include_dirs=include_dirs,
depends=common_depends + ["edenscm/mercurial/bdiff.h"],
),
Extension(
"edenscmnative.diffhelpers",
["edenscm/mercurial/cext/diffhelpers.c"],
include_dirs=include_dirs,
depends=common_depends,
),
Extension(
"edenscmnative.mpatch",
["edenscm/mercurial/mpatch.c", "edenscm/mercurial/cext/mpatch.c"],