##// END OF EJS Templates
dirstate-item: factor some code in the C implementation...
marmoute -
r48758:0919d66e default
parent child Browse files
Show More
@@ -1,1145 +1,1134 b''
1 /*
1 /*
2 parsers.c - efficient content parsing
2 parsers.c - efficient content parsing
3
3
4 Copyright 2008 Olivia Mackall <olivia@selenic.com> and others
4 Copyright 2008 Olivia Mackall <olivia@selenic.com> and others
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
7 the GNU General Public License, incorporated herein by reference.
8 */
8 */
9
9
10 #define PY_SSIZE_T_CLEAN
10 #define PY_SSIZE_T_CLEAN
11 #include <Python.h>
11 #include <Python.h>
12 #include <ctype.h>
12 #include <ctype.h>
13 #include <stddef.h>
13 #include <stddef.h>
14 #include <string.h>
14 #include <string.h>
15
15
16 #include "bitmanipulation.h"
16 #include "bitmanipulation.h"
17 #include "charencode.h"
17 #include "charencode.h"
18 #include "util.h"
18 #include "util.h"
19
19
20 #ifdef IS_PY3K
20 #ifdef IS_PY3K
21 /* The mapping of Python types is meant to be temporary to get Python
21 /* The mapping of Python types is meant to be temporary to get Python
22 * 3 to compile. We should remove this once Python 3 support is fully
22 * 3 to compile. We should remove this once Python 3 support is fully
23 * supported and proper types are used in the extensions themselves. */
23 * supported and proper types are used in the extensions themselves. */
24 #define PyInt_Check PyLong_Check
24 #define PyInt_Check PyLong_Check
25 #define PyInt_FromLong PyLong_FromLong
25 #define PyInt_FromLong PyLong_FromLong
26 #define PyInt_FromSsize_t PyLong_FromSsize_t
26 #define PyInt_FromSsize_t PyLong_FromSsize_t
27 #define PyInt_AsLong PyLong_AsLong
27 #define PyInt_AsLong PyLong_AsLong
28 #endif
28 #endif
29
29
30 static const char *const versionerrortext = "Python minor version mismatch";
30 static const char *const versionerrortext = "Python minor version mismatch";
31
31
32 static const int dirstate_v1_from_p2 = -2;
32 static const int dirstate_v1_from_p2 = -2;
33 static const int dirstate_v1_nonnormal = -1;
33 static const int dirstate_v1_nonnormal = -1;
34 static const int ambiguous_time = -1;
34 static const int ambiguous_time = -1;
35
35
36 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
36 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
37 {
37 {
38 Py_ssize_t expected_size;
38 Py_ssize_t expected_size;
39
39
40 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size)) {
40 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size)) {
41 return NULL;
41 return NULL;
42 }
42 }
43
43
44 return _dict_new_presized(expected_size);
44 return _dict_new_presized(expected_size);
45 }
45 }
46
46
47 static PyObject *dirstate_item_new(PyTypeObject *subtype, PyObject *args,
47 static PyObject *dirstate_item_new(PyTypeObject *subtype, PyObject *args,
48 PyObject *kwds)
48 PyObject *kwds)
49 {
49 {
50 /* We do all the initialization here and not a tp_init function because
50 /* We do all the initialization here and not a tp_init function because
51 * dirstate_item is immutable. */
51 * dirstate_item is immutable. */
52 dirstateItemObject *t;
52 dirstateItemObject *t;
53 int wc_tracked;
53 int wc_tracked;
54 int p1_tracked;
54 int p1_tracked;
55 int p2_tracked;
55 int p2_tracked;
56 int merged;
56 int merged;
57 int clean_p1;
57 int clean_p1;
58 int clean_p2;
58 int clean_p2;
59 int possibly_dirty;
59 int possibly_dirty;
60 PyObject *parentfiledata;
60 PyObject *parentfiledata;
61 static char *keywords_name[] = {
61 static char *keywords_name[] = {
62 "wc_tracked", "p1_tracked", "p2_tracked",
62 "wc_tracked", "p1_tracked", "p2_tracked",
63 "merged", "clean_p1", "clean_p2",
63 "merged", "clean_p1", "clean_p2",
64 "possibly_dirty", "parentfiledata", NULL,
64 "possibly_dirty", "parentfiledata", NULL,
65 };
65 };
66 wc_tracked = 0;
66 wc_tracked = 0;
67 p1_tracked = 0;
67 p1_tracked = 0;
68 p2_tracked = 0;
68 p2_tracked = 0;
69 merged = 0;
69 merged = 0;
70 clean_p1 = 0;
70 clean_p1 = 0;
71 clean_p2 = 0;
71 clean_p2 = 0;
72 possibly_dirty = 0;
72 possibly_dirty = 0;
73 parentfiledata = Py_None;
73 parentfiledata = Py_None;
74 if (!PyArg_ParseTupleAndKeywords(args, kwds, "iiiiiiiO", keywords_name,
74 if (!PyArg_ParseTupleAndKeywords(args, kwds, "iiiiiiiO", keywords_name,
75 &wc_tracked, &p1_tracked, &p2_tracked,
75 &wc_tracked, &p1_tracked, &p2_tracked,
76 &merged, &clean_p1, &clean_p2,
76 &merged, &clean_p1, &clean_p2,
77 &possibly_dirty, &parentfiledata
77 &possibly_dirty, &parentfiledata
78
78
79 )) {
79 )) {
80 return NULL;
80 return NULL;
81 }
81 }
82 if (merged && (clean_p1 || clean_p2)) {
82 if (merged && (clean_p1 || clean_p2)) {
83 PyErr_SetString(PyExc_RuntimeError,
83 PyErr_SetString(PyExc_RuntimeError,
84 "`merged` argument incompatible with "
84 "`merged` argument incompatible with "
85 "`clean_p1`/`clean_p2`");
85 "`clean_p1`/`clean_p2`");
86 return NULL;
86 return NULL;
87 }
87 }
88 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
88 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
89 if (!t) {
89 if (!t) {
90 return NULL;
90 return NULL;
91 }
91 }
92 t->state = 'r';
92 t->state = 'r';
93 t->mode = 0;
93 t->mode = 0;
94 t->size = dirstate_v1_nonnormal;
94 t->size = dirstate_v1_nonnormal;
95 t->mtime = ambiguous_time;
95 t->mtime = ambiguous_time;
96 if (!(p1_tracked || p2_tracked || wc_tracked)) {
96 if (!(p1_tracked || p2_tracked || wc_tracked)) {
97 /* Nothing special to do, file is untracked */
97 /* Nothing special to do, file is untracked */
98 } else if (merged) {
98 } else if (merged) {
99 t->state = 'm';
99 t->state = 'm';
100 t->size = dirstate_v1_from_p2;
100 t->size = dirstate_v1_from_p2;
101 t->mtime = ambiguous_time;
101 t->mtime = ambiguous_time;
102 } else if (!(p1_tracked || p2_tracked) && wc_tracked) {
102 } else if (!(p1_tracked || p2_tracked) && wc_tracked) {
103 t->state = 'a';
103 t->state = 'a';
104 t->size = dirstate_v1_nonnormal;
104 t->size = dirstate_v1_nonnormal;
105 t->mtime = ambiguous_time;
105 t->mtime = ambiguous_time;
106 } else if ((p1_tracked || p2_tracked) && !wc_tracked) {
106 } else if ((p1_tracked || p2_tracked) && !wc_tracked) {
107 t->state = 'r';
107 t->state = 'r';
108 t->size = 0;
108 t->size = 0;
109 t->mtime = 0;
109 t->mtime = 0;
110 } else if (clean_p2 && wc_tracked) {
110 } else if (clean_p2 && wc_tracked) {
111 t->state = 'n';
111 t->state = 'n';
112 t->size = dirstate_v1_from_p2;
112 t->size = dirstate_v1_from_p2;
113 t->mtime = ambiguous_time;
113 t->mtime = ambiguous_time;
114 } else if (!p1_tracked && p2_tracked && wc_tracked) {
114 } else if (!p1_tracked && p2_tracked && wc_tracked) {
115 t->state = 'n';
115 t->state = 'n';
116 t->size = dirstate_v1_from_p2;
116 t->size = dirstate_v1_from_p2;
117 t->mtime = ambiguous_time;
117 t->mtime = ambiguous_time;
118 } else if (possibly_dirty) {
118 } else if (possibly_dirty) {
119 t->state = 'n';
119 t->state = 'n';
120 t->size = dirstate_v1_nonnormal;
120 t->size = dirstate_v1_nonnormal;
121 t->mtime = ambiguous_time;
121 t->mtime = ambiguous_time;
122 } else if (wc_tracked) {
122 } else if (wc_tracked) {
123 /* this is a "normal" file */
123 /* this is a "normal" file */
124 if (parentfiledata == Py_None) {
124 if (parentfiledata == Py_None) {
125 PyErr_SetString(
125 PyErr_SetString(
126 PyExc_RuntimeError,
126 PyExc_RuntimeError,
127 "failed to pass parentfiledata for a normal file");
127 "failed to pass parentfiledata for a normal file");
128 return NULL;
128 return NULL;
129 }
129 }
130 if (!PyTuple_CheckExact(parentfiledata)) {
130 if (!PyTuple_CheckExact(parentfiledata)) {
131 PyErr_SetString(
131 PyErr_SetString(
132 PyExc_TypeError,
132 PyExc_TypeError,
133 "parentfiledata should be a Tuple or None");
133 "parentfiledata should be a Tuple or None");
134 return NULL;
134 return NULL;
135 }
135 }
136 t->state = 'n';
136 t->state = 'n';
137 t->mode =
137 t->mode =
138 (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 0));
138 (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 0));
139 t->size =
139 t->size =
140 (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 1));
140 (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 1));
141 t->mtime =
141 t->mtime =
142 (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 2));
142 (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 2));
143 } else {
143 } else {
144 PyErr_SetString(PyExc_RuntimeError, "unreachable");
144 PyErr_SetString(PyExc_RuntimeError, "unreachable");
145 return NULL;
145 return NULL;
146 }
146 }
147 return (PyObject *)t;
147 return (PyObject *)t;
148 }
148 }
149
149
150 static void dirstate_item_dealloc(PyObject *o)
150 static void dirstate_item_dealloc(PyObject *o)
151 {
151 {
152 PyObject_Del(o);
152 PyObject_Del(o);
153 }
153 }
154
154
155 static PyObject *dirstate_item_v1_state(dirstateItemObject *self)
155 static PyObject *dirstate_item_v1_state(dirstateItemObject *self)
156 {
156 {
157 return PyBytes_FromStringAndSize(&self->state, 1);
157 return PyBytes_FromStringAndSize(&self->state, 1);
158 };
158 };
159
159
160 static PyObject *dirstate_item_v1_mode(dirstateItemObject *self)
160 static PyObject *dirstate_item_v1_mode(dirstateItemObject *self)
161 {
161 {
162 return PyInt_FromLong(self->mode);
162 return PyInt_FromLong(self->mode);
163 };
163 };
164
164
165 static PyObject *dirstate_item_v1_size(dirstateItemObject *self)
165 static PyObject *dirstate_item_v1_size(dirstateItemObject *self)
166 {
166 {
167 return PyInt_FromLong(self->size);
167 return PyInt_FromLong(self->size);
168 };
168 };
169
169
170 static PyObject *dirstate_item_v1_mtime(dirstateItemObject *self)
170 static PyObject *dirstate_item_v1_mtime(dirstateItemObject *self)
171 {
171 {
172 return PyInt_FromLong(self->mtime);
172 return PyInt_FromLong(self->mtime);
173 };
173 };
174
174
175 static PyObject *dirstate_item_need_delay(dirstateItemObject *self,
175 static PyObject *dirstate_item_need_delay(dirstateItemObject *self,
176 PyObject *value)
176 PyObject *value)
177 {
177 {
178 long now;
178 long now;
179 if (!pylong_to_long(value, &now)) {
179 if (!pylong_to_long(value, &now)) {
180 return NULL;
180 return NULL;
181 }
181 }
182 if (self->state == 'n' && self->mtime == now) {
182 if (self->state == 'n' && self->mtime == now) {
183 Py_RETURN_TRUE;
183 Py_RETURN_TRUE;
184 } else {
184 } else {
185 Py_RETURN_FALSE;
185 Py_RETURN_FALSE;
186 }
186 }
187 };
187 };
188
188
189 /* This will never change since it's bound to V1
189 /* This will never change since it's bound to V1
190 */
190 */
191 static inline dirstateItemObject *
191 static inline dirstateItemObject *
192 dirstate_item_from_v1_data(char state, int mode, int size, int mtime)
192 dirstate_item_from_v1_data(char state, int mode, int size, int mtime)
193 {
193 {
194 dirstateItemObject *t =
194 dirstateItemObject *t =
195 PyObject_New(dirstateItemObject, &dirstateItemType);
195 PyObject_New(dirstateItemObject, &dirstateItemType);
196 if (!t) {
196 if (!t) {
197 return NULL;
197 return NULL;
198 }
198 }
199 t->state = state;
199 t->state = state;
200 t->mode = mode;
200 t->mode = mode;
201 t->size = size;
201 t->size = size;
202 t->mtime = mtime;
202 t->mtime = mtime;
203 return t;
203 return t;
204 }
204 }
205
205
206 /* This will never change since it's bound to V1, unlike `dirstate_item_new` */
206 /* This will never change since it's bound to V1, unlike `dirstate_item_new` */
207 static PyObject *dirstate_item_from_v1_meth(PyTypeObject *subtype,
207 static PyObject *dirstate_item_from_v1_meth(PyTypeObject *subtype,
208 PyObject *args)
208 PyObject *args)
209 {
209 {
210 /* We do all the initialization here and not a tp_init function because
210 /* We do all the initialization here and not a tp_init function because
211 * dirstate_item is immutable. */
211 * dirstate_item is immutable. */
212 dirstateItemObject *t;
213 char state;
212 char state;
214 int size, mode, mtime;
213 int size, mode, mtime;
215 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) {
214 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) {
216 return NULL;
215 return NULL;
217 }
216 }
218
217 return (PyObject *)dirstate_item_from_v1_data(state, mode, size, mtime);
219 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
220 if (!t) {
221 return NULL;
222 }
223 t->state = state;
224 t->mode = mode;
225 t->size = size;
226 t->mtime = mtime;
227
228 return (PyObject *)t;
229 };
218 };
230
219
231 /* constructor to help legacy API to build a new "added" item
220 /* constructor to help legacy API to build a new "added" item
232
221
233 Should eventually be removed */
222 Should eventually be removed */
234 static PyObject *dirstate_item_new_added(PyTypeObject *subtype)
223 static PyObject *dirstate_item_new_added(PyTypeObject *subtype)
235 {
224 {
236 dirstateItemObject *t;
225 dirstateItemObject *t;
237 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
226 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
238 if (!t) {
227 if (!t) {
239 return NULL;
228 return NULL;
240 }
229 }
241 t->state = 'a';
230 t->state = 'a';
242 t->mode = 0;
231 t->mode = 0;
243 t->size = dirstate_v1_nonnormal;
232 t->size = dirstate_v1_nonnormal;
244 t->mtime = ambiguous_time;
233 t->mtime = ambiguous_time;
245 return (PyObject *)t;
234 return (PyObject *)t;
246 };
235 };
247
236
248 /* constructor to help legacy API to build a new "merged" item
237 /* constructor to help legacy API to build a new "merged" item
249
238
250 Should eventually be removed */
239 Should eventually be removed */
251 static PyObject *dirstate_item_new_merged(PyTypeObject *subtype)
240 static PyObject *dirstate_item_new_merged(PyTypeObject *subtype)
252 {
241 {
253 dirstateItemObject *t;
242 dirstateItemObject *t;
254 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
243 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
255 if (!t) {
244 if (!t) {
256 return NULL;
245 return NULL;
257 }
246 }
258 t->state = 'm';
247 t->state = 'm';
259 t->mode = 0;
248 t->mode = 0;
260 t->size = dirstate_v1_from_p2;
249 t->size = dirstate_v1_from_p2;
261 t->mtime = ambiguous_time;
250 t->mtime = ambiguous_time;
262 return (PyObject *)t;
251 return (PyObject *)t;
263 };
252 };
264
253
265 /* constructor to help legacy API to build a new "from_p2" item
254 /* constructor to help legacy API to build a new "from_p2" item
266
255
267 Should eventually be removed */
256 Should eventually be removed */
268 static PyObject *dirstate_item_new_from_p2(PyTypeObject *subtype)
257 static PyObject *dirstate_item_new_from_p2(PyTypeObject *subtype)
269 {
258 {
270 /* We do all the initialization here and not a tp_init function because
259 /* We do all the initialization here and not a tp_init function because
271 * dirstate_item is immutable. */
260 * dirstate_item is immutable. */
272 dirstateItemObject *t;
261 dirstateItemObject *t;
273 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
262 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
274 if (!t) {
263 if (!t) {
275 return NULL;
264 return NULL;
276 }
265 }
277 t->state = 'n';
266 t->state = 'n';
278 t->mode = 0;
267 t->mode = 0;
279 t->size = dirstate_v1_from_p2;
268 t->size = dirstate_v1_from_p2;
280 t->mtime = ambiguous_time;
269 t->mtime = ambiguous_time;
281 return (PyObject *)t;
270 return (PyObject *)t;
282 };
271 };
283
272
284 /* constructor to help legacy API to build a new "possibly" item
273 /* constructor to help legacy API to build a new "possibly" item
285
274
286 Should eventually be removed */
275 Should eventually be removed */
287 static PyObject *dirstate_item_new_possibly_dirty(PyTypeObject *subtype)
276 static PyObject *dirstate_item_new_possibly_dirty(PyTypeObject *subtype)
288 {
277 {
289 /* We do all the initialization here and not a tp_init function because
278 /* We do all the initialization here and not a tp_init function because
290 * dirstate_item is immutable. */
279 * dirstate_item is immutable. */
291 dirstateItemObject *t;
280 dirstateItemObject *t;
292 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
281 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
293 if (!t) {
282 if (!t) {
294 return NULL;
283 return NULL;
295 }
284 }
296 t->state = 'n';
285 t->state = 'n';
297 t->mode = 0;
286 t->mode = 0;
298 t->size = dirstate_v1_nonnormal;
287 t->size = dirstate_v1_nonnormal;
299 t->mtime = ambiguous_time;
288 t->mtime = ambiguous_time;
300 return (PyObject *)t;
289 return (PyObject *)t;
301 };
290 };
302
291
303 /* constructor to help legacy API to build a new "normal" item
292 /* constructor to help legacy API to build a new "normal" item
304
293
305 Should eventually be removed */
294 Should eventually be removed */
306 static PyObject *dirstate_item_new_normal(PyTypeObject *subtype, PyObject *args)
295 static PyObject *dirstate_item_new_normal(PyTypeObject *subtype, PyObject *args)
307 {
296 {
308 /* We do all the initialization here and not a tp_init function because
297 /* We do all the initialization here and not a tp_init function because
309 * dirstate_item is immutable. */
298 * dirstate_item is immutable. */
310 dirstateItemObject *t;
299 dirstateItemObject *t;
311 int size, mode, mtime;
300 int size, mode, mtime;
312 if (!PyArg_ParseTuple(args, "iii", &mode, &size, &mtime)) {
301 if (!PyArg_ParseTuple(args, "iii", &mode, &size, &mtime)) {
313 return NULL;
302 return NULL;
314 }
303 }
315
304
316 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
305 t = (dirstateItemObject *)subtype->tp_alloc(subtype, 1);
317 if (!t) {
306 if (!t) {
318 return NULL;
307 return NULL;
319 }
308 }
320 t->state = 'n';
309 t->state = 'n';
321 t->mode = mode;
310 t->mode = mode;
322 t->size = size;
311 t->size = size;
323 t->mtime = mtime;
312 t->mtime = mtime;
324 return (PyObject *)t;
313 return (PyObject *)t;
325 };
314 };
326
315
327 /* This means the next status call will have to actually check its content
316 /* This means the next status call will have to actually check its content
328 to make sure it is correct. */
317 to make sure it is correct. */
329 static PyObject *dirstate_item_set_possibly_dirty(dirstateItemObject *self)
318 static PyObject *dirstate_item_set_possibly_dirty(dirstateItemObject *self)
330 {
319 {
331 self->mtime = ambiguous_time;
320 self->mtime = ambiguous_time;
332 Py_RETURN_NONE;
321 Py_RETURN_NONE;
333 }
322 }
334
323
335 static PyObject *dirstate_item_set_untracked(dirstateItemObject *self)
324 static PyObject *dirstate_item_set_untracked(dirstateItemObject *self)
336 {
325 {
337 if (self->state == 'm') {
326 if (self->state == 'm') {
338 self->size = dirstate_v1_nonnormal;
327 self->size = dirstate_v1_nonnormal;
339 } else if (self->state == 'n' && self->size == dirstate_v1_from_p2) {
328 } else if (self->state == 'n' && self->size == dirstate_v1_from_p2) {
340 self->size = dirstate_v1_from_p2;
329 self->size = dirstate_v1_from_p2;
341 } else {
330 } else {
342 self->size = 0;
331 self->size = 0;
343 }
332 }
344 self->state = 'r';
333 self->state = 'r';
345 self->mode = 0;
334 self->mode = 0;
346 self->mtime = 0;
335 self->mtime = 0;
347 Py_RETURN_NONE;
336 Py_RETURN_NONE;
348 }
337 }
349
338
350 static PyMethodDef dirstate_item_methods[] = {
339 static PyMethodDef dirstate_item_methods[] = {
351 {"v1_state", (PyCFunction)dirstate_item_v1_state, METH_NOARGS,
340 {"v1_state", (PyCFunction)dirstate_item_v1_state, METH_NOARGS,
352 "return a \"state\" suitable for v1 serialization"},
341 "return a \"state\" suitable for v1 serialization"},
353 {"v1_mode", (PyCFunction)dirstate_item_v1_mode, METH_NOARGS,
342 {"v1_mode", (PyCFunction)dirstate_item_v1_mode, METH_NOARGS,
354 "return a \"mode\" suitable for v1 serialization"},
343 "return a \"mode\" suitable for v1 serialization"},
355 {"v1_size", (PyCFunction)dirstate_item_v1_size, METH_NOARGS,
344 {"v1_size", (PyCFunction)dirstate_item_v1_size, METH_NOARGS,
356 "return a \"size\" suitable for v1 serialization"},
345 "return a \"size\" suitable for v1 serialization"},
357 {"v1_mtime", (PyCFunction)dirstate_item_v1_mtime, METH_NOARGS,
346 {"v1_mtime", (PyCFunction)dirstate_item_v1_mtime, METH_NOARGS,
358 "return a \"mtime\" suitable for v1 serialization"},
347 "return a \"mtime\" suitable for v1 serialization"},
359 {"need_delay", (PyCFunction)dirstate_item_need_delay, METH_O,
348 {"need_delay", (PyCFunction)dirstate_item_need_delay, METH_O,
360 "True if the stored mtime would be ambiguous with the current time"},
349 "True if the stored mtime would be ambiguous with the current time"},
361 {"from_v1_data", (PyCFunction)dirstate_item_from_v1_meth,
350 {"from_v1_data", (PyCFunction)dirstate_item_from_v1_meth,
362 METH_VARARGS | METH_CLASS, "build a new DirstateItem object from V1 data"},
351 METH_VARARGS | METH_CLASS, "build a new DirstateItem object from V1 data"},
363 {"new_added", (PyCFunction)dirstate_item_new_added,
352 {"new_added", (PyCFunction)dirstate_item_new_added,
364 METH_NOARGS | METH_CLASS,
353 METH_NOARGS | METH_CLASS,
365 "constructor to help legacy API to build a new \"added\" item"},
354 "constructor to help legacy API to build a new \"added\" item"},
366 {"new_merged", (PyCFunction)dirstate_item_new_merged,
355 {"new_merged", (PyCFunction)dirstate_item_new_merged,
367 METH_NOARGS | METH_CLASS,
356 METH_NOARGS | METH_CLASS,
368 "constructor to help legacy API to build a new \"merged\" item"},
357 "constructor to help legacy API to build a new \"merged\" item"},
369 {"new_from_p2", (PyCFunction)dirstate_item_new_from_p2,
358 {"new_from_p2", (PyCFunction)dirstate_item_new_from_p2,
370 METH_NOARGS | METH_CLASS,
359 METH_NOARGS | METH_CLASS,
371 "constructor to help legacy API to build a new \"from_p2\" item"},
360 "constructor to help legacy API to build a new \"from_p2\" item"},
372 {"new_possibly_dirty", (PyCFunction)dirstate_item_new_possibly_dirty,
361 {"new_possibly_dirty", (PyCFunction)dirstate_item_new_possibly_dirty,
373 METH_NOARGS | METH_CLASS,
362 METH_NOARGS | METH_CLASS,
374 "constructor to help legacy API to build a new \"possibly_dirty\" item"},
363 "constructor to help legacy API to build a new \"possibly_dirty\" item"},
375 {"new_normal", (PyCFunction)dirstate_item_new_normal,
364 {"new_normal", (PyCFunction)dirstate_item_new_normal,
376 METH_VARARGS | METH_CLASS,
365 METH_VARARGS | METH_CLASS,
377 "constructor to help legacy API to build a new \"normal\" item"},
366 "constructor to help legacy API to build a new \"normal\" item"},
378 {"set_possibly_dirty", (PyCFunction)dirstate_item_set_possibly_dirty,
367 {"set_possibly_dirty", (PyCFunction)dirstate_item_set_possibly_dirty,
379 METH_NOARGS, "mark a file as \"possibly dirty\""},
368 METH_NOARGS, "mark a file as \"possibly dirty\""},
380 {"set_untracked", (PyCFunction)dirstate_item_set_untracked, METH_NOARGS,
369 {"set_untracked", (PyCFunction)dirstate_item_set_untracked, METH_NOARGS,
381 "mark a file as \"untracked\""},
370 "mark a file as \"untracked\""},
382 {NULL} /* Sentinel */
371 {NULL} /* Sentinel */
383 };
372 };
384
373
385 static PyObject *dirstate_item_get_mode(dirstateItemObject *self)
374 static PyObject *dirstate_item_get_mode(dirstateItemObject *self)
386 {
375 {
387 return PyInt_FromLong(self->mode);
376 return PyInt_FromLong(self->mode);
388 };
377 };
389
378
390 static PyObject *dirstate_item_get_size(dirstateItemObject *self)
379 static PyObject *dirstate_item_get_size(dirstateItemObject *self)
391 {
380 {
392 return PyInt_FromLong(self->size);
381 return PyInt_FromLong(self->size);
393 };
382 };
394
383
395 static PyObject *dirstate_item_get_mtime(dirstateItemObject *self)
384 static PyObject *dirstate_item_get_mtime(dirstateItemObject *self)
396 {
385 {
397 return PyInt_FromLong(self->mtime);
386 return PyInt_FromLong(self->mtime);
398 };
387 };
399
388
400 static PyObject *dirstate_item_get_state(dirstateItemObject *self)
389 static PyObject *dirstate_item_get_state(dirstateItemObject *self)
401 {
390 {
402 return PyBytes_FromStringAndSize(&self->state, 1);
391 return PyBytes_FromStringAndSize(&self->state, 1);
403 };
392 };
404
393
405 static PyObject *dirstate_item_get_tracked(dirstateItemObject *self)
394 static PyObject *dirstate_item_get_tracked(dirstateItemObject *self)
406 {
395 {
407 if (self->state == 'a' || self->state == 'm' || self->state == 'n') {
396 if (self->state == 'a' || self->state == 'm' || self->state == 'n') {
408 Py_RETURN_TRUE;
397 Py_RETURN_TRUE;
409 } else {
398 } else {
410 Py_RETURN_FALSE;
399 Py_RETURN_FALSE;
411 }
400 }
412 };
401 };
413
402
414 static PyObject *dirstate_item_get_added(dirstateItemObject *self)
403 static PyObject *dirstate_item_get_added(dirstateItemObject *self)
415 {
404 {
416 if (self->state == 'a') {
405 if (self->state == 'a') {
417 Py_RETURN_TRUE;
406 Py_RETURN_TRUE;
418 } else {
407 } else {
419 Py_RETURN_FALSE;
408 Py_RETURN_FALSE;
420 }
409 }
421 };
410 };
422
411
423 static PyObject *dirstate_item_get_merged(dirstateItemObject *self)
412 static PyObject *dirstate_item_get_merged(dirstateItemObject *self)
424 {
413 {
425 if (self->state == 'm') {
414 if (self->state == 'm') {
426 Py_RETURN_TRUE;
415 Py_RETURN_TRUE;
427 } else {
416 } else {
428 Py_RETURN_FALSE;
417 Py_RETURN_FALSE;
429 }
418 }
430 };
419 };
431
420
432 static PyObject *dirstate_item_get_merged_removed(dirstateItemObject *self)
421 static PyObject *dirstate_item_get_merged_removed(dirstateItemObject *self)
433 {
422 {
434 if (self->state == 'r' && self->size == dirstate_v1_nonnormal) {
423 if (self->state == 'r' && self->size == dirstate_v1_nonnormal) {
435 Py_RETURN_TRUE;
424 Py_RETURN_TRUE;
436 } else {
425 } else {
437 Py_RETURN_FALSE;
426 Py_RETURN_FALSE;
438 }
427 }
439 };
428 };
440
429
441 static PyObject *dirstate_item_get_from_p2(dirstateItemObject *self)
430 static PyObject *dirstate_item_get_from_p2(dirstateItemObject *self)
442 {
431 {
443 if (self->state == 'n' && self->size == dirstate_v1_from_p2) {
432 if (self->state == 'n' && self->size == dirstate_v1_from_p2) {
444 Py_RETURN_TRUE;
433 Py_RETURN_TRUE;
445 } else {
434 } else {
446 Py_RETURN_FALSE;
435 Py_RETURN_FALSE;
447 }
436 }
448 };
437 };
449
438
450 static PyObject *dirstate_item_get_from_p2_removed(dirstateItemObject *self)
439 static PyObject *dirstate_item_get_from_p2_removed(dirstateItemObject *self)
451 {
440 {
452 if (self->state == 'r' && self->size == dirstate_v1_from_p2) {
441 if (self->state == 'r' && self->size == dirstate_v1_from_p2) {
453 Py_RETURN_TRUE;
442 Py_RETURN_TRUE;
454 } else {
443 } else {
455 Py_RETURN_FALSE;
444 Py_RETURN_FALSE;
456 }
445 }
457 };
446 };
458
447
459 static PyObject *dirstate_item_get_removed(dirstateItemObject *self)
448 static PyObject *dirstate_item_get_removed(dirstateItemObject *self)
460 {
449 {
461 if (self->state == 'r') {
450 if (self->state == 'r') {
462 Py_RETURN_TRUE;
451 Py_RETURN_TRUE;
463 } else {
452 } else {
464 Py_RETURN_FALSE;
453 Py_RETURN_FALSE;
465 }
454 }
466 };
455 };
467
456
468 static PyObject *dm_nonnormal(dirstateItemObject *self)
457 static PyObject *dm_nonnormal(dirstateItemObject *self)
469 {
458 {
470 if (self->state != 'n' || self->mtime == ambiguous_time) {
459 if (self->state != 'n' || self->mtime == ambiguous_time) {
471 Py_RETURN_TRUE;
460 Py_RETURN_TRUE;
472 } else {
461 } else {
473 Py_RETURN_FALSE;
462 Py_RETURN_FALSE;
474 }
463 }
475 };
464 };
476 static PyObject *dm_otherparent(dirstateItemObject *self)
465 static PyObject *dm_otherparent(dirstateItemObject *self)
477 {
466 {
478 if (self->size == dirstate_v1_from_p2) {
467 if (self->size == dirstate_v1_from_p2) {
479 Py_RETURN_TRUE;
468 Py_RETURN_TRUE;
480 } else {
469 } else {
481 Py_RETURN_FALSE;
470 Py_RETURN_FALSE;
482 }
471 }
483 };
472 };
484
473
485 static PyGetSetDef dirstate_item_getset[] = {
474 static PyGetSetDef dirstate_item_getset[] = {
486 {"mode", (getter)dirstate_item_get_mode, NULL, "mode", NULL},
475 {"mode", (getter)dirstate_item_get_mode, NULL, "mode", NULL},
487 {"size", (getter)dirstate_item_get_size, NULL, "size", NULL},
476 {"size", (getter)dirstate_item_get_size, NULL, "size", NULL},
488 {"mtime", (getter)dirstate_item_get_mtime, NULL, "mtime", NULL},
477 {"mtime", (getter)dirstate_item_get_mtime, NULL, "mtime", NULL},
489 {"state", (getter)dirstate_item_get_state, NULL, "state", NULL},
478 {"state", (getter)dirstate_item_get_state, NULL, "state", NULL},
490 {"tracked", (getter)dirstate_item_get_tracked, NULL, "tracked", NULL},
479 {"tracked", (getter)dirstate_item_get_tracked, NULL, "tracked", NULL},
491 {"added", (getter)dirstate_item_get_added, NULL, "added", NULL},
480 {"added", (getter)dirstate_item_get_added, NULL, "added", NULL},
492 {"merged_removed", (getter)dirstate_item_get_merged_removed, NULL,
481 {"merged_removed", (getter)dirstate_item_get_merged_removed, NULL,
493 "merged_removed", NULL},
482 "merged_removed", NULL},
494 {"merged", (getter)dirstate_item_get_merged, NULL, "merged", NULL},
483 {"merged", (getter)dirstate_item_get_merged, NULL, "merged", NULL},
495 {"from_p2_removed", (getter)dirstate_item_get_from_p2_removed, NULL,
484 {"from_p2_removed", (getter)dirstate_item_get_from_p2_removed, NULL,
496 "from_p2_removed", NULL},
485 "from_p2_removed", NULL},
497 {"from_p2", (getter)dirstate_item_get_from_p2, NULL, "from_p2", NULL},
486 {"from_p2", (getter)dirstate_item_get_from_p2, NULL, "from_p2", NULL},
498 {"removed", (getter)dirstate_item_get_removed, NULL, "removed", NULL},
487 {"removed", (getter)dirstate_item_get_removed, NULL, "removed", NULL},
499 {"dm_nonnormal", (getter)dm_nonnormal, NULL, "dm_nonnormal", NULL},
488 {"dm_nonnormal", (getter)dm_nonnormal, NULL, "dm_nonnormal", NULL},
500 {"dm_otherparent", (getter)dm_otherparent, NULL, "dm_otherparent", NULL},
489 {"dm_otherparent", (getter)dm_otherparent, NULL, "dm_otherparent", NULL},
501 {NULL} /* Sentinel */
490 {NULL} /* Sentinel */
502 };
491 };
503
492
504 PyTypeObject dirstateItemType = {
493 PyTypeObject dirstateItemType = {
505 PyVarObject_HEAD_INIT(NULL, 0) /* header */
494 PyVarObject_HEAD_INIT(NULL, 0) /* header */
506 "dirstate_tuple", /* tp_name */
495 "dirstate_tuple", /* tp_name */
507 sizeof(dirstateItemObject), /* tp_basicsize */
496 sizeof(dirstateItemObject), /* tp_basicsize */
508 0, /* tp_itemsize */
497 0, /* tp_itemsize */
509 (destructor)dirstate_item_dealloc, /* tp_dealloc */
498 (destructor)dirstate_item_dealloc, /* tp_dealloc */
510 0, /* tp_print */
499 0, /* tp_print */
511 0, /* tp_getattr */
500 0, /* tp_getattr */
512 0, /* tp_setattr */
501 0, /* tp_setattr */
513 0, /* tp_compare */
502 0, /* tp_compare */
514 0, /* tp_repr */
503 0, /* tp_repr */
515 0, /* tp_as_number */
504 0, /* tp_as_number */
516 0, /* tp_as_sequence */
505 0, /* tp_as_sequence */
517 0, /* tp_as_mapping */
506 0, /* tp_as_mapping */
518 0, /* tp_hash */
507 0, /* tp_hash */
519 0, /* tp_call */
508 0, /* tp_call */
520 0, /* tp_str */
509 0, /* tp_str */
521 0, /* tp_getattro */
510 0, /* tp_getattro */
522 0, /* tp_setattro */
511 0, /* tp_setattro */
523 0, /* tp_as_buffer */
512 0, /* tp_as_buffer */
524 Py_TPFLAGS_DEFAULT, /* tp_flags */
513 Py_TPFLAGS_DEFAULT, /* tp_flags */
525 "dirstate tuple", /* tp_doc */
514 "dirstate tuple", /* tp_doc */
526 0, /* tp_traverse */
515 0, /* tp_traverse */
527 0, /* tp_clear */
516 0, /* tp_clear */
528 0, /* tp_richcompare */
517 0, /* tp_richcompare */
529 0, /* tp_weaklistoffset */
518 0, /* tp_weaklistoffset */
530 0, /* tp_iter */
519 0, /* tp_iter */
531 0, /* tp_iternext */
520 0, /* tp_iternext */
532 dirstate_item_methods, /* tp_methods */
521 dirstate_item_methods, /* tp_methods */
533 0, /* tp_members */
522 0, /* tp_members */
534 dirstate_item_getset, /* tp_getset */
523 dirstate_item_getset, /* tp_getset */
535 0, /* tp_base */
524 0, /* tp_base */
536 0, /* tp_dict */
525 0, /* tp_dict */
537 0, /* tp_descr_get */
526 0, /* tp_descr_get */
538 0, /* tp_descr_set */
527 0, /* tp_descr_set */
539 0, /* tp_dictoffset */
528 0, /* tp_dictoffset */
540 0, /* tp_init */
529 0, /* tp_init */
541 0, /* tp_alloc */
530 0, /* tp_alloc */
542 dirstate_item_new, /* tp_new */
531 dirstate_item_new, /* tp_new */
543 };
532 };
544
533
545 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
534 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
546 {
535 {
547 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
536 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
548 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
537 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
549 char state, *cur, *str, *cpos;
538 char state, *cur, *str, *cpos;
550 int mode, size, mtime;
539 int mode, size, mtime;
551 unsigned int flen, pos = 40;
540 unsigned int flen, pos = 40;
552 Py_ssize_t len = 40;
541 Py_ssize_t len = 40;
553 Py_ssize_t readlen;
542 Py_ssize_t readlen;
554
543
555 if (!PyArg_ParseTuple(
544 if (!PyArg_ParseTuple(
556 args, PY23("O!O!s#:parse_dirstate", "O!O!y#:parse_dirstate"),
545 args, PY23("O!O!s#:parse_dirstate", "O!O!y#:parse_dirstate"),
557 &PyDict_Type, &dmap, &PyDict_Type, &cmap, &str, &readlen)) {
546 &PyDict_Type, &dmap, &PyDict_Type, &cmap, &str, &readlen)) {
558 goto quit;
547 goto quit;
559 }
548 }
560
549
561 len = readlen;
550 len = readlen;
562
551
563 /* read parents */
552 /* read parents */
564 if (len < 40) {
553 if (len < 40) {
565 PyErr_SetString(PyExc_ValueError,
554 PyErr_SetString(PyExc_ValueError,
566 "too little data for parents");
555 "too little data for parents");
567 goto quit;
556 goto quit;
568 }
557 }
569
558
570 parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, (Py_ssize_t)20,
559 parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, (Py_ssize_t)20,
571 str + 20, (Py_ssize_t)20);
560 str + 20, (Py_ssize_t)20);
572 if (!parents) {
561 if (!parents) {
573 goto quit;
562 goto quit;
574 }
563 }
575
564
576 /* read filenames */
565 /* read filenames */
577 while (pos >= 40 && pos < len) {
566 while (pos >= 40 && pos < len) {
578 if (pos + 17 > len) {
567 if (pos + 17 > len) {
579 PyErr_SetString(PyExc_ValueError,
568 PyErr_SetString(PyExc_ValueError,
580 "overflow in dirstate");
569 "overflow in dirstate");
581 goto quit;
570 goto quit;
582 }
571 }
583 cur = str + pos;
572 cur = str + pos;
584 /* unpack header */
573 /* unpack header */
585 state = *cur;
574 state = *cur;
586 mode = getbe32(cur + 1);
575 mode = getbe32(cur + 1);
587 size = getbe32(cur + 5);
576 size = getbe32(cur + 5);
588 mtime = getbe32(cur + 9);
577 mtime = getbe32(cur + 9);
589 flen = getbe32(cur + 13);
578 flen = getbe32(cur + 13);
590 pos += 17;
579 pos += 17;
591 cur += 17;
580 cur += 17;
592 if (flen > len - pos) {
581 if (flen > len - pos) {
593 PyErr_SetString(PyExc_ValueError,
582 PyErr_SetString(PyExc_ValueError,
594 "overflow in dirstate");
583 "overflow in dirstate");
595 goto quit;
584 goto quit;
596 }
585 }
597
586
598 entry = (PyObject *)dirstate_item_from_v1_data(state, mode,
587 entry = (PyObject *)dirstate_item_from_v1_data(state, mode,
599 size, mtime);
588 size, mtime);
600 cpos = memchr(cur, 0, flen);
589 cpos = memchr(cur, 0, flen);
601 if (cpos) {
590 if (cpos) {
602 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
591 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
603 cname = PyBytes_FromStringAndSize(
592 cname = PyBytes_FromStringAndSize(
604 cpos + 1, flen - (cpos - cur) - 1);
593 cpos + 1, flen - (cpos - cur) - 1);
605 if (!fname || !cname ||
594 if (!fname || !cname ||
606 PyDict_SetItem(cmap, fname, cname) == -1 ||
595 PyDict_SetItem(cmap, fname, cname) == -1 ||
607 PyDict_SetItem(dmap, fname, entry) == -1) {
596 PyDict_SetItem(dmap, fname, entry) == -1) {
608 goto quit;
597 goto quit;
609 }
598 }
610 Py_DECREF(cname);
599 Py_DECREF(cname);
611 } else {
600 } else {
612 fname = PyBytes_FromStringAndSize(cur, flen);
601 fname = PyBytes_FromStringAndSize(cur, flen);
613 if (!fname ||
602 if (!fname ||
614 PyDict_SetItem(dmap, fname, entry) == -1) {
603 PyDict_SetItem(dmap, fname, entry) == -1) {
615 goto quit;
604 goto quit;
616 }
605 }
617 }
606 }
618 Py_DECREF(fname);
607 Py_DECREF(fname);
619 Py_DECREF(entry);
608 Py_DECREF(entry);
620 fname = cname = entry = NULL;
609 fname = cname = entry = NULL;
621 pos += flen;
610 pos += flen;
622 }
611 }
623
612
624 ret = parents;
613 ret = parents;
625 Py_INCREF(ret);
614 Py_INCREF(ret);
626 quit:
615 quit:
627 Py_XDECREF(fname);
616 Py_XDECREF(fname);
628 Py_XDECREF(cname);
617 Py_XDECREF(cname);
629 Py_XDECREF(entry);
618 Py_XDECREF(entry);
630 Py_XDECREF(parents);
619 Py_XDECREF(parents);
631 return ret;
620 return ret;
632 }
621 }
633
622
634 /*
623 /*
635 * Build a set of non-normal and other parent entries from the dirstate dmap
624 * Build a set of non-normal and other parent entries from the dirstate dmap
636 */
625 */
637 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
626 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
638 {
627 {
639 PyObject *dmap, *fname, *v;
628 PyObject *dmap, *fname, *v;
640 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
629 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
641 Py_ssize_t pos;
630 Py_ssize_t pos;
642
631
643 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type,
632 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type,
644 &dmap)) {
633 &dmap)) {
645 goto bail;
634 goto bail;
646 }
635 }
647
636
648 nonnset = PySet_New(NULL);
637 nonnset = PySet_New(NULL);
649 if (nonnset == NULL) {
638 if (nonnset == NULL) {
650 goto bail;
639 goto bail;
651 }
640 }
652
641
653 otherpset = PySet_New(NULL);
642 otherpset = PySet_New(NULL);
654 if (otherpset == NULL) {
643 if (otherpset == NULL) {
655 goto bail;
644 goto bail;
656 }
645 }
657
646
658 pos = 0;
647 pos = 0;
659 while (PyDict_Next(dmap, &pos, &fname, &v)) {
648 while (PyDict_Next(dmap, &pos, &fname, &v)) {
660 dirstateItemObject *t;
649 dirstateItemObject *t;
661 if (!dirstate_tuple_check(v)) {
650 if (!dirstate_tuple_check(v)) {
662 PyErr_SetString(PyExc_TypeError,
651 PyErr_SetString(PyExc_TypeError,
663 "expected a dirstate tuple");
652 "expected a dirstate tuple");
664 goto bail;
653 goto bail;
665 }
654 }
666 t = (dirstateItemObject *)v;
655 t = (dirstateItemObject *)v;
667
656
668 if (t->state == 'n' && t->size == -2) {
657 if (t->state == 'n' && t->size == -2) {
669 if (PySet_Add(otherpset, fname) == -1) {
658 if (PySet_Add(otherpset, fname) == -1) {
670 goto bail;
659 goto bail;
671 }
660 }
672 }
661 }
673
662
674 if (t->state == 'n' && t->mtime != -1) {
663 if (t->state == 'n' && t->mtime != -1) {
675 continue;
664 continue;
676 }
665 }
677 if (PySet_Add(nonnset, fname) == -1) {
666 if (PySet_Add(nonnset, fname) == -1) {
678 goto bail;
667 goto bail;
679 }
668 }
680 }
669 }
681
670
682 result = Py_BuildValue("(OO)", nonnset, otherpset);
671 result = Py_BuildValue("(OO)", nonnset, otherpset);
683 if (result == NULL) {
672 if (result == NULL) {
684 goto bail;
673 goto bail;
685 }
674 }
686 Py_DECREF(nonnset);
675 Py_DECREF(nonnset);
687 Py_DECREF(otherpset);
676 Py_DECREF(otherpset);
688 return result;
677 return result;
689 bail:
678 bail:
690 Py_XDECREF(nonnset);
679 Py_XDECREF(nonnset);
691 Py_XDECREF(otherpset);
680 Py_XDECREF(otherpset);
692 Py_XDECREF(result);
681 Py_XDECREF(result);
693 return NULL;
682 return NULL;
694 }
683 }
695
684
696 /*
685 /*
697 * Efficiently pack a dirstate object into its on-disk format.
686 * Efficiently pack a dirstate object into its on-disk format.
698 */
687 */
699 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
688 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
700 {
689 {
701 PyObject *packobj = NULL;
690 PyObject *packobj = NULL;
702 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
691 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
703 Py_ssize_t nbytes, pos, l;
692 Py_ssize_t nbytes, pos, l;
704 PyObject *k, *v = NULL, *pn;
693 PyObject *k, *v = NULL, *pn;
705 char *p, *s;
694 char *p, *s;
706 int now;
695 int now;
707
696
708 if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map,
697 if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map,
709 &PyDict_Type, &copymap, &PyTuple_Type, &pl,
698 &PyDict_Type, &copymap, &PyTuple_Type, &pl,
710 &now)) {
699 &now)) {
711 return NULL;
700 return NULL;
712 }
701 }
713
702
714 if (PyTuple_Size(pl) != 2) {
703 if (PyTuple_Size(pl) != 2) {
715 PyErr_SetString(PyExc_TypeError, "expected 2-element tuple");
704 PyErr_SetString(PyExc_TypeError, "expected 2-element tuple");
716 return NULL;
705 return NULL;
717 }
706 }
718
707
719 /* Figure out how much we need to allocate. */
708 /* Figure out how much we need to allocate. */
720 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
709 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
721 PyObject *c;
710 PyObject *c;
722 if (!PyBytes_Check(k)) {
711 if (!PyBytes_Check(k)) {
723 PyErr_SetString(PyExc_TypeError, "expected string key");
712 PyErr_SetString(PyExc_TypeError, "expected string key");
724 goto bail;
713 goto bail;
725 }
714 }
726 nbytes += PyBytes_GET_SIZE(k) + 17;
715 nbytes += PyBytes_GET_SIZE(k) + 17;
727 c = PyDict_GetItem(copymap, k);
716 c = PyDict_GetItem(copymap, k);
728 if (c) {
717 if (c) {
729 if (!PyBytes_Check(c)) {
718 if (!PyBytes_Check(c)) {
730 PyErr_SetString(PyExc_TypeError,
719 PyErr_SetString(PyExc_TypeError,
731 "expected string key");
720 "expected string key");
732 goto bail;
721 goto bail;
733 }
722 }
734 nbytes += PyBytes_GET_SIZE(c) + 1;
723 nbytes += PyBytes_GET_SIZE(c) + 1;
735 }
724 }
736 }
725 }
737
726
738 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
727 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
739 if (packobj == NULL) {
728 if (packobj == NULL) {
740 goto bail;
729 goto bail;
741 }
730 }
742
731
743 p = PyBytes_AS_STRING(packobj);
732 p = PyBytes_AS_STRING(packobj);
744
733
745 pn = PyTuple_GET_ITEM(pl, 0);
734 pn = PyTuple_GET_ITEM(pl, 0);
746 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
735 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
747 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
736 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
748 goto bail;
737 goto bail;
749 }
738 }
750 memcpy(p, s, l);
739 memcpy(p, s, l);
751 p += 20;
740 p += 20;
752 pn = PyTuple_GET_ITEM(pl, 1);
741 pn = PyTuple_GET_ITEM(pl, 1);
753 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
742 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
754 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
743 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
755 goto bail;
744 goto bail;
756 }
745 }
757 memcpy(p, s, l);
746 memcpy(p, s, l);
758 p += 20;
747 p += 20;
759
748
760 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
749 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
761 dirstateItemObject *tuple;
750 dirstateItemObject *tuple;
762 char state;
751 char state;
763 int mode, size, mtime;
752 int mode, size, mtime;
764 Py_ssize_t len, l;
753 Py_ssize_t len, l;
765 PyObject *o;
754 PyObject *o;
766 char *t;
755 char *t;
767
756
768 if (!dirstate_tuple_check(v)) {
757 if (!dirstate_tuple_check(v)) {
769 PyErr_SetString(PyExc_TypeError,
758 PyErr_SetString(PyExc_TypeError,
770 "expected a dirstate tuple");
759 "expected a dirstate tuple");
771 goto bail;
760 goto bail;
772 }
761 }
773 tuple = (dirstateItemObject *)v;
762 tuple = (dirstateItemObject *)v;
774
763
775 state = tuple->state;
764 state = tuple->state;
776 mode = tuple->mode;
765 mode = tuple->mode;
777 size = tuple->size;
766 size = tuple->size;
778 mtime = tuple->mtime;
767 mtime = tuple->mtime;
779 if (state == 'n' && mtime == now) {
768 if (state == 'n' && mtime == now) {
780 /* See pure/parsers.py:pack_dirstate for why we do
769 /* See pure/parsers.py:pack_dirstate for why we do
781 * this. */
770 * this. */
782 mtime = -1;
771 mtime = -1;
783 mtime_unset = (PyObject *)dirstate_item_from_v1_data(
772 mtime_unset = (PyObject *)dirstate_item_from_v1_data(
784 state, mode, size, mtime);
773 state, mode, size, mtime);
785 if (!mtime_unset) {
774 if (!mtime_unset) {
786 goto bail;
775 goto bail;
787 }
776 }
788 if (PyDict_SetItem(map, k, mtime_unset) == -1) {
777 if (PyDict_SetItem(map, k, mtime_unset) == -1) {
789 goto bail;
778 goto bail;
790 }
779 }
791 Py_DECREF(mtime_unset);
780 Py_DECREF(mtime_unset);
792 mtime_unset = NULL;
781 mtime_unset = NULL;
793 }
782 }
794 *p++ = state;
783 *p++ = state;
795 putbe32((uint32_t)mode, p);
784 putbe32((uint32_t)mode, p);
796 putbe32((uint32_t)size, p + 4);
785 putbe32((uint32_t)size, p + 4);
797 putbe32((uint32_t)mtime, p + 8);
786 putbe32((uint32_t)mtime, p + 8);
798 t = p + 12;
787 t = p + 12;
799 p += 16;
788 p += 16;
800 len = PyBytes_GET_SIZE(k);
789 len = PyBytes_GET_SIZE(k);
801 memcpy(p, PyBytes_AS_STRING(k), len);
790 memcpy(p, PyBytes_AS_STRING(k), len);
802 p += len;
791 p += len;
803 o = PyDict_GetItem(copymap, k);
792 o = PyDict_GetItem(copymap, k);
804 if (o) {
793 if (o) {
805 *p++ = '\0';
794 *p++ = '\0';
806 l = PyBytes_GET_SIZE(o);
795 l = PyBytes_GET_SIZE(o);
807 memcpy(p, PyBytes_AS_STRING(o), l);
796 memcpy(p, PyBytes_AS_STRING(o), l);
808 p += l;
797 p += l;
809 len += l + 1;
798 len += l + 1;
810 }
799 }
811 putbe32((uint32_t)len, t);
800 putbe32((uint32_t)len, t);
812 }
801 }
813
802
814 pos = p - PyBytes_AS_STRING(packobj);
803 pos = p - PyBytes_AS_STRING(packobj);
815 if (pos != nbytes) {
804 if (pos != nbytes) {
816 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
805 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
817 (long)pos, (long)nbytes);
806 (long)pos, (long)nbytes);
818 goto bail;
807 goto bail;
819 }
808 }
820
809
821 return packobj;
810 return packobj;
822 bail:
811 bail:
823 Py_XDECREF(mtime_unset);
812 Py_XDECREF(mtime_unset);
824 Py_XDECREF(packobj);
813 Py_XDECREF(packobj);
825 Py_XDECREF(v);
814 Py_XDECREF(v);
826 return NULL;
815 return NULL;
827 }
816 }
828
817
829 #define BUMPED_FIX 1
818 #define BUMPED_FIX 1
830 #define USING_SHA_256 2
819 #define USING_SHA_256 2
831 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
820 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
832
821
833 static PyObject *readshas(const char *source, unsigned char num,
822 static PyObject *readshas(const char *source, unsigned char num,
834 Py_ssize_t hashwidth)
823 Py_ssize_t hashwidth)
835 {
824 {
836 int i;
825 int i;
837 PyObject *list = PyTuple_New(num);
826 PyObject *list = PyTuple_New(num);
838 if (list == NULL) {
827 if (list == NULL) {
839 return NULL;
828 return NULL;
840 }
829 }
841 for (i = 0; i < num; i++) {
830 for (i = 0; i < num; i++) {
842 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
831 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
843 if (hash == NULL) {
832 if (hash == NULL) {
844 Py_DECREF(list);
833 Py_DECREF(list);
845 return NULL;
834 return NULL;
846 }
835 }
847 PyTuple_SET_ITEM(list, i, hash);
836 PyTuple_SET_ITEM(list, i, hash);
848 source += hashwidth;
837 source += hashwidth;
849 }
838 }
850 return list;
839 return list;
851 }
840 }
852
841
853 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
842 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
854 uint32_t *msize)
843 uint32_t *msize)
855 {
844 {
856 const char *data = databegin;
845 const char *data = databegin;
857 const char *meta;
846 const char *meta;
858
847
859 double mtime;
848 double mtime;
860 int16_t tz;
849 int16_t tz;
861 uint16_t flags;
850 uint16_t flags;
862 unsigned char nsuccs, nparents, nmetadata;
851 unsigned char nsuccs, nparents, nmetadata;
863 Py_ssize_t hashwidth = 20;
852 Py_ssize_t hashwidth = 20;
864
853
865 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
854 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
866 PyObject *metadata = NULL, *ret = NULL;
855 PyObject *metadata = NULL, *ret = NULL;
867 int i;
856 int i;
868
857
869 if (data + FM1_HEADER_SIZE > dataend) {
858 if (data + FM1_HEADER_SIZE > dataend) {
870 goto overflow;
859 goto overflow;
871 }
860 }
872
861
873 *msize = getbe32(data);
862 *msize = getbe32(data);
874 data += 4;
863 data += 4;
875 mtime = getbefloat64(data);
864 mtime = getbefloat64(data);
876 data += 8;
865 data += 8;
877 tz = getbeint16(data);
866 tz = getbeint16(data);
878 data += 2;
867 data += 2;
879 flags = getbeuint16(data);
868 flags = getbeuint16(data);
880 data += 2;
869 data += 2;
881
870
882 if (flags & USING_SHA_256) {
871 if (flags & USING_SHA_256) {
883 hashwidth = 32;
872 hashwidth = 32;
884 }
873 }
885
874
886 nsuccs = (unsigned char)(*data++);
875 nsuccs = (unsigned char)(*data++);
887 nparents = (unsigned char)(*data++);
876 nparents = (unsigned char)(*data++);
888 nmetadata = (unsigned char)(*data++);
877 nmetadata = (unsigned char)(*data++);
889
878
890 if (databegin + *msize > dataend) {
879 if (databegin + *msize > dataend) {
891 goto overflow;
880 goto overflow;
892 }
881 }
893 dataend = databegin + *msize; /* narrow down to marker size */
882 dataend = databegin + *msize; /* narrow down to marker size */
894
883
895 if (data + hashwidth > dataend) {
884 if (data + hashwidth > dataend) {
896 goto overflow;
885 goto overflow;
897 }
886 }
898 prec = PyBytes_FromStringAndSize(data, hashwidth);
887 prec = PyBytes_FromStringAndSize(data, hashwidth);
899 data += hashwidth;
888 data += hashwidth;
900 if (prec == NULL) {
889 if (prec == NULL) {
901 goto bail;
890 goto bail;
902 }
891 }
903
892
904 if (data + nsuccs * hashwidth > dataend) {
893 if (data + nsuccs * hashwidth > dataend) {
905 goto overflow;
894 goto overflow;
906 }
895 }
907 succs = readshas(data, nsuccs, hashwidth);
896 succs = readshas(data, nsuccs, hashwidth);
908 if (succs == NULL) {
897 if (succs == NULL) {
909 goto bail;
898 goto bail;
910 }
899 }
911 data += nsuccs * hashwidth;
900 data += nsuccs * hashwidth;
912
901
913 if (nparents == 1 || nparents == 2) {
902 if (nparents == 1 || nparents == 2) {
914 if (data + nparents * hashwidth > dataend) {
903 if (data + nparents * hashwidth > dataend) {
915 goto overflow;
904 goto overflow;
916 }
905 }
917 parents = readshas(data, nparents, hashwidth);
906 parents = readshas(data, nparents, hashwidth);
918 if (parents == NULL) {
907 if (parents == NULL) {
919 goto bail;
908 goto bail;
920 }
909 }
921 data += nparents * hashwidth;
910 data += nparents * hashwidth;
922 } else {
911 } else {
923 parents = Py_None;
912 parents = Py_None;
924 Py_INCREF(parents);
913 Py_INCREF(parents);
925 }
914 }
926
915
927 if (data + 2 * nmetadata > dataend) {
916 if (data + 2 * nmetadata > dataend) {
928 goto overflow;
917 goto overflow;
929 }
918 }
930 meta = data + (2 * nmetadata);
919 meta = data + (2 * nmetadata);
931 metadata = PyTuple_New(nmetadata);
920 metadata = PyTuple_New(nmetadata);
932 if (metadata == NULL) {
921 if (metadata == NULL) {
933 goto bail;
922 goto bail;
934 }
923 }
935 for (i = 0; i < nmetadata; i++) {
924 for (i = 0; i < nmetadata; i++) {
936 PyObject *tmp, *left = NULL, *right = NULL;
925 PyObject *tmp, *left = NULL, *right = NULL;
937 Py_ssize_t leftsize = (unsigned char)(*data++);
926 Py_ssize_t leftsize = (unsigned char)(*data++);
938 Py_ssize_t rightsize = (unsigned char)(*data++);
927 Py_ssize_t rightsize = (unsigned char)(*data++);
939 if (meta + leftsize + rightsize > dataend) {
928 if (meta + leftsize + rightsize > dataend) {
940 goto overflow;
929 goto overflow;
941 }
930 }
942 left = PyBytes_FromStringAndSize(meta, leftsize);
931 left = PyBytes_FromStringAndSize(meta, leftsize);
943 meta += leftsize;
932 meta += leftsize;
944 right = PyBytes_FromStringAndSize(meta, rightsize);
933 right = PyBytes_FromStringAndSize(meta, rightsize);
945 meta += rightsize;
934 meta += rightsize;
946 tmp = PyTuple_New(2);
935 tmp = PyTuple_New(2);
947 if (!left || !right || !tmp) {
936 if (!left || !right || !tmp) {
948 Py_XDECREF(left);
937 Py_XDECREF(left);
949 Py_XDECREF(right);
938 Py_XDECREF(right);
950 Py_XDECREF(tmp);
939 Py_XDECREF(tmp);
951 goto bail;
940 goto bail;
952 }
941 }
953 PyTuple_SET_ITEM(tmp, 0, left);
942 PyTuple_SET_ITEM(tmp, 0, left);
954 PyTuple_SET_ITEM(tmp, 1, right);
943 PyTuple_SET_ITEM(tmp, 1, right);
955 PyTuple_SET_ITEM(metadata, i, tmp);
944 PyTuple_SET_ITEM(metadata, i, tmp);
956 }
945 }
957 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
946 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
958 (int)tz * 60, parents);
947 (int)tz * 60, parents);
959 goto bail; /* return successfully */
948 goto bail; /* return successfully */
960
949
961 overflow:
950 overflow:
962 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
951 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
963 bail:
952 bail:
964 Py_XDECREF(prec);
953 Py_XDECREF(prec);
965 Py_XDECREF(succs);
954 Py_XDECREF(succs);
966 Py_XDECREF(metadata);
955 Py_XDECREF(metadata);
967 Py_XDECREF(parents);
956 Py_XDECREF(parents);
968 return ret;
957 return ret;
969 }
958 }
970
959
971 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
960 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
972 {
961 {
973 const char *data, *dataend;
962 const char *data, *dataend;
974 Py_ssize_t datalen, offset, stop;
963 Py_ssize_t datalen, offset, stop;
975 PyObject *markers = NULL;
964 PyObject *markers = NULL;
976
965
977 if (!PyArg_ParseTuple(args, PY23("s#nn", "y#nn"), &data, &datalen,
966 if (!PyArg_ParseTuple(args, PY23("s#nn", "y#nn"), &data, &datalen,
978 &offset, &stop)) {
967 &offset, &stop)) {
979 return NULL;
968 return NULL;
980 }
969 }
981 if (offset < 0) {
970 if (offset < 0) {
982 PyErr_SetString(PyExc_ValueError,
971 PyErr_SetString(PyExc_ValueError,
983 "invalid negative offset in fm1readmarkers");
972 "invalid negative offset in fm1readmarkers");
984 return NULL;
973 return NULL;
985 }
974 }
986 if (stop > datalen) {
975 if (stop > datalen) {
987 PyErr_SetString(
976 PyErr_SetString(
988 PyExc_ValueError,
977 PyExc_ValueError,
989 "stop longer than data length in fm1readmarkers");
978 "stop longer than data length in fm1readmarkers");
990 return NULL;
979 return NULL;
991 }
980 }
992 dataend = data + datalen;
981 dataend = data + datalen;
993 data += offset;
982 data += offset;
994 markers = PyList_New(0);
983 markers = PyList_New(0);
995 if (!markers) {
984 if (!markers) {
996 return NULL;
985 return NULL;
997 }
986 }
998 while (offset < stop) {
987 while (offset < stop) {
999 uint32_t msize;
988 uint32_t msize;
1000 int error;
989 int error;
1001 PyObject *record = fm1readmarker(data, dataend, &msize);
990 PyObject *record = fm1readmarker(data, dataend, &msize);
1002 if (!record) {
991 if (!record) {
1003 goto bail;
992 goto bail;
1004 }
993 }
1005 error = PyList_Append(markers, record);
994 error = PyList_Append(markers, record);
1006 Py_DECREF(record);
995 Py_DECREF(record);
1007 if (error) {
996 if (error) {
1008 goto bail;
997 goto bail;
1009 }
998 }
1010 data += msize;
999 data += msize;
1011 offset += msize;
1000 offset += msize;
1012 }
1001 }
1013 return markers;
1002 return markers;
1014 bail:
1003 bail:
1015 Py_DECREF(markers);
1004 Py_DECREF(markers);
1016 return NULL;
1005 return NULL;
1017 }
1006 }
1018
1007
1019 static char parsers_doc[] = "Efficient content parsing.";
1008 static char parsers_doc[] = "Efficient content parsing.";
1020
1009
1021 PyObject *encodedir(PyObject *self, PyObject *args);
1010 PyObject *encodedir(PyObject *self, PyObject *args);
1022 PyObject *pathencode(PyObject *self, PyObject *args);
1011 PyObject *pathencode(PyObject *self, PyObject *args);
1023 PyObject *lowerencode(PyObject *self, PyObject *args);
1012 PyObject *lowerencode(PyObject *self, PyObject *args);
1024 PyObject *parse_index2(PyObject *self, PyObject *args, PyObject *kwargs);
1013 PyObject *parse_index2(PyObject *self, PyObject *args, PyObject *kwargs);
1025
1014
1026 static PyMethodDef methods[] = {
1015 static PyMethodDef methods[] = {
1027 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
1016 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
1028 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
1017 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
1029 "create a set containing non-normal and other parent entries of given "
1018 "create a set containing non-normal and other parent entries of given "
1030 "dirstate\n"},
1019 "dirstate\n"},
1031 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1020 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1032 {"parse_index2", (PyCFunction)parse_index2, METH_VARARGS | METH_KEYWORDS,
1021 {"parse_index2", (PyCFunction)parse_index2, METH_VARARGS | METH_KEYWORDS,
1033 "parse a revlog index\n"},
1022 "parse a revlog index\n"},
1034 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
1023 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
1035 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
1024 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
1036 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
1025 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
1037 {"dict_new_presized", dict_new_presized, METH_VARARGS,
1026 {"dict_new_presized", dict_new_presized, METH_VARARGS,
1038 "construct a dict with an expected size\n"},
1027 "construct a dict with an expected size\n"},
1039 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
1028 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
1040 "make file foldmap\n"},
1029 "make file foldmap\n"},
1041 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
1030 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
1042 "escape a UTF-8 byte string to JSON (fast path)\n"},
1031 "escape a UTF-8 byte string to JSON (fast path)\n"},
1043 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
1032 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
1044 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
1033 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
1045 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
1034 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
1046 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
1035 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
1047 "parse v1 obsolete markers\n"},
1036 "parse v1 obsolete markers\n"},
1048 {NULL, NULL}};
1037 {NULL, NULL}};
1049
1038
1050 void dirs_module_init(PyObject *mod);
1039 void dirs_module_init(PyObject *mod);
1051 void manifest_module_init(PyObject *mod);
1040 void manifest_module_init(PyObject *mod);
1052 void revlog_module_init(PyObject *mod);
1041 void revlog_module_init(PyObject *mod);
1053
1042
1054 static const int version = 20;
1043 static const int version = 20;
1055
1044
1056 static void module_init(PyObject *mod)
1045 static void module_init(PyObject *mod)
1057 {
1046 {
1058 PyObject *capsule = NULL;
1047 PyObject *capsule = NULL;
1059 PyModule_AddIntConstant(mod, "version", version);
1048 PyModule_AddIntConstant(mod, "version", version);
1060
1049
1061 /* This module constant has two purposes. First, it lets us unit test
1050 /* This module constant has two purposes. First, it lets us unit test
1062 * the ImportError raised without hard-coding any error text. This
1051 * the ImportError raised without hard-coding any error text. This
1063 * means we can change the text in the future without breaking tests,
1052 * means we can change the text in the future without breaking tests,
1064 * even across changesets without a recompile. Second, its presence
1053 * even across changesets without a recompile. Second, its presence
1065 * can be used to determine whether the version-checking logic is
1054 * can be used to determine whether the version-checking logic is
1066 * present, which also helps in testing across changesets without a
1055 * present, which also helps in testing across changesets without a
1067 * recompile. Note that this means the pure-Python version of parsers
1056 * recompile. Note that this means the pure-Python version of parsers
1068 * should not have this module constant. */
1057 * should not have this module constant. */
1069 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
1058 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
1070
1059
1071 dirs_module_init(mod);
1060 dirs_module_init(mod);
1072 manifest_module_init(mod);
1061 manifest_module_init(mod);
1073 revlog_module_init(mod);
1062 revlog_module_init(mod);
1074
1063
1075 capsule = PyCapsule_New(
1064 capsule = PyCapsule_New(
1076 dirstate_item_from_v1_data,
1065 dirstate_item_from_v1_data,
1077 "mercurial.cext.parsers.make_dirstate_item_CAPI", NULL);
1066 "mercurial.cext.parsers.make_dirstate_item_CAPI", NULL);
1078 if (capsule != NULL)
1067 if (capsule != NULL)
1079 PyModule_AddObject(mod, "make_dirstate_item_CAPI", capsule);
1068 PyModule_AddObject(mod, "make_dirstate_item_CAPI", capsule);
1080
1069
1081 if (PyType_Ready(&dirstateItemType) < 0) {
1070 if (PyType_Ready(&dirstateItemType) < 0) {
1082 return;
1071 return;
1083 }
1072 }
1084 Py_INCREF(&dirstateItemType);
1073 Py_INCREF(&dirstateItemType);
1085 PyModule_AddObject(mod, "DirstateItem", (PyObject *)&dirstateItemType);
1074 PyModule_AddObject(mod, "DirstateItem", (PyObject *)&dirstateItemType);
1086 }
1075 }
1087
1076
1088 static int check_python_version(void)
1077 static int check_python_version(void)
1089 {
1078 {
1090 PyObject *sys = PyImport_ImportModule("sys"), *ver;
1079 PyObject *sys = PyImport_ImportModule("sys"), *ver;
1091 long hexversion;
1080 long hexversion;
1092 if (!sys) {
1081 if (!sys) {
1093 return -1;
1082 return -1;
1094 }
1083 }
1095 ver = PyObject_GetAttrString(sys, "hexversion");
1084 ver = PyObject_GetAttrString(sys, "hexversion");
1096 Py_DECREF(sys);
1085 Py_DECREF(sys);
1097 if (!ver) {
1086 if (!ver) {
1098 return -1;
1087 return -1;
1099 }
1088 }
1100 hexversion = PyInt_AsLong(ver);
1089 hexversion = PyInt_AsLong(ver);
1101 Py_DECREF(ver);
1090 Py_DECREF(ver);
1102 /* sys.hexversion is a 32-bit number by default, so the -1 case
1091 /* sys.hexversion is a 32-bit number by default, so the -1 case
1103 * should only occur in unusual circumstances (e.g. if sys.hexversion
1092 * should only occur in unusual circumstances (e.g. if sys.hexversion
1104 * is manually set to an invalid value). */
1093 * is manually set to an invalid value). */
1105 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
1094 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
1106 PyErr_Format(PyExc_ImportError,
1095 PyErr_Format(PyExc_ImportError,
1107 "%s: The Mercurial extension "
1096 "%s: The Mercurial extension "
1108 "modules were compiled with Python " PY_VERSION
1097 "modules were compiled with Python " PY_VERSION
1109 ", but "
1098 ", but "
1110 "Mercurial is currently using Python with "
1099 "Mercurial is currently using Python with "
1111 "sys.hexversion=%ld: "
1100 "sys.hexversion=%ld: "
1112 "Python %s\n at: %s",
1101 "Python %s\n at: %s",
1113 versionerrortext, hexversion, Py_GetVersion(),
1102 versionerrortext, hexversion, Py_GetVersion(),
1114 Py_GetProgramFullPath());
1103 Py_GetProgramFullPath());
1115 return -1;
1104 return -1;
1116 }
1105 }
1117 return 0;
1106 return 0;
1118 }
1107 }
1119
1108
1120 #ifdef IS_PY3K
1109 #ifdef IS_PY3K
1121 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
1110 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
1122 parsers_doc, -1, methods};
1111 parsers_doc, -1, methods};
1123
1112
1124 PyMODINIT_FUNC PyInit_parsers(void)
1113 PyMODINIT_FUNC PyInit_parsers(void)
1125 {
1114 {
1126 PyObject *mod;
1115 PyObject *mod;
1127
1116
1128 if (check_python_version() == -1)
1117 if (check_python_version() == -1)
1129 return NULL;
1118 return NULL;
1130 mod = PyModule_Create(&parsers_module);
1119 mod = PyModule_Create(&parsers_module);
1131 module_init(mod);
1120 module_init(mod);
1132 return mod;
1121 return mod;
1133 }
1122 }
1134 #else
1123 #else
1135 PyMODINIT_FUNC initparsers(void)
1124 PyMODINIT_FUNC initparsers(void)
1136 {
1125 {
1137 PyObject *mod;
1126 PyObject *mod;
1138
1127
1139 if (check_python_version() == -1) {
1128 if (check_python_version() == -1) {
1140 return;
1129 return;
1141 }
1130 }
1142 mod = Py_InitModule3("parsers", methods, parsers_doc);
1131 mod = Py_InitModule3("parsers", methods, parsers_doc);
1143 module_init(mod);
1132 module_init(mod);
1144 }
1133 }
1145 #endif
1134 #endif
General Comments 0
You need to be logged in to leave comments. Login now