##// END OF EJS Templates
cmdutil: add class to restore dirstate during unexpected failure...
cmdutil: add class to restore dirstate during unexpected failure Before this patch, after "dirstate.write()" execution, there was no way to restore dirstate to the original status before "dirstate.write()". In some code paths, "dirstate.invalidate()" is used as a kind of "restore .hg/dirstate to the original status", but it just avoids writing changes in memory out, and doesn't actually restore the ".hg/dirstate" file. To fix the issue that the recent (in memory) dirstate isn't visible to external processes (e.g. "precommit" hooks), "dirstate.write()" should be invoked before invocation of external processes. But at the same time, ".hg/dirstate" should be restored to its content before "dirstate.write()" during an unexpected failure in some cases. This patch adds the class "dirstateguard" to easily restore ".hg/dirstate" during unexpected failures. Typical usecase of it is: # (1) build dirstate up .... # (2) write dirstate out, and backup ".hg/dirstate" dsguard = dirstateguard(repo, 'scopename') try: # (3) execute somethig to do: # this may imply making some additional changes on dirstate .... # (4) unlink backed-up dirstate file at the end of dsguard scope dsguard.close() finally: # (5) if execution is aborted before "dsguard.close()", # ".hg/dirstate" is restored from the backup dsguard.release() For this kind of issue, an "extending transaction" approach (in https://titanpad.com/mercurial32-sprint) seems to not be suitable, because: - transaction nesting occurs in some cases (e.g. "shelve => rebase"), and - "dirstate" may be already modified since the beginning of OUTER transaction scope, then - dirstate should be backed up into the file other than "dirstate.journal" at the beginning of INNER transaction scope, but - such alternative backup files are useless for transaction itself, and increases complication of its implementation "transaction" and "dirstateguard" differ from each other also in "what it should do for .hg/dirstate" in cases other than success. ============== ======= ======== ============= type success fail "hg rollback" ============== ======= ======== ============= transaction keep keep restore dirstateguard keep restore (not implied) ============== ======= ======== ============= Some collaboration between transaction and dirstate will probably be introduced in the future. But this layer is needed in all cases.

File last commit:

r23964:f1c127df stable
r24991:4169a4f8 default
Show More
diffhelpers.c
199 lines | 4.7 KiB | text/x-c | CLexer
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 /*
* 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>
Renato Cunha
diffhelpers.c: Added support for py3k....
r11363 #include "util.h"
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 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)
{
Adrian Buehlmann
diffhelpers: use Py_ssize_t in _fix_newline()...
r16693 Py_ssize_t hunksz = PyList_Size(hunk);
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 PyObject *s = PyList_GET_ITEM(hunk, hunksz-1);
Renato Cunha
diffhelpers.c: Added support for py3k....
r11363 char *l = PyBytes_AsString(s);
Adrian Buehlmann
diffhelpers: use Py_ssize_t in _fix_newline()...
r16693 Py_ssize_t alen = PyList_Size(a);
Py_ssize_t blen = PyList_Size(b);
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 char c = l[0];
Patrick Mezard
diffhelpers: fix variable declaration for MSVC (not C99)
r10146 PyObject *hline;
Adrian Buehlmann
diffhelpers: use Py_ssize_t in _fix_newline()...
r16693 Py_ssize_t sz = PyBytes_GET_SIZE(s);
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897
Patrick Mezard
diffhelpers: fix variable declaration for MSVC (not C99)
r10146 if (sz > 1 && l[sz-2] == '\r')
/* tolerate CRLF in last line */
sz -= 1;
Renato Cunha
diffhelpers.c: Added support for py3k....
r11363
hline = PyBytes_FromStringAndSize(l, sz-1);
Augie Fackler
diffhelpers: verify hline was created before using it...
r23959 if (!hline) {
Augie Fackler
diffhelpers: fix botched return statement from c8e7fa41bfc5...
r23964 return;
Augie Fackler
diffhelpers: verify hline was created before using it...
r23959 }
Patrick Mezard
diffhelpers: fix variable declaration for MSVC (not C99)
r10146
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 if (c == ' ' || c == '+') {
Renato Cunha
diffhelpers.c: Added support for py3k....
r11363 PyObject *rline = PyBytes_FromStringAndSize(l + 1, sz - 2);
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 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);
}
Adrian Buehlmann
diffhelpers: use Py_ssize_t in addlines()...
r16694 #if (PY_VERSION_HEX < 0x02050000)
static const char *addlines_format = "OOiiOO";
#else
static const char *addlines_format = "OOnnOO";
#endif
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 /*
* 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;
Adrian Buehlmann
diffhelpers: use Py_ssize_t in addlines()...
r16694 Py_ssize_t i;
Py_ssize_t lena, lenb;
Py_ssize_t num;
Py_ssize_t todoa, todob;
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 char *s, c;
PyObject *l;
Adrian Buehlmann
diffhelpers: use Py_ssize_t in addlines()...
r16694 if (!PyArg_ParseTuple(args, addlines_format,
&fp, &hunk, &lena, &lenb, &a, &b))
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 return NULL;
Matt Mackall
many, many trivial check-code fixups
r10282 while (1) {
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 todoa = lena - PyList_Size(a);
todob = lenb - PyList_Size(b);
num = todoa > todob ? todoa : todob;
if (num == 0)
break;
Matt Mackall
many, many trivial check-code fixups
r10282 for (i = 0; i < num; i++) {
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 x = PyFile_GetLine(fp, 0);
Renato Cunha
diffhelpers.c: Added support for py3k....
r11363 s = PyBytes_AsString(x);
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 c = *s;
if (strcmp(s, "\\ No newline at end of file\n") == 0) {
_fix_newline(hunk, a, b);
continue;
}
Hollis Blanchard
Handle patches with misformatted empty lines...
r5483 if (c == '\n') {
/* Some patches may be missing the control char
* on empty lines. Supply a leading space. */
Py_DECREF(x);
Renato Cunha
diffhelpers.c: Added support for py3k....
r11363 x = PyBytes_FromString(" \n");
Hollis Blanchard
Handle patches with misformatted empty lines...
r5483 }
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 PyList_Append(hunk, x);
if (c == '+') {
Renato Cunha
diffhelpers.c: Added support for py3k....
r11363 l = PyBytes_FromString(s + 1);
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 PyList_Append(b, l);
Py_DECREF(l);
} else if (c == '-') {
PyList_Append(a, x);
} else {
Renato Cunha
diffhelpers.c: Added support for py3k....
r11363 l = PyBytes_FromString(s + 1);
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 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;
Adrian Buehlmann
diffhelpers: use Py_ssize_t in testhunk()...
r16695 Py_ssize_t alen, blen;
Py_ssize_t i;
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 char *sa, *sb;
if (!PyArg_ParseTuple(args, "OOl", &a, &b, &bstart))
return NULL;
alen = PyList_Size(a);
blen = PyList_Size(b);
Matt Mackall
diffhelpers: harden testhunk
r16651 if (alen > blen - bstart || bstart < 0) {
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 return Py_BuildValue("l", -1);
}
Matt Mackall
many, many trivial check-code fixups
r10282 for (i = 0; i < alen; i++) {
Renato Cunha
diffhelpers.c: Added support for py3k....
r11363 sa = PyBytes_AsString(PyList_GET_ITEM(a, i));
sb = PyBytes_AsString(PyList_GET_ITEM(b, i + bstart));
Matt Mackall
many, many trivial check-code fixups
r10282 if (strcmp(sa + 1, sb) != 0)
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 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}
};
Renato Cunha
diffhelpers.c: Added support for py3k....
r11363 #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);
return m;
}
#else
Bryan O'Sullivan
Add Chris Mason's mpatch library....
r4897 PyMODINIT_FUNC
initdiffhelpers(void)
{
Py_InitModule3("diffhelpers", methods, diffhelpers_doc);
diffhelpers_Error = PyErr_NewException("diffhelpers.diffhelpersError",
NULL, NULL);
}
Renato Cunha
diffhelpers.c: Added support for py3k....
r11363 #endif