##// END OF EJS Templates
dirstate: fix restoration of "merged" state after a remove...
dirstate: fix restoration of "merged" state after a remove Before this change, "merged" file that get removed and re-added later were recorded as "from_p2" instead. This came from 8fe74328f700, a 2014 changeset that start explicitly doing so for reason I have not been able to fully grasp. The graft test mentioned in the description are still happy after this changeset. So this changeset restore what seems to be the intended behavior. Restoring information as it was before the removal. Differential Revision: https://phab.mercurial-scm.org/D11429

File last commit:

r48790:20187530 default
r48803:87b3010c default
Show More
parsers.c
1320 lines | 36.0 KiB | text/x-c | CLexer
Yuya Nishihara
parsers: switch to policy importer...
r32372 /*
parsers.c - efficient content parsing
Raphaël Gomès
contributor: change mentions of mpm to olivia...
r47575 Copyright 2008 Olivia Mackall <olivia@selenic.com> and others
Yuya Nishihara
parsers: switch to policy importer...
r32372
This software may be used and distributed according to the terms of
the GNU General Public License, incorporated herein by reference.
*/
Gregory Szorc
cext: make parsers.c PY_SSIZE_T_CLEAN...
r42235 #define PY_SSIZE_T_CLEAN
Yuya Nishihara
parsers: switch to policy importer...
r32372 #include <Python.h>
#include <ctype.h>
#include <stddef.h>
#include <string.h>
Gregory Szorc
cext: reorder #include...
r34439 #include "bitmanipulation.h"
Yuya Nishihara
cext: factor out header for charencode.c...
r33753 #include "charencode.h"
Yuya Nishihara
parsers: switch to policy importer...
r32372 #include "util.h"
#ifdef IS_PY3K
/* The mapping of Python types is meant to be temporary to get Python
* 3 to compile. We should remove this once Python 3 support is fully
* supported and proper types are used in the extensions themselves. */
#define PyInt_Check PyLong_Check
#define PyInt_FromLong PyLong_FromLong
#define PyInt_FromSsize_t PyLong_FromSsize_t
#define PyInt_AsLong PyLong_AsLong
#endif
Yuya Nishihara
cext: mark constant variables
r32385 static const char *const versionerrortext = "Python minor version mismatch";
Yuya Nishihara
parsers: switch to policy importer...
r32372
dirstate-entry: add a `from_p2` property...
r48303 static const int dirstate_v1_from_p2 = -2;
dirstate-entry: `merged_removed` and `from_p2_removed` properties...
r48305 static const int dirstate_v1_nonnormal = -1;
dirstate-item: add a `set_possibly_dirty` method...
r48466 static const int ambiguous_time = -1;
dirstate-entry: add a `from_p2` property...
r48303
Yuya Nishihara
parsers: switch to policy importer...
r32372 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
{
Py_ssize_t expected_size;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size)) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 return NULL;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372
return _dict_new_presized(expected_size);
}
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_new(PyTypeObject *subtype, PyObject *args,
PyObject *kwds)
Yuya Nishihara
parsers: switch to policy importer...
r32372 {
/* We do all the initialization here and not a tp_init function because
dirstate-item: rename the class to DirstateItem...
r48328 * dirstate_item is immutable. */
dirstateItemObject *t;
dirstate-item: feed more information to `__init__`...
r48706 int wc_tracked;
int p1_tracked;
int p2_tracked;
int merged;
int clean_p1;
int clean_p2;
int possibly_dirty;
PyObject *parentfiledata;
static char *keywords_name[] = {
"wc_tracked", "p1_tracked", "p2_tracked",
"merged", "clean_p1", "clean_p2",
"possibly_dirty", "parentfiledata", NULL,
};
wc_tracked = 0;
p1_tracked = 0;
p2_tracked = 0;
merged = 0;
clean_p1 = 0;
clean_p2 = 0;
possibly_dirty = 0;
parentfiledata = Py_None;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "iiiiiiiO", keywords_name,
&wc_tracked, &p1_tracked, &p2_tracked,
&merged, &clean_p1, &clean_p2,
&possibly_dirty, &parentfiledata
)) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 return NULL;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
dirstate-item: feed more information to `__init__`...
r48706 if (merged && (clean_p1 || clean_p2)) {
PyErr_SetString(PyExc_RuntimeError,
"`merged` argument incompatible with "
"`clean_p1`/`clean_p2`");
return NULL;
}
dirstate-item: rename the class to DirstateItem...
r48328 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (!t) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 return NULL;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
dirstate-item: move the C implementation to the same logic...
r48760
t->flags = 0;
if (wc_tracked) {
t->flags |= dirstate_flag_wc_tracked;
}
if (p1_tracked) {
t->flags |= dirstate_flag_p1_tracked;
}
if (p2_tracked) {
t->flags |= dirstate_flag_p2_tracked;
}
if (possibly_dirty) {
t->flags |= dirstate_flag_possibly_dirty;
}
if (merged) {
t->flags |= dirstate_flag_merged;
}
if (clean_p1) {
t->flags |= dirstate_flag_clean_p1;
}
if (clean_p2) {
t->flags |= dirstate_flag_clean_p2;
}
dirstate-item: feed more information to `__init__`...
r48706 t->mode = 0;
t->size = dirstate_v1_nonnormal;
t->mtime = ambiguous_time;
dirstate-item: move the C implementation to the same logic...
r48760 if (parentfiledata != Py_None) {
dirstate-item: feed more information to `__init__`...
r48706 if (!PyTuple_CheckExact(parentfiledata)) {
PyErr_SetString(
PyExc_TypeError,
"parentfiledata should be a Tuple or None");
return NULL;
}
t->mode =
(int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 0));
t->size =
(int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 1));
t->mtime =
(int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 2));
}
Yuya Nishihara
parsers: switch to policy importer...
r32372 return (PyObject *)t;
}
dirstate-item: rename the class to DirstateItem...
r48328 static void dirstate_item_dealloc(PyObject *o)
Yuya Nishihara
parsers: switch to policy importer...
r32372 {
PyObject_Del(o);
}
dirstate-item: introduce low level C function...
r48759 static inline bool dirstate_item_c_tracked(dirstateItemObject *self)
{
dirstate-item: move the C implementation to the same logic...
r48760 return (self->flags & dirstate_flag_wc_tracked);
dirstate-item: introduce low level C function...
r48759 }
static inline bool dirstate_item_c_added(dirstateItemObject *self)
{
Martin von Zweigbergk
dirstate: make dirstate flags char be unsigned...
r48789 unsigned char mask =
(dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
dirstate_flag_p2_tracked);
unsigned char target = dirstate_flag_wc_tracked;
dirstate-item: move the C implementation to the same logic...
r48760 return (self->flags & mask) == target;
dirstate-item: introduce low level C function...
r48759 }
static inline bool dirstate_item_c_removed(dirstateItemObject *self)
{
dirstate-item: move the C implementation to the same logic...
r48760 if (self->flags & dirstate_flag_wc_tracked) {
return false;
}
return (self->flags &
(dirstate_flag_p1_tracked | dirstate_flag_p2_tracked));
dirstate-item: introduce low level C function...
r48759 }
static inline bool dirstate_item_c_merged(dirstateItemObject *self)
{
dirstate-item: move the C implementation to the same logic...
r48760 return ((self->flags & dirstate_flag_wc_tracked) &&
(self->flags & dirstate_flag_merged));
dirstate-item: introduce low level C function...
r48759 }
static inline bool dirstate_item_c_merged_removed(dirstateItemObject *self)
{
dirstate-item: move the C implementation to the same logic...
r48760 if (!dirstate_item_c_removed(self)) {
return false;
}
return (self->flags & dirstate_flag_merged);
dirstate-item: introduce low level C function...
r48759 }
static inline bool dirstate_item_c_from_p2(dirstateItemObject *self)
{
dirstate-item: move the C implementation to the same logic...
r48760 if (!dirstate_item_c_tracked(self)) {
return false;
}
return (self->flags & dirstate_flag_clean_p2);
dirstate-item: introduce low level C function...
r48759 }
static inline bool dirstate_item_c_from_p2_removed(dirstateItemObject *self)
{
dirstate-item: move the C implementation to the same logic...
r48760 if (!dirstate_item_c_removed(self)) {
return false;
}
return (self->flags & dirstate_flag_clean_p2);
dirstate-item: introduce low level C function...
r48759 }
static inline char dirstate_item_c_v1_state(dirstateItemObject *self)
{
dirstate-item: move the C implementation to the same logic...
r48760 if (self->flags & dirstate_flag_rust_special) {
return ' ';
} else if (dirstate_item_c_removed(self)) {
return 'r';
} else if (dirstate_item_c_merged(self)) {
return 'm';
} else if (dirstate_item_c_added(self)) {
return 'a';
} else {
return 'n';
}
dirstate-item: introduce low level C function...
r48759 }
static inline int dirstate_item_c_v1_mode(dirstateItemObject *self)
{
return self->mode;
}
static inline int dirstate_item_c_v1_size(dirstateItemObject *self)
{
dirstate-item: move the C implementation to the same logic...
r48760 if (self->flags & dirstate_flag_rust_special) {
return self->size;
} else if (dirstate_item_c_merged_removed(self)) {
return dirstate_v1_nonnormal;
} else if (dirstate_item_c_from_p2_removed(self)) {
return dirstate_v1_from_p2;
} else if (dirstate_item_c_removed(self)) {
return 0;
} else if (dirstate_item_c_merged(self)) {
return dirstate_v1_from_p2;
} else if (dirstate_item_c_added(self)) {
return dirstate_v1_nonnormal;
} else if (dirstate_item_c_from_p2(self)) {
return dirstate_v1_from_p2;
} else if (self->flags & dirstate_flag_possibly_dirty) {
return self->size; /* NON NORMAL ? */
} else {
return self->size;
}
dirstate-item: introduce low level C function...
r48759 }
static inline int dirstate_item_c_v1_mtime(dirstateItemObject *self)
{
dirstate-item: move the C implementation to the same logic...
r48760 if (self->flags & dirstate_flag_rust_special) {
return self->mtime;
} else if (dirstate_item_c_removed(self)) {
return 0;
} else if (self->flags & dirstate_flag_possibly_dirty) {
return ambiguous_time;
} else if (dirstate_item_c_merged(self)) {
return ambiguous_time;
} else if (dirstate_item_c_added(self)) {
return ambiguous_time;
} else if (dirstate_item_c_from_p2(self)) {
return ambiguous_time;
} else {
return self->mtime;
}
dirstate-item: introduce low level C function...
r48759 }
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_v1_state(dirstateItemObject *self)
dirstate-entry: introduce dedicated accessors for v1 serialization...
r48298 {
dirstate-item: introduce low level C function...
r48759 char state = dirstate_item_c_v1_state(self);
return PyBytes_FromStringAndSize(&state, 1);
dirstate-entry: introduce dedicated accessors for v1 serialization...
r48298 };
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_v1_mode(dirstateItemObject *self)
dirstate-entry: introduce dedicated accessors for v1 serialization...
r48298 {
dirstate-item: introduce low level C function...
r48759 return PyInt_FromLong(dirstate_item_c_v1_mode(self));
dirstate-entry: introduce dedicated accessors for v1 serialization...
r48298 };
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_v1_size(dirstateItemObject *self)
dirstate-entry: introduce dedicated accessors for v1 serialization...
r48298 {
dirstate-item: introduce low level C function...
r48759 return PyInt_FromLong(dirstate_item_c_v1_size(self));
dirstate-entry: introduce dedicated accessors for v1 serialization...
r48298 };
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_v1_mtime(dirstateItemObject *self)
dirstate-entry: introduce dedicated accessors for v1 serialization...
r48298 {
dirstate-item: introduce low level C function...
r48759 return PyInt_FromLong(dirstate_item_c_v1_mtime(self));
dirstate-entry: introduce dedicated accessors for v1 serialization...
r48298 };
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_need_delay(dirstateItemObject *self,
dirstate-entry: add a `need_delay` method...
r48321 PyObject *value)
{
long now;
if (!pylong_to_long(value, &now)) {
return NULL;
}
dirstate-item: introduce low level C function...
r48759 if (dirstate_item_c_v1_state(self) == 'n' &&
dirstate_item_c_v1_mtime(self) == now) {
dirstate-entry: add a `need_delay` method...
r48321 Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
};
dirstate-item: `dirstate_item_from_v1_data` replaces make_dirstate_item...
r48757 /* This will never change since it's bound to V1
dirstate-item: add a `from_v1_data` constructor...
r48465 */
static inline dirstateItemObject *
dirstate_item_from_v1_data(char state, int mode, int size, int mtime)
{
dirstateItemObject *t =
PyObject_New(dirstateItemObject, &dirstateItemType);
if (!t) {
return NULL;
}
dirstate-item: move the C implementation to the same logic...
r48760
if (state == 'm') {
t->flags =
(dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
dirstate_flag_p2_tracked | dirstate_flag_merged);
t->mode = 0;
t->size = dirstate_v1_from_p2;
t->mtime = ambiguous_time;
} else if (state == 'a') {
t->flags = dirstate_flag_wc_tracked;
t->mode = 0;
t->size = dirstate_v1_nonnormal;
t->mtime = ambiguous_time;
} else if (state == 'r') {
t->mode = 0;
t->size = 0;
t->mtime = 0;
if (size == dirstate_v1_nonnormal) {
t->flags =
(dirstate_flag_p1_tracked |
dirstate_flag_p2_tracked | dirstate_flag_merged);
} else if (size == dirstate_v1_from_p2) {
t->flags =
(dirstate_flag_p2_tracked | dirstate_flag_clean_p2);
} else {
t->flags = dirstate_flag_p1_tracked;
}
} else if (state == 'n') {
if (size == dirstate_v1_from_p2) {
t->flags =
(dirstate_flag_wc_tracked |
dirstate_flag_p2_tracked | dirstate_flag_clean_p2);
t->mode = 0;
t->size = dirstate_v1_from_p2;
t->mtime = ambiguous_time;
} else if (size == dirstate_v1_nonnormal) {
t->flags = (dirstate_flag_wc_tracked |
dirstate_flag_p1_tracked |
dirstate_flag_possibly_dirty);
t->mode = 0;
t->size = dirstate_v1_nonnormal;
t->mtime = ambiguous_time;
} else if (mtime == ambiguous_time) {
t->flags = (dirstate_flag_wc_tracked |
dirstate_flag_p1_tracked |
dirstate_flag_possibly_dirty);
t->mode = mode;
t->size = size;
t->mtime = 0;
} else {
t->flags = (dirstate_flag_wc_tracked |
dirstate_flag_p1_tracked);
t->mode = mode;
t->size = size;
t->mtime = mtime;
}
} else if (state == ' ') {
/* XXX Rust is using this special case, it should be clean up
* later. */
t->flags = dirstate_flag_rust_special;
t->mode = mode;
t->size = size;
t->mtime = mtime;
} else {
PyErr_Format(PyExc_RuntimeError,
"unknown state: `%c` (%d, %d, %d)", state, mode,
size, mtime, NULL);
return NULL;
}
dirstate-item: add a `from_v1_data` constructor...
r48465 return t;
}
/* This will never change since it's bound to V1, unlike `dirstate_item_new` */
static PyObject *dirstate_item_from_v1_meth(PyTypeObject *subtype,
PyObject *args)
{
/* We do all the initialization here and not a tp_init function because
* dirstate_item is immutable. */
char state;
int size, mode, mtime;
if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) {
return NULL;
}
dirstate-item: factor some code in the C implementation...
r48758 return (PyObject *)dirstate_item_from_v1_data(state, mode, size, mtime);
dirstate-item: add a `from_v1_data` constructor...
r48465 };
dirstate-item: add dedicated "legacy" constructor for `addfile` case...
r48716 /* constructor to help legacy API to build a new "added" item
Should eventually be removed */
static PyObject *dirstate_item_new_added(PyTypeObject *subtype)
{
dirstateItemObject *t;
t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
if (!t) {
return NULL;
}
dirstate-item: move the C implementation to the same logic...
r48760 t->flags = dirstate_flag_wc_tracked;
dirstate-item: add dedicated "legacy" constructor for `addfile` case...
r48716 t->mode = 0;
t->size = dirstate_v1_nonnormal;
t->mtime = ambiguous_time;
return (PyObject *)t;
};
/* constructor to help legacy API to build a new "merged" item
Should eventually be removed */
static PyObject *dirstate_item_new_merged(PyTypeObject *subtype)
{
dirstateItemObject *t;
t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
if (!t) {
return NULL;
}
dirstate-item: move the C implementation to the same logic...
r48760 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
dirstate_flag_p2_tracked | dirstate_flag_merged);
dirstate-item: add dedicated "legacy" constructor for `addfile` case...
r48716 t->mode = 0;
t->size = dirstate_v1_from_p2;
t->mtime = ambiguous_time;
return (PyObject *)t;
};
/* constructor to help legacy API to build a new "from_p2" item
Should eventually be removed */
static PyObject *dirstate_item_new_from_p2(PyTypeObject *subtype)
{
/* We do all the initialization here and not a tp_init function because
* dirstate_item is immutable. */
dirstateItemObject *t;
t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
if (!t) {
return NULL;
}
dirstate-item: move the C implementation to the same logic...
r48760 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p2_tracked |
dirstate_flag_clean_p2);
dirstate-item: add dedicated "legacy" constructor for `addfile` case...
r48716 t->mode = 0;
t->size = dirstate_v1_from_p2;
t->mtime = ambiguous_time;
return (PyObject *)t;
};
/* constructor to help legacy API to build a new "possibly" item
Should eventually be removed */
static PyObject *dirstate_item_new_possibly_dirty(PyTypeObject *subtype)
{
/* We do all the initialization here and not a tp_init function because
* dirstate_item is immutable. */
dirstateItemObject *t;
t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
if (!t) {
return NULL;
}
dirstate-item: move the C implementation to the same logic...
r48760 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
dirstate_flag_possibly_dirty);
dirstate-item: add dedicated "legacy" constructor for `addfile` case...
r48716 t->mode = 0;
t->size = dirstate_v1_nonnormal;
t->mtime = ambiguous_time;
return (PyObject *)t;
};
/* constructor to help legacy API to build a new "normal" item
Should eventually be removed */
static PyObject *dirstate_item_new_normal(PyTypeObject *subtype, PyObject *args)
{
/* We do all the initialization here and not a tp_init function because
* dirstate_item is immutable. */
dirstateItemObject *t;
int size, mode, mtime;
if (!PyArg_ParseTuple(args, "iii", &mode, &size, &mtime)) {
return NULL;
}
t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
if (!t) {
return NULL;
}
dirstate-item: move the C implementation to the same logic...
r48760 t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked);
dirstate-item: add dedicated "legacy" constructor for `addfile` case...
r48716 t->mode = mode;
t->size = size;
t->mtime = mtime;
return (PyObject *)t;
};
dirstate-item: add a `set_possibly_dirty` method...
r48466 /* This means the next status call will have to actually check its content
to make sure it is correct. */
static PyObject *dirstate_item_set_possibly_dirty(dirstateItemObject *self)
{
Martin von Zweigbergk
dirstate: fix compilation warnings in `dirstate_item_set_possibly_dirty()`...
r48790 self->flags |= dirstate_flag_possibly_dirty;
Py_RETURN_NONE;
dirstate-item: add a `set_possibly_dirty` method...
r48466 }
dirstate: introduce a `set_clean` method on dirstate's map and items...
r48788 /* See docstring of the python implementation for details */
static PyObject *dirstate_item_set_clean(dirstateItemObject *self,
PyObject *args)
{
int size, mode, mtime;
if (!PyArg_ParseTuple(args, "iii", &mode, &size, &mtime)) {
return NULL;
}
self->flags = dirstate_flag_wc_tracked | dirstate_flag_p1_tracked;
self->mode = mode;
self->size = size;
self->mtime = mtime;
Py_RETURN_NONE;
}
dirstatemap: replace `removefile` by an explicit `entry.set_untracked()`...
r48701 static PyObject *dirstate_item_set_untracked(dirstateItemObject *self)
{
dirstate-item: move the C implementation to the same logic...
r48760 self->flags &= ~dirstate_flag_wc_tracked;
dirstatemap: replace `removefile` by an explicit `entry.set_untracked()`...
r48701 self->mode = 0;
self->mtime = 0;
dirstate-item: move the C implementation to the same logic...
r48760 self->size = 0;
dirstatemap: replace `removefile` by an explicit `entry.set_untracked()`...
r48701 Py_RETURN_NONE;
}
dirstate-item: rename the class to DirstateItem...
r48328 static PyMethodDef dirstate_item_methods[] = {
{"v1_state", (PyCFunction)dirstate_item_v1_state, METH_NOARGS,
dirstate-entry: introduce dedicated accessors for v1 serialization...
r48298 "return a \"state\" suitable for v1 serialization"},
dirstate-item: rename the class to DirstateItem...
r48328 {"v1_mode", (PyCFunction)dirstate_item_v1_mode, METH_NOARGS,
dirstate-entry: introduce dedicated accessors for v1 serialization...
r48298 "return a \"mode\" suitable for v1 serialization"},
dirstate-item: rename the class to DirstateItem...
r48328 {"v1_size", (PyCFunction)dirstate_item_v1_size, METH_NOARGS,
dirstate-entry: introduce dedicated accessors for v1 serialization...
r48298 "return a \"size\" suitable for v1 serialization"},
dirstate-item: rename the class to DirstateItem...
r48328 {"v1_mtime", (PyCFunction)dirstate_item_v1_mtime, METH_NOARGS,
dirstate-entry: introduce dedicated accessors for v1 serialization...
r48298 "return a \"mtime\" suitable for v1 serialization"},
dirstate-item: rename the class to DirstateItem...
r48328 {"need_delay", (PyCFunction)dirstate_item_need_delay, METH_O,
dirstate-entry: add a `need_delay` method...
r48321 "True if the stored mtime would be ambiguous with the current time"},
dirstate-item: fix the declaration of the Cext `from_v1_meth`...
r48703 {"from_v1_data", (PyCFunction)dirstate_item_from_v1_meth,
METH_VARARGS | METH_CLASS, "build a new DirstateItem object from V1 data"},
dirstate-item: add dedicated "legacy" constructor for `addfile` case...
r48716 {"new_added", (PyCFunction)dirstate_item_new_added,
METH_NOARGS | METH_CLASS,
"constructor to help legacy API to build a new \"added\" item"},
{"new_merged", (PyCFunction)dirstate_item_new_merged,
METH_NOARGS | METH_CLASS,
"constructor to help legacy API to build a new \"merged\" item"},
{"new_from_p2", (PyCFunction)dirstate_item_new_from_p2,
METH_NOARGS | METH_CLASS,
"constructor to help legacy API to build a new \"from_p2\" item"},
{"new_possibly_dirty", (PyCFunction)dirstate_item_new_possibly_dirty,
METH_NOARGS | METH_CLASS,
"constructor to help legacy API to build a new \"possibly_dirty\" item"},
{"new_normal", (PyCFunction)dirstate_item_new_normal,
METH_VARARGS | METH_CLASS,
"constructor to help legacy API to build a new \"normal\" item"},
dirstate-item: add a `set_possibly_dirty` method...
r48466 {"set_possibly_dirty", (PyCFunction)dirstate_item_set_possibly_dirty,
METH_NOARGS, "mark a file as \"possibly dirty\""},
dirstate: introduce a `set_clean` method on dirstate's map and items...
r48788 {"set_clean", (PyCFunction)dirstate_item_set_clean, METH_VARARGS,
"mark a file as \"clean\""},
dirstatemap: replace `removefile` by an explicit `entry.set_untracked()`...
r48701 {"set_untracked", (PyCFunction)dirstate_item_set_untracked, METH_NOARGS,
"mark a file as \"untracked\""},
dirstate-entry: introduce dedicated accessors for v1 serialization...
r48298 {NULL} /* Sentinel */
};
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_get_mode(dirstateItemObject *self)
dirstate-entry: add a `mode` property...
r48325 {
dirstate-item: introduce low level C function...
r48759 return PyInt_FromLong(dirstate_item_c_v1_mode(self));
dirstate-entry: add a `mode` property...
r48325 };
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_get_size(dirstateItemObject *self)
dirstate-entry: add a `size` property...
r48326 {
dirstate-item: introduce low level C function...
r48759 return PyInt_FromLong(dirstate_item_c_v1_size(self));
dirstate-entry: add a `size` property...
r48326 };
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_get_mtime(dirstateItemObject *self)
dirstate-entry: add a `mtime` property...
r48327 {
dirstate-item: introduce low level C function...
r48759 return PyInt_FromLong(dirstate_item_c_v1_mtime(self));
dirstate-entry: add a `mtime` property...
r48327 };
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_get_state(dirstateItemObject *self)
dirstate-entry: add a `state` property (and use it)...
r48301 {
dirstate-item: introduce low level C function...
r48759 char state = dirstate_item_c_v1_state(self);
return PyBytes_FromStringAndSize(&state, 1);
dirstate-entry: add a `state` property (and use it)...
r48301 };
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_get_tracked(dirstateItemObject *self)
dirstate-entry: add a `tracked` property...
r48320 {
dirstate-item: introduce low level C function...
r48759 if (dirstate_item_c_tracked(self)) {
dirstate-entry: add a `tracked` property...
r48320 Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
};
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_get_added(dirstateItemObject *self)
dirstate-entry: add a `added` property...
r48315 {
dirstate-item: introduce low level C function...
r48759 if (dirstate_item_c_added(self)) {
dirstate-entry: add a `added` property...
r48315 Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
};
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_get_merged(dirstateItemObject *self)
dirstate-entry: add a `merged` property...
r48302 {
dirstate-item: introduce low level C function...
r48759 if (dirstate_item_c_merged(self)) {
dirstate-entry: add a `merged` property...
r48302 Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
};
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_get_merged_removed(dirstateItemObject *self)
dirstate-entry: `merged_removed` and `from_p2_removed` properties...
r48305 {
dirstate-item: introduce low level C function...
r48759 if (dirstate_item_c_merged_removed(self)) {
dirstate-entry: `merged_removed` and `from_p2_removed` properties...
r48305 Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
};
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_get_from_p2(dirstateItemObject *self)
dirstate-entry: add a `from_p2` property...
r48303 {
dirstate-item: introduce low level C function...
r48759 if (dirstate_item_c_from_p2(self)) {
dirstate-entry: add a `from_p2` property...
r48303 Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
};
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_get_from_p2_removed(dirstateItemObject *self)
dirstate-entry: `merged_removed` and `from_p2_removed` properties...
r48305 {
dirstate-item: introduce low level C function...
r48759 if (dirstate_item_c_from_p2_removed(self)) {
dirstate-entry: `merged_removed` and `from_p2_removed` properties...
r48305 Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
};
dirstate-item: rename the class to DirstateItem...
r48328 static PyObject *dirstate_item_get_removed(dirstateItemObject *self)
dirstate-entry: add a `removed` property...
r48304 {
dirstate-item: introduce low level C function...
r48759 if (dirstate_item_c_removed(self)) {
dirstate-entry: add a `removed` property...
r48304 Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
};
dirstate-item: fix Cext declaration of dm_nonnormal and dm_otherparent...
r48702 static PyObject *dm_nonnormal(dirstateItemObject *self)
{
dirstate-item: introduce low level C function...
r48759 if ((dirstate_item_c_v1_state(self) != 'n') ||
(dirstate_item_c_v1_mtime(self) == ambiguous_time)) {
dirstate-item: fix Cext declaration of dm_nonnormal and dm_otherparent...
r48702 Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
};
static PyObject *dm_otherparent(dirstateItemObject *self)
{
dirstate-item: introduce low level C function...
r48759 if (dirstate_item_c_v1_mtime(self) == dirstate_v1_from_p2) {
dirstate-item: fix Cext declaration of dm_nonnormal and dm_otherparent...
r48702 Py_RETURN_TRUE;
} else {
Py_RETURN_FALSE;
}
};
dirstate-item: rename the class to DirstateItem...
r48328 static PyGetSetDef dirstate_item_getset[] = {
{"mode", (getter)dirstate_item_get_mode, NULL, "mode", NULL},
{"size", (getter)dirstate_item_get_size, NULL, "size", NULL},
{"mtime", (getter)dirstate_item_get_mtime, NULL, "mtime", NULL},
{"state", (getter)dirstate_item_get_state, NULL, "state", NULL},
{"tracked", (getter)dirstate_item_get_tracked, NULL, "tracked", NULL},
{"added", (getter)dirstate_item_get_added, NULL, "added", NULL},
{"merged_removed", (getter)dirstate_item_get_merged_removed, NULL,
dirstate-entry: `merged_removed` and `from_p2_removed` properties...
r48305 "merged_removed", NULL},
dirstate-item: rename the class to DirstateItem...
r48328 {"merged", (getter)dirstate_item_get_merged, NULL, "merged", NULL},
{"from_p2_removed", (getter)dirstate_item_get_from_p2_removed, NULL,
dirstate-entry: `merged_removed` and `from_p2_removed` properties...
r48305 "from_p2_removed", NULL},
dirstate-item: rename the class to DirstateItem...
r48328 {"from_p2", (getter)dirstate_item_get_from_p2, NULL, "from_p2", NULL},
{"removed", (getter)dirstate_item_get_removed, NULL, "removed", NULL},
dirstate-item: fix Cext declaration of dm_nonnormal and dm_otherparent...
r48702 {"dm_nonnormal", (getter)dm_nonnormal, NULL, "dm_nonnormal", NULL},
{"dm_otherparent", (getter)dm_otherparent, NULL, "dm_otherparent", NULL},
dirstate-entry: add a `state` property (and use it)...
r48301 {NULL} /* Sentinel */
};
dirstate-item: rename the class to DirstateItem...
r48328 PyTypeObject dirstateItemType = {
PyVarObject_HEAD_INIT(NULL, 0) /* header */
"dirstate_tuple", /* tp_name */
sizeof(dirstateItemObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)dirstate_item_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
dirstate-item: drop the deprecated __getitem__ variante...
r48737 0, /* tp_as_sequence */
dirstate-item: rename the class to DirstateItem...
r48328 0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"dirstate tuple", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
dirstate_item_methods, /* tp_methods */
0, /* tp_members */
dirstate_item_getset, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
dirstate_item_new, /* tp_new */
Yuya Nishihara
parsers: switch to policy importer...
r32372 };
static PyObject *parse_dirstate(PyObject *self, PyObject *args)
{
PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
PyObject *fname = NULL, *cname = NULL, *entry = NULL;
char state, *cur, *str, *cpos;
int mode, size, mtime;
Gregory Szorc
cext: make parsers.c PY_SSIZE_T_CLEAN...
r42235 unsigned int flen, pos = 40;
Py_ssize_t len = 40;
Py_ssize_t readlen;
Yuya Nishihara
parsers: switch to policy importer...
r32372
Yuya Nishihara
py3: bulk-replace 'const char*' format specifier passed to PyArg_ParseTuple*()...
r36638 if (!PyArg_ParseTuple(
args, PY23("O!O!s#:parse_dirstate", "O!O!y#:parse_dirstate"),
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 &PyDict_Type, &dmap, &PyDict_Type, &cmap, &str, &readlen)) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto quit;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372
len = readlen;
/* read parents */
if (len < 40) {
Augie Fackler
parsers: allow clang-format here...
r34863 PyErr_SetString(PyExc_ValueError,
"too little data for parents");
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto quit;
}
Yuya Nishihara
cext: cast s# arguments of Py_BuildValue() to Py_ssize_t...
r42265 parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, (Py_ssize_t)20,
str + 20, (Py_ssize_t)20);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (!parents) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto quit;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372
/* read filenames */
while (pos >= 40 && pos < len) {
if (pos + 17 > len) {
PyErr_SetString(PyExc_ValueError,
Augie Fackler
parsers: allow clang-format here...
r34863 "overflow in dirstate");
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto quit;
}
cur = str + pos;
/* unpack header */
state = *cur;
mode = getbe32(cur + 1);
size = getbe32(cur + 5);
mtime = getbe32(cur + 9);
flen = getbe32(cur + 13);
pos += 17;
cur += 17;
if (flen > len - pos) {
Augie Fackler
parsers: allow clang-format here...
r34863 PyErr_SetString(PyExc_ValueError,
"overflow in dirstate");
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto quit;
}
dirstate-item: add a `from_v1_data` constructor...
r48465 entry = (PyObject *)dirstate_item_from_v1_data(state, mode,
size, mtime);
Yuya Nishihara
parsers: switch to policy importer...
r32372 cpos = memchr(cur, 0, flen);
if (cpos) {
fname = PyBytes_FromStringAndSize(cur, cpos - cur);
Augie Fackler
parsers: allow clang-format here...
r34863 cname = PyBytes_FromStringAndSize(
cpos + 1, flen - (cpos - cur) - 1);
Yuya Nishihara
parsers: switch to policy importer...
r32372 if (!fname || !cname ||
PyDict_SetItem(cmap, fname, cname) == -1 ||
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 PyDict_SetItem(dmap, fname, entry) == -1) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto quit;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372 Py_DECREF(cname);
} else {
fname = PyBytes_FromStringAndSize(cur, flen);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (!fname ||
PyDict_SetItem(dmap, fname, entry) == -1) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto quit;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372 }
Py_DECREF(fname);
Py_DECREF(entry);
fname = cname = entry = NULL;
pos += flen;
}
ret = parents;
Py_INCREF(ret);
quit:
Py_XDECREF(fname);
Py_XDECREF(cname);
Py_XDECREF(entry);
Py_XDECREF(parents);
return ret;
}
/*
* Build a set of non-normal and other parent entries from the dirstate dmap
Augie Fackler
parsers: allow clang-format here...
r34863 */
Gregory Szorc
cext: wrap before brace for functions...
r34441 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
{
Yuya Nishihara
parsers: switch to policy importer...
r32372 PyObject *dmap, *fname, *v;
PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
Py_ssize_t pos;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type,
&dmap)) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto bail;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372
nonnset = PySet_New(NULL);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (nonnset == NULL) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto bail;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372
otherpset = PySet_New(NULL);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (otherpset == NULL) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto bail;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372
pos = 0;
while (PyDict_Next(dmap, &pos, &fname, &v)) {
dirstate-item: rename the class to DirstateItem...
r48328 dirstateItemObject *t;
Yuya Nishihara
parsers: switch to policy importer...
r32372 if (!dirstate_tuple_check(v)) {
PyErr_SetString(PyExc_TypeError,
Augie Fackler
parsers: allow clang-format here...
r34863 "expected a dirstate tuple");
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto bail;
}
dirstate-item: rename the class to DirstateItem...
r48328 t = (dirstateItemObject *)v;
Yuya Nishihara
parsers: switch to policy importer...
r32372
dirstate-item: move the C implementation to the same logic...
r48760 if (dirstate_item_c_from_p2(t)) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 if (PySet_Add(otherpset, fname) == -1) {
goto bail;
}
}
dirstate-item: move the C implementation to the same logic...
r48760 if (!(t->flags & dirstate_flag_wc_tracked) ||
!(t->flags &
(dirstate_flag_p1_tracked | dirstate_flag_p2_tracked)) ||
(t->flags &
(dirstate_flag_possibly_dirty | dirstate_flag_merged))) {
if (PySet_Add(nonnset, fname) == -1) {
goto bail;
}
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372 }
result = Py_BuildValue("(OO)", nonnset, otherpset);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (result == NULL) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto bail;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372 Py_DECREF(nonnset);
Py_DECREF(otherpset);
return result;
bail:
Py_XDECREF(nonnset);
Py_XDECREF(otherpset);
Py_XDECREF(result);
return NULL;
}
/*
* Efficiently pack a dirstate object into its on-disk format.
*/
static PyObject *pack_dirstate(PyObject *self, PyObject *args)
{
PyObject *packobj = NULL;
PyObject *map, *copymap, *pl, *mtime_unset = NULL;
Py_ssize_t nbytes, pos, l;
PyObject *k, *v = NULL, *pn;
char *p, *s;
int now;
Yuya Nishihara
dirstate: use tuple interface to fix leak in pack_dirstate()...
r39485 if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map,
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 &PyDict_Type, &copymap, &PyTuple_Type, &pl,
&now)) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 return NULL;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372
Yuya Nishihara
dirstate: use tuple interface to fix leak in pack_dirstate()...
r39485 if (PyTuple_Size(pl) != 2) {
PyErr_SetString(PyExc_TypeError, "expected 2-element tuple");
Yuya Nishihara
parsers: switch to policy importer...
r32372 return NULL;
}
/* Figure out how much we need to allocate. */
for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
PyObject *c;
if (!PyBytes_Check(k)) {
PyErr_SetString(PyExc_TypeError, "expected string key");
goto bail;
}
nbytes += PyBytes_GET_SIZE(k) + 17;
c = PyDict_GetItem(copymap, k);
if (c) {
if (!PyBytes_Check(c)) {
PyErr_SetString(PyExc_TypeError,
Augie Fackler
parsers: allow clang-format here...
r34863 "expected string key");
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto bail;
}
nbytes += PyBytes_GET_SIZE(c) + 1;
}
}
packobj = PyBytes_FromStringAndSize(NULL, nbytes);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (packobj == NULL) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto bail;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372
p = PyBytes_AS_STRING(packobj);
Yuya Nishihara
dirstate: use tuple interface to fix leak in pack_dirstate()...
r39485 pn = PyTuple_GET_ITEM(pl, 0);
Yuya Nishihara
parsers: switch to policy importer...
r32372 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
goto bail;
}
memcpy(p, s, l);
p += 20;
Yuya Nishihara
dirstate: use tuple interface to fix leak in pack_dirstate()...
r39485 pn = PyTuple_GET_ITEM(pl, 1);
Yuya Nishihara
parsers: switch to policy importer...
r32372 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
goto bail;
}
memcpy(p, s, l);
p += 20;
Augie Fackler
parsers: allow clang-format here...
r34863 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
dirstate-item: rename the class to DirstateItem...
r48328 dirstateItemObject *tuple;
Yuya Nishihara
parsers: switch to policy importer...
r32372 char state;
int mode, size, mtime;
Py_ssize_t len, l;
PyObject *o;
char *t;
if (!dirstate_tuple_check(v)) {
PyErr_SetString(PyExc_TypeError,
Augie Fackler
parsers: allow clang-format here...
r34863 "expected a dirstate tuple");
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto bail;
}
dirstate-item: rename the class to DirstateItem...
r48328 tuple = (dirstateItemObject *)v;
Yuya Nishihara
parsers: switch to policy importer...
r32372
dirstate-item: move the C implementation to the same logic...
r48760 state = dirstate_item_c_v1_state(tuple);
mode = dirstate_item_c_v1_mode(tuple);
size = dirstate_item_c_v1_size(tuple);
mtime = dirstate_item_c_v1_mtime(tuple);
Yuya Nishihara
parsers: switch to policy importer...
r32372 if (state == 'n' && mtime == now) {
/* See pure/parsers.py:pack_dirstate for why we do
* this. */
mtime = -1;
dirstate-item: `dirstate_item_from_v1_data` replaces make_dirstate_item...
r48757 mtime_unset = (PyObject *)dirstate_item_from_v1_data(
Augie Fackler
parsers: allow clang-format here...
r34863 state, mode, size, mtime);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (!mtime_unset) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto bail;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
if (PyDict_SetItem(map, k, mtime_unset) == -1) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto bail;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372 Py_DECREF(mtime_unset);
mtime_unset = NULL;
}
*p++ = state;
putbe32((uint32_t)mode, p);
putbe32((uint32_t)size, p + 4);
putbe32((uint32_t)mtime, p + 8);
t = p + 12;
p += 16;
len = PyBytes_GET_SIZE(k);
memcpy(p, PyBytes_AS_STRING(k), len);
p += len;
o = PyDict_GetItem(copymap, k);
if (o) {
*p++ = '\0';
l = PyBytes_GET_SIZE(o);
memcpy(p, PyBytes_AS_STRING(o), l);
p += l;
len += l + 1;
}
putbe32((uint32_t)len, t);
}
pos = p - PyBytes_AS_STRING(packobj);
if (pos != nbytes) {
PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
Augie Fackler
parsers: allow clang-format here...
r34863 (long)pos, (long)nbytes);
Yuya Nishihara
parsers: switch to policy importer...
r32372 goto bail;
}
return packobj;
bail:
Py_XDECREF(mtime_unset);
Py_XDECREF(packobj);
Py_XDECREF(v);
return NULL;
}
#define BUMPED_FIX 1
#define USING_SHA_256 2
#define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
Augie Fackler
parsers: allow clang-format here...
r34863 static PyObject *readshas(const char *source, unsigned char num,
Py_ssize_t hashwidth)
Yuya Nishihara
parsers: switch to policy importer...
r32372 {
int i;
PyObject *list = PyTuple_New(num);
if (list == NULL) {
return NULL;
}
for (i = 0; i < num; i++) {
PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
if (hash == NULL) {
Py_DECREF(list);
return NULL;
}
PyTuple_SET_ITEM(list, i, hash);
source += hashwidth;
}
return list;
}
static PyObject *fm1readmarker(const char *databegin, const char *dataend,
Augie Fackler
parsers: allow clang-format here...
r34863 uint32_t *msize)
Yuya Nishihara
parsers: switch to policy importer...
r32372 {
const char *data = databegin;
const char *meta;
double mtime;
int16_t tz;
uint16_t flags;
unsigned char nsuccs, nparents, nmetadata;
Py_ssize_t hashwidth = 20;
PyObject *prec = NULL, *parents = NULL, *succs = NULL;
PyObject *metadata = NULL, *ret = NULL;
int i;
if (data + FM1_HEADER_SIZE > dataend) {
goto overflow;
}
*msize = getbe32(data);
data += 4;
mtime = getbefloat64(data);
data += 8;
tz = getbeint16(data);
data += 2;
flags = getbeuint16(data);
data += 2;
if (flags & USING_SHA_256) {
hashwidth = 32;
}
nsuccs = (unsigned char)(*data++);
nparents = (unsigned char)(*data++);
nmetadata = (unsigned char)(*data++);
if (databegin + *msize > dataend) {
goto overflow;
}
Augie Fackler
parsers: allow clang-format here...
r34863 dataend = databegin + *msize; /* narrow down to marker size */
Yuya Nishihara
parsers: switch to policy importer...
r32372
if (data + hashwidth > dataend) {
goto overflow;
}
prec = PyBytes_FromStringAndSize(data, hashwidth);
data += hashwidth;
if (prec == NULL) {
goto bail;
}
if (data + nsuccs * hashwidth > dataend) {
goto overflow;
}
succs = readshas(data, nsuccs, hashwidth);
if (succs == NULL) {
goto bail;
}
data += nsuccs * hashwidth;
if (nparents == 1 || nparents == 2) {
if (data + nparents * hashwidth > dataend) {
goto overflow;
}
parents = readshas(data, nparents, hashwidth);
if (parents == NULL) {
goto bail;
}
data += nparents * hashwidth;
} else {
parents = Py_None;
Py_INCREF(parents);
}
if (data + 2 * nmetadata > dataend) {
goto overflow;
}
meta = data + (2 * nmetadata);
metadata = PyTuple_New(nmetadata);
if (metadata == NULL) {
goto bail;
}
for (i = 0; i < nmetadata; i++) {
PyObject *tmp, *left = NULL, *right = NULL;
Py_ssize_t leftsize = (unsigned char)(*data++);
Py_ssize_t rightsize = (unsigned char)(*data++);
if (meta + leftsize + rightsize > dataend) {
goto overflow;
}
left = PyBytes_FromStringAndSize(meta, leftsize);
meta += leftsize;
right = PyBytes_FromStringAndSize(meta, rightsize);
meta += rightsize;
tmp = PyTuple_New(2);
if (!left || !right || !tmp) {
Py_XDECREF(left);
Py_XDECREF(right);
Py_XDECREF(tmp);
goto bail;
}
PyTuple_SET_ITEM(tmp, 0, left);
PyTuple_SET_ITEM(tmp, 1, right);
PyTuple_SET_ITEM(metadata, i, tmp);
}
Augie Fackler
parsers: allow clang-format here...
r34863 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
(int)tz * 60, parents);
goto bail; /* return successfully */
Yuya Nishihara
parsers: switch to policy importer...
r32372
overflow:
PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
bail:
Py_XDECREF(prec);
Py_XDECREF(succs);
Py_XDECREF(metadata);
Py_XDECREF(parents);
return ret;
}
Gregory Szorc
cext: wrap before brace for functions...
r34441 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
{
Yuya Nishihara
parsers: switch to policy importer...
r32372 const char *data, *dataend;
Gregory Szorc
cext: make parsers.c PY_SSIZE_T_CLEAN...
r42235 Py_ssize_t datalen, offset, stop;
Yuya Nishihara
parsers: switch to policy importer...
r32372 PyObject *markers = NULL;
Yuya Nishihara
py3: bulk-replace 'const char*' format specifier passed to PyArg_ParseTuple*()...
r36638 if (!PyArg_ParseTuple(args, PY23("s#nn", "y#nn"), &data, &datalen,
&offset, &stop)) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 return NULL;
}
Augie Fackler
parsers: better bounds checking in fm1readmarkers...
r41052 if (offset < 0) {
PyErr_SetString(PyExc_ValueError,
"invalid negative offset in fm1readmarkers");
return NULL;
}
if (stop > datalen) {
PyErr_SetString(
PyExc_ValueError,
"stop longer than data length in fm1readmarkers");
return NULL;
}
Yuya Nishihara
parsers: switch to policy importer...
r32372 dataend = data + datalen;
data += offset;
markers = PyList_New(0);
if (!markers) {
return NULL;
}
while (offset < stop) {
uint32_t msize;
int error;
PyObject *record = fm1readmarker(data, dataend, &msize);
if (!record) {
goto bail;
}
error = PyList_Append(markers, record);
Py_DECREF(record);
if (error) {
goto bail;
}
data += msize;
offset += msize;
}
return markers;
bail:
Py_DECREF(markers);
return NULL;
}
static char parsers_doc[] = "Efficient content parsing.";
PyObject *encodedir(PyObject *self, PyObject *args);
PyObject *pathencode(PyObject *self, PyObject *args);
PyObject *lowerencode(PyObject *self, PyObject *args);
Raphaël Gomès
cext: add support for revlogv2...
r47442 PyObject *parse_index2(PyObject *self, PyObject *args, PyObject *kwargs);
Yuya Nishihara
parsers: switch to policy importer...
r32372
static PyMethodDef methods[] = {
Augie Fackler
parsers: allow clang-format here...
r34863 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
{"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
"create a set containing non-normal and other parent entries of given "
"dirstate\n"},
{"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
Raphaël Gomès
cext: add support for revlogv2...
r47442 {"parse_index2", (PyCFunction)parse_index2, METH_VARARGS | METH_KEYWORDS,
"parse a revlog index\n"},
Augie Fackler
parsers: allow clang-format here...
r34863 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
{"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
{"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
{"dict_new_presized", dict_new_presized, METH_VARARGS,
"construct a dict with an expected size\n"},
{"make_file_foldmap", make_file_foldmap, METH_VARARGS,
"make file foldmap\n"},
{"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
"escape a UTF-8 byte string to JSON (fast path)\n"},
{"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
{"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
{"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
{"fm1readmarkers", fm1readmarkers, METH_VARARGS,
"parse v1 obsolete markers\n"},
{NULL, NULL}};
Yuya Nishihara
parsers: switch to policy importer...
r32372
void dirs_module_init(PyObject *mod);
void manifest_module_init(PyObject *mod);
Gregory Szorc
cext: extract revlog/index parsing code to own C file...
r32378 void revlog_module_init(PyObject *mod);
Yuya Nishihara
parsers: switch to policy importer...
r32372
revlog: signal which revlog index are compatible with Rust...
r48042 static const int version = 20;
Yuya Nishihara
parsers: switch to policy importer...
r32372
static void module_init(PyObject *mod)
{
Raphaël Gomès
rust-dirstate: add rust-cpython bindings to the new parse/pack functions...
r42489 PyObject *capsule = NULL;
Yuya Nishihara
parsers: switch to policy importer...
r32372 PyModule_AddIntConstant(mod, "version", version);
/* This module constant has two purposes. First, it lets us unit test
* the ImportError raised without hard-coding any error text. This
* means we can change the text in the future without breaking tests,
* even across changesets without a recompile. Second, its presence
* can be used to determine whether the version-checking logic is
* present, which also helps in testing across changesets without a
* recompile. Note that this means the pure-Python version of parsers
* should not have this module constant. */
PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
dirs_module_init(mod);
manifest_module_init(mod);
Gregory Szorc
cext: extract revlog/index parsing code to own C file...
r32378 revlog_module_init(mod);
Yuya Nishihara
parsers: switch to policy importer...
r32372
Raphaël Gomès
rust-dirstate: add rust-cpython bindings to the new parse/pack functions...
r42489 capsule = PyCapsule_New(
dirstate-item: `dirstate_item_from_v1_data` replaces make_dirstate_item...
r48757 dirstate_item_from_v1_data,
dirstate-item: rename the class to DirstateItem...
r48328 "mercurial.cext.parsers.make_dirstate_item_CAPI", NULL);
Raphaël Gomès
rust-dirstate: add rust-cpython bindings to the new parse/pack functions...
r42489 if (capsule != NULL)
dirstate-item: rename the class to DirstateItem...
r48328 PyModule_AddObject(mod, "make_dirstate_item_CAPI", capsule);
Raphaël Gomès
rust-dirstate: add rust-cpython bindings to the new parse/pack functions...
r42489
dirstate-item: rename the class to DirstateItem...
r48328 if (PyType_Ready(&dirstateItemType) < 0) {
Yuya Nishihara
cext: move back finalization of dirstateTupleType where it should be
r32383 return;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
dirstate-item: rename the class to DirstateItem...
r48328 Py_INCREF(&dirstateItemType);
PyModule_AddObject(mod, "DirstateItem", (PyObject *)&dirstateItemType);
Yuya Nishihara
parsers: switch to policy importer...
r32372 }
static int check_python_version(void)
{
PyObject *sys = PyImport_ImportModule("sys"), *ver;
long hexversion;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (!sys) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 return -1;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372 ver = PyObject_GetAttrString(sys, "hexversion");
Py_DECREF(sys);
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (!ver) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 return -1;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372 hexversion = PyInt_AsLong(ver);
Py_DECREF(ver);
/* sys.hexversion is a 32-bit number by default, so the -1 case
* should only occur in unusual circumstances (e.g. if sys.hexversion
* is manually set to an invalid value). */
if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
Augie Fackler
parsers: allow clang-format here...
r34863 PyErr_Format(PyExc_ImportError,
"%s: The Mercurial extension "
"modules were compiled with Python " PY_VERSION
", but "
"Mercurial is currently using Python with "
"sys.hexversion=%ld: "
"Python %s\n at: %s",
versionerrortext, hexversion, Py_GetVersion(),
Py_GetProgramFullPath());
Yuya Nishihara
parsers: switch to policy importer...
r32372 return -1;
}
return 0;
}
#ifdef IS_PY3K
Augie Fackler
parsers: allow clang-format here...
r34863 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
parsers_doc, -1, methods};
Yuya Nishihara
parsers: switch to policy importer...
r32372
PyMODINIT_FUNC PyInit_parsers(void)
{
PyObject *mod;
if (check_python_version() == -1)
return NULL;
mod = PyModule_Create(&parsers_module);
module_init(mod);
return mod;
}
#else
PyMODINIT_FUNC initparsers(void)
{
PyObject *mod;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 if (check_python_version() == -1) {
Yuya Nishihara
parsers: switch to policy importer...
r32372 return;
Augie Fackler
cleanup: use clang-tidy to add missing {} around one-line statements...
r41367 }
Yuya Nishihara
parsers: switch to policy importer...
r32372 mod = Py_InitModule3("parsers", methods, parsers_doc);
module_init(mod);
}
#endif