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