##// END OF EJS Templates
cext: increment the `parsers` module version...
Boris Feld -
r40744:f2342483 default
parent child Browse files
Show More
@@ -1,797 +1,797 b''
1 /*
1 /*
2 parsers.c - efficient content parsing
2 parsers.c - efficient content parsing
3
3
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
4 Copyright 2008 Matt Mackall <mpm@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 #include <Python.h>
10 #include <Python.h>
11 #include <ctype.h>
11 #include <ctype.h>
12 #include <stddef.h>
12 #include <stddef.h>
13 #include <string.h>
13 #include <string.h>
14
14
15 #include "bitmanipulation.h"
15 #include "bitmanipulation.h"
16 #include "charencode.h"
16 #include "charencode.h"
17 #include "util.h"
17 #include "util.h"
18
18
19 #ifdef IS_PY3K
19 #ifdef IS_PY3K
20 /* The mapping of Python types is meant to be temporary to get Python
20 /* The mapping of Python types is meant to be temporary to get Python
21 * 3 to compile. We should remove this once Python 3 support is fully
21 * 3 to compile. We should remove this once Python 3 support is fully
22 * supported and proper types are used in the extensions themselves. */
22 * supported and proper types are used in the extensions themselves. */
23 #define PyInt_Check PyLong_Check
23 #define PyInt_Check PyLong_Check
24 #define PyInt_FromLong PyLong_FromLong
24 #define PyInt_FromLong PyLong_FromLong
25 #define PyInt_FromSsize_t PyLong_FromSsize_t
25 #define PyInt_FromSsize_t PyLong_FromSsize_t
26 #define PyInt_AsLong PyLong_AsLong
26 #define PyInt_AsLong PyLong_AsLong
27 #endif
27 #endif
28
28
29 static const char *const versionerrortext = "Python minor version mismatch";
29 static const char *const versionerrortext = "Python minor version mismatch";
30
30
31 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
31 static PyObject *dict_new_presized(PyObject *self, PyObject *args)
32 {
32 {
33 Py_ssize_t expected_size;
33 Py_ssize_t expected_size;
34
34
35 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size))
35 if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size))
36 return NULL;
36 return NULL;
37
37
38 return _dict_new_presized(expected_size);
38 return _dict_new_presized(expected_size);
39 }
39 }
40
40
41 /*
41 /*
42 * This code assumes that a manifest is stitched together with newline
42 * This code assumes that a manifest is stitched together with newline
43 * ('\n') characters.
43 * ('\n') characters.
44 */
44 */
45 static PyObject *parse_manifest(PyObject *self, PyObject *args)
45 static PyObject *parse_manifest(PyObject *self, PyObject *args)
46 {
46 {
47 PyObject *mfdict, *fdict;
47 PyObject *mfdict, *fdict;
48 char *str, *start, *end;
48 char *str, *start, *end;
49 int len;
49 int len;
50
50
51 if (!PyArg_ParseTuple(
51 if (!PyArg_ParseTuple(
52 args, PY23("O!O!s#:parse_manifest", "O!O!y#:parse_manifest"),
52 args, PY23("O!O!s#:parse_manifest", "O!O!y#:parse_manifest"),
53 &PyDict_Type, &mfdict, &PyDict_Type, &fdict, &str, &len))
53 &PyDict_Type, &mfdict, &PyDict_Type, &fdict, &str, &len))
54 goto quit;
54 goto quit;
55
55
56 start = str;
56 start = str;
57 end = str + len;
57 end = str + len;
58 while (start < end) {
58 while (start < end) {
59 PyObject *file = NULL, *node = NULL;
59 PyObject *file = NULL, *node = NULL;
60 PyObject *flags = NULL;
60 PyObject *flags = NULL;
61 char *zero = NULL, *newline = NULL;
61 char *zero = NULL, *newline = NULL;
62 ptrdiff_t nlen;
62 ptrdiff_t nlen;
63
63
64 zero = memchr(start, '\0', end - start);
64 zero = memchr(start, '\0', end - start);
65 if (!zero) {
65 if (!zero) {
66 PyErr_SetString(PyExc_ValueError,
66 PyErr_SetString(PyExc_ValueError,
67 "manifest entry has no separator");
67 "manifest entry has no separator");
68 goto quit;
68 goto quit;
69 }
69 }
70
70
71 newline = memchr(zero + 1, '\n', end - (zero + 1));
71 newline = memchr(zero + 1, '\n', end - (zero + 1));
72 if (!newline) {
72 if (!newline) {
73 PyErr_SetString(PyExc_ValueError,
73 PyErr_SetString(PyExc_ValueError,
74 "manifest contains trailing garbage");
74 "manifest contains trailing garbage");
75 goto quit;
75 goto quit;
76 }
76 }
77
77
78 file = PyBytes_FromStringAndSize(start, zero - start);
78 file = PyBytes_FromStringAndSize(start, zero - start);
79
79
80 if (!file)
80 if (!file)
81 goto bail;
81 goto bail;
82
82
83 nlen = newline - zero - 1;
83 nlen = newline - zero - 1;
84
84
85 node = unhexlify(zero + 1, nlen > 40 ? 40 : (Py_ssize_t)nlen);
85 node = unhexlify(zero + 1, nlen > 40 ? 40 : (Py_ssize_t)nlen);
86 if (!node)
86 if (!node)
87 goto bail;
87 goto bail;
88
88
89 if (nlen > 40) {
89 if (nlen > 40) {
90 flags = PyBytes_FromStringAndSize(zero + 41, nlen - 40);
90 flags = PyBytes_FromStringAndSize(zero + 41, nlen - 40);
91 if (!flags)
91 if (!flags)
92 goto bail;
92 goto bail;
93
93
94 if (PyDict_SetItem(fdict, file, flags) == -1)
94 if (PyDict_SetItem(fdict, file, flags) == -1)
95 goto bail;
95 goto bail;
96 }
96 }
97
97
98 if (PyDict_SetItem(mfdict, file, node) == -1)
98 if (PyDict_SetItem(mfdict, file, node) == -1)
99 goto bail;
99 goto bail;
100
100
101 start = newline + 1;
101 start = newline + 1;
102
102
103 Py_XDECREF(flags);
103 Py_XDECREF(flags);
104 Py_XDECREF(node);
104 Py_XDECREF(node);
105 Py_XDECREF(file);
105 Py_XDECREF(file);
106 continue;
106 continue;
107 bail:
107 bail:
108 Py_XDECREF(flags);
108 Py_XDECREF(flags);
109 Py_XDECREF(node);
109 Py_XDECREF(node);
110 Py_XDECREF(file);
110 Py_XDECREF(file);
111 goto quit;
111 goto quit;
112 }
112 }
113
113
114 Py_INCREF(Py_None);
114 Py_INCREF(Py_None);
115 return Py_None;
115 return Py_None;
116 quit:
116 quit:
117 return NULL;
117 return NULL;
118 }
118 }
119
119
120 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
120 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
121 int size, int mtime)
121 int size, int mtime)
122 {
122 {
123 dirstateTupleObject *t =
123 dirstateTupleObject *t =
124 PyObject_New(dirstateTupleObject, &dirstateTupleType);
124 PyObject_New(dirstateTupleObject, &dirstateTupleType);
125 if (!t)
125 if (!t)
126 return NULL;
126 return NULL;
127 t->state = state;
127 t->state = state;
128 t->mode = mode;
128 t->mode = mode;
129 t->size = size;
129 t->size = size;
130 t->mtime = mtime;
130 t->mtime = mtime;
131 return t;
131 return t;
132 }
132 }
133
133
134 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
134 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
135 PyObject *kwds)
135 PyObject *kwds)
136 {
136 {
137 /* We do all the initialization here and not a tp_init function because
137 /* We do all the initialization here and not a tp_init function because
138 * dirstate_tuple is immutable. */
138 * dirstate_tuple is immutable. */
139 dirstateTupleObject *t;
139 dirstateTupleObject *t;
140 char state;
140 char state;
141 int size, mode, mtime;
141 int size, mode, mtime;
142 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
142 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
143 return NULL;
143 return NULL;
144
144
145 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
145 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
146 if (!t)
146 if (!t)
147 return NULL;
147 return NULL;
148 t->state = state;
148 t->state = state;
149 t->mode = mode;
149 t->mode = mode;
150 t->size = size;
150 t->size = size;
151 t->mtime = mtime;
151 t->mtime = mtime;
152
152
153 return (PyObject *)t;
153 return (PyObject *)t;
154 }
154 }
155
155
156 static void dirstate_tuple_dealloc(PyObject *o)
156 static void dirstate_tuple_dealloc(PyObject *o)
157 {
157 {
158 PyObject_Del(o);
158 PyObject_Del(o);
159 }
159 }
160
160
161 static Py_ssize_t dirstate_tuple_length(PyObject *o)
161 static Py_ssize_t dirstate_tuple_length(PyObject *o)
162 {
162 {
163 return 4;
163 return 4;
164 }
164 }
165
165
166 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
166 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
167 {
167 {
168 dirstateTupleObject *t = (dirstateTupleObject *)o;
168 dirstateTupleObject *t = (dirstateTupleObject *)o;
169 switch (i) {
169 switch (i) {
170 case 0:
170 case 0:
171 return PyBytes_FromStringAndSize(&t->state, 1);
171 return PyBytes_FromStringAndSize(&t->state, 1);
172 case 1:
172 case 1:
173 return PyInt_FromLong(t->mode);
173 return PyInt_FromLong(t->mode);
174 case 2:
174 case 2:
175 return PyInt_FromLong(t->size);
175 return PyInt_FromLong(t->size);
176 case 3:
176 case 3:
177 return PyInt_FromLong(t->mtime);
177 return PyInt_FromLong(t->mtime);
178 default:
178 default:
179 PyErr_SetString(PyExc_IndexError, "index out of range");
179 PyErr_SetString(PyExc_IndexError, "index out of range");
180 return NULL;
180 return NULL;
181 }
181 }
182 }
182 }
183
183
184 static PySequenceMethods dirstate_tuple_sq = {
184 static PySequenceMethods dirstate_tuple_sq = {
185 dirstate_tuple_length, /* sq_length */
185 dirstate_tuple_length, /* sq_length */
186 0, /* sq_concat */
186 0, /* sq_concat */
187 0, /* sq_repeat */
187 0, /* sq_repeat */
188 dirstate_tuple_item, /* sq_item */
188 dirstate_tuple_item, /* sq_item */
189 0, /* sq_ass_item */
189 0, /* sq_ass_item */
190 0, /* sq_contains */
190 0, /* sq_contains */
191 0, /* sq_inplace_concat */
191 0, /* sq_inplace_concat */
192 0 /* sq_inplace_repeat */
192 0 /* sq_inplace_repeat */
193 };
193 };
194
194
195 PyTypeObject dirstateTupleType = {
195 PyTypeObject dirstateTupleType = {
196 PyVarObject_HEAD_INIT(NULL, 0) /* header */
196 PyVarObject_HEAD_INIT(NULL, 0) /* header */
197 "dirstate_tuple", /* tp_name */
197 "dirstate_tuple", /* tp_name */
198 sizeof(dirstateTupleObject), /* tp_basicsize */
198 sizeof(dirstateTupleObject), /* tp_basicsize */
199 0, /* tp_itemsize */
199 0, /* tp_itemsize */
200 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
200 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
201 0, /* tp_print */
201 0, /* tp_print */
202 0, /* tp_getattr */
202 0, /* tp_getattr */
203 0, /* tp_setattr */
203 0, /* tp_setattr */
204 0, /* tp_compare */
204 0, /* tp_compare */
205 0, /* tp_repr */
205 0, /* tp_repr */
206 0, /* tp_as_number */
206 0, /* tp_as_number */
207 &dirstate_tuple_sq, /* tp_as_sequence */
207 &dirstate_tuple_sq, /* tp_as_sequence */
208 0, /* tp_as_mapping */
208 0, /* tp_as_mapping */
209 0, /* tp_hash */
209 0, /* tp_hash */
210 0, /* tp_call */
210 0, /* tp_call */
211 0, /* tp_str */
211 0, /* tp_str */
212 0, /* tp_getattro */
212 0, /* tp_getattro */
213 0, /* tp_setattro */
213 0, /* tp_setattro */
214 0, /* tp_as_buffer */
214 0, /* tp_as_buffer */
215 Py_TPFLAGS_DEFAULT, /* tp_flags */
215 Py_TPFLAGS_DEFAULT, /* tp_flags */
216 "dirstate tuple", /* tp_doc */
216 "dirstate tuple", /* tp_doc */
217 0, /* tp_traverse */
217 0, /* tp_traverse */
218 0, /* tp_clear */
218 0, /* tp_clear */
219 0, /* tp_richcompare */
219 0, /* tp_richcompare */
220 0, /* tp_weaklistoffset */
220 0, /* tp_weaklistoffset */
221 0, /* tp_iter */
221 0, /* tp_iter */
222 0, /* tp_iternext */
222 0, /* tp_iternext */
223 0, /* tp_methods */
223 0, /* tp_methods */
224 0, /* tp_members */
224 0, /* tp_members */
225 0, /* tp_getset */
225 0, /* tp_getset */
226 0, /* tp_base */
226 0, /* tp_base */
227 0, /* tp_dict */
227 0, /* tp_dict */
228 0, /* tp_descr_get */
228 0, /* tp_descr_get */
229 0, /* tp_descr_set */
229 0, /* tp_descr_set */
230 0, /* tp_dictoffset */
230 0, /* tp_dictoffset */
231 0, /* tp_init */
231 0, /* tp_init */
232 0, /* tp_alloc */
232 0, /* tp_alloc */
233 dirstate_tuple_new, /* tp_new */
233 dirstate_tuple_new, /* tp_new */
234 };
234 };
235
235
236 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
236 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
237 {
237 {
238 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
238 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
239 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
239 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
240 char state, *cur, *str, *cpos;
240 char state, *cur, *str, *cpos;
241 int mode, size, mtime;
241 int mode, size, mtime;
242 unsigned int flen, len, pos = 40;
242 unsigned int flen, len, pos = 40;
243 int readlen;
243 int readlen;
244
244
245 if (!PyArg_ParseTuple(
245 if (!PyArg_ParseTuple(
246 args, PY23("O!O!s#:parse_dirstate", "O!O!y#:parse_dirstate"),
246 args, PY23("O!O!s#:parse_dirstate", "O!O!y#:parse_dirstate"),
247 &PyDict_Type, &dmap, &PyDict_Type, &cmap, &str, &readlen))
247 &PyDict_Type, &dmap, &PyDict_Type, &cmap, &str, &readlen))
248 goto quit;
248 goto quit;
249
249
250 len = readlen;
250 len = readlen;
251
251
252 /* read parents */
252 /* read parents */
253 if (len < 40) {
253 if (len < 40) {
254 PyErr_SetString(PyExc_ValueError,
254 PyErr_SetString(PyExc_ValueError,
255 "too little data for parents");
255 "too little data for parents");
256 goto quit;
256 goto quit;
257 }
257 }
258
258
259 parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, 20, str + 20, 20);
259 parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, 20, str + 20, 20);
260 if (!parents)
260 if (!parents)
261 goto quit;
261 goto quit;
262
262
263 /* read filenames */
263 /* read filenames */
264 while (pos >= 40 && pos < len) {
264 while (pos >= 40 && pos < len) {
265 if (pos + 17 > len) {
265 if (pos + 17 > len) {
266 PyErr_SetString(PyExc_ValueError,
266 PyErr_SetString(PyExc_ValueError,
267 "overflow in dirstate");
267 "overflow in dirstate");
268 goto quit;
268 goto quit;
269 }
269 }
270 cur = str + pos;
270 cur = str + pos;
271 /* unpack header */
271 /* unpack header */
272 state = *cur;
272 state = *cur;
273 mode = getbe32(cur + 1);
273 mode = getbe32(cur + 1);
274 size = getbe32(cur + 5);
274 size = getbe32(cur + 5);
275 mtime = getbe32(cur + 9);
275 mtime = getbe32(cur + 9);
276 flen = getbe32(cur + 13);
276 flen = getbe32(cur + 13);
277 pos += 17;
277 pos += 17;
278 cur += 17;
278 cur += 17;
279 if (flen > len - pos) {
279 if (flen > len - pos) {
280 PyErr_SetString(PyExc_ValueError,
280 PyErr_SetString(PyExc_ValueError,
281 "overflow in dirstate");
281 "overflow in dirstate");
282 goto quit;
282 goto quit;
283 }
283 }
284
284
285 entry =
285 entry =
286 (PyObject *)make_dirstate_tuple(state, mode, size, mtime);
286 (PyObject *)make_dirstate_tuple(state, mode, size, mtime);
287 cpos = memchr(cur, 0, flen);
287 cpos = memchr(cur, 0, flen);
288 if (cpos) {
288 if (cpos) {
289 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
289 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
290 cname = PyBytes_FromStringAndSize(
290 cname = PyBytes_FromStringAndSize(
291 cpos + 1, flen - (cpos - cur) - 1);
291 cpos + 1, flen - (cpos - cur) - 1);
292 if (!fname || !cname ||
292 if (!fname || !cname ||
293 PyDict_SetItem(cmap, fname, cname) == -1 ||
293 PyDict_SetItem(cmap, fname, cname) == -1 ||
294 PyDict_SetItem(dmap, fname, entry) == -1)
294 PyDict_SetItem(dmap, fname, entry) == -1)
295 goto quit;
295 goto quit;
296 Py_DECREF(cname);
296 Py_DECREF(cname);
297 } else {
297 } else {
298 fname = PyBytes_FromStringAndSize(cur, flen);
298 fname = PyBytes_FromStringAndSize(cur, flen);
299 if (!fname || PyDict_SetItem(dmap, fname, entry) == -1)
299 if (!fname || PyDict_SetItem(dmap, fname, entry) == -1)
300 goto quit;
300 goto quit;
301 }
301 }
302 Py_DECREF(fname);
302 Py_DECREF(fname);
303 Py_DECREF(entry);
303 Py_DECREF(entry);
304 fname = cname = entry = NULL;
304 fname = cname = entry = NULL;
305 pos += flen;
305 pos += flen;
306 }
306 }
307
307
308 ret = parents;
308 ret = parents;
309 Py_INCREF(ret);
309 Py_INCREF(ret);
310 quit:
310 quit:
311 Py_XDECREF(fname);
311 Py_XDECREF(fname);
312 Py_XDECREF(cname);
312 Py_XDECREF(cname);
313 Py_XDECREF(entry);
313 Py_XDECREF(entry);
314 Py_XDECREF(parents);
314 Py_XDECREF(parents);
315 return ret;
315 return ret;
316 }
316 }
317
317
318 /*
318 /*
319 * Build a set of non-normal and other parent entries from the dirstate dmap
319 * Build a set of non-normal and other parent entries from the dirstate dmap
320 */
320 */
321 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
321 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
322 {
322 {
323 PyObject *dmap, *fname, *v;
323 PyObject *dmap, *fname, *v;
324 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
324 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
325 Py_ssize_t pos;
325 Py_ssize_t pos;
326
326
327 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type, &dmap))
327 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type, &dmap))
328 goto bail;
328 goto bail;
329
329
330 nonnset = PySet_New(NULL);
330 nonnset = PySet_New(NULL);
331 if (nonnset == NULL)
331 if (nonnset == NULL)
332 goto bail;
332 goto bail;
333
333
334 otherpset = PySet_New(NULL);
334 otherpset = PySet_New(NULL);
335 if (otherpset == NULL)
335 if (otherpset == NULL)
336 goto bail;
336 goto bail;
337
337
338 pos = 0;
338 pos = 0;
339 while (PyDict_Next(dmap, &pos, &fname, &v)) {
339 while (PyDict_Next(dmap, &pos, &fname, &v)) {
340 dirstateTupleObject *t;
340 dirstateTupleObject *t;
341 if (!dirstate_tuple_check(v)) {
341 if (!dirstate_tuple_check(v)) {
342 PyErr_SetString(PyExc_TypeError,
342 PyErr_SetString(PyExc_TypeError,
343 "expected a dirstate tuple");
343 "expected a dirstate tuple");
344 goto bail;
344 goto bail;
345 }
345 }
346 t = (dirstateTupleObject *)v;
346 t = (dirstateTupleObject *)v;
347
347
348 if (t->state == 'n' && t->size == -2) {
348 if (t->state == 'n' && t->size == -2) {
349 if (PySet_Add(otherpset, fname) == -1) {
349 if (PySet_Add(otherpset, fname) == -1) {
350 goto bail;
350 goto bail;
351 }
351 }
352 }
352 }
353
353
354 if (t->state == 'n' && t->mtime != -1)
354 if (t->state == 'n' && t->mtime != -1)
355 continue;
355 continue;
356 if (PySet_Add(nonnset, fname) == -1)
356 if (PySet_Add(nonnset, fname) == -1)
357 goto bail;
357 goto bail;
358 }
358 }
359
359
360 result = Py_BuildValue("(OO)", nonnset, otherpset);
360 result = Py_BuildValue("(OO)", nonnset, otherpset);
361 if (result == NULL)
361 if (result == NULL)
362 goto bail;
362 goto bail;
363 Py_DECREF(nonnset);
363 Py_DECREF(nonnset);
364 Py_DECREF(otherpset);
364 Py_DECREF(otherpset);
365 return result;
365 return result;
366 bail:
366 bail:
367 Py_XDECREF(nonnset);
367 Py_XDECREF(nonnset);
368 Py_XDECREF(otherpset);
368 Py_XDECREF(otherpset);
369 Py_XDECREF(result);
369 Py_XDECREF(result);
370 return NULL;
370 return NULL;
371 }
371 }
372
372
373 /*
373 /*
374 * Efficiently pack a dirstate object into its on-disk format.
374 * Efficiently pack a dirstate object into its on-disk format.
375 */
375 */
376 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
376 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
377 {
377 {
378 PyObject *packobj = NULL;
378 PyObject *packobj = NULL;
379 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
379 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
380 Py_ssize_t nbytes, pos, l;
380 Py_ssize_t nbytes, pos, l;
381 PyObject *k, *v = NULL, *pn;
381 PyObject *k, *v = NULL, *pn;
382 char *p, *s;
382 char *p, *s;
383 int now;
383 int now;
384
384
385 if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map,
385 if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map,
386 &PyDict_Type, &copymap, &PyTuple_Type, &pl, &now))
386 &PyDict_Type, &copymap, &PyTuple_Type, &pl, &now))
387 return NULL;
387 return NULL;
388
388
389 if (PyTuple_Size(pl) != 2) {
389 if (PyTuple_Size(pl) != 2) {
390 PyErr_SetString(PyExc_TypeError, "expected 2-element tuple");
390 PyErr_SetString(PyExc_TypeError, "expected 2-element tuple");
391 return NULL;
391 return NULL;
392 }
392 }
393
393
394 /* Figure out how much we need to allocate. */
394 /* Figure out how much we need to allocate. */
395 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
395 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
396 PyObject *c;
396 PyObject *c;
397 if (!PyBytes_Check(k)) {
397 if (!PyBytes_Check(k)) {
398 PyErr_SetString(PyExc_TypeError, "expected string key");
398 PyErr_SetString(PyExc_TypeError, "expected string key");
399 goto bail;
399 goto bail;
400 }
400 }
401 nbytes += PyBytes_GET_SIZE(k) + 17;
401 nbytes += PyBytes_GET_SIZE(k) + 17;
402 c = PyDict_GetItem(copymap, k);
402 c = PyDict_GetItem(copymap, k);
403 if (c) {
403 if (c) {
404 if (!PyBytes_Check(c)) {
404 if (!PyBytes_Check(c)) {
405 PyErr_SetString(PyExc_TypeError,
405 PyErr_SetString(PyExc_TypeError,
406 "expected string key");
406 "expected string key");
407 goto bail;
407 goto bail;
408 }
408 }
409 nbytes += PyBytes_GET_SIZE(c) + 1;
409 nbytes += PyBytes_GET_SIZE(c) + 1;
410 }
410 }
411 }
411 }
412
412
413 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
413 packobj = PyBytes_FromStringAndSize(NULL, nbytes);
414 if (packobj == NULL)
414 if (packobj == NULL)
415 goto bail;
415 goto bail;
416
416
417 p = PyBytes_AS_STRING(packobj);
417 p = PyBytes_AS_STRING(packobj);
418
418
419 pn = PyTuple_GET_ITEM(pl, 0);
419 pn = PyTuple_GET_ITEM(pl, 0);
420 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
420 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
421 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
421 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
422 goto bail;
422 goto bail;
423 }
423 }
424 memcpy(p, s, l);
424 memcpy(p, s, l);
425 p += 20;
425 p += 20;
426 pn = PyTuple_GET_ITEM(pl, 1);
426 pn = PyTuple_GET_ITEM(pl, 1);
427 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
427 if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
428 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
428 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
429 goto bail;
429 goto bail;
430 }
430 }
431 memcpy(p, s, l);
431 memcpy(p, s, l);
432 p += 20;
432 p += 20;
433
433
434 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
434 for (pos = 0; PyDict_Next(map, &pos, &k, &v);) {
435 dirstateTupleObject *tuple;
435 dirstateTupleObject *tuple;
436 char state;
436 char state;
437 int mode, size, mtime;
437 int mode, size, mtime;
438 Py_ssize_t len, l;
438 Py_ssize_t len, l;
439 PyObject *o;
439 PyObject *o;
440 char *t;
440 char *t;
441
441
442 if (!dirstate_tuple_check(v)) {
442 if (!dirstate_tuple_check(v)) {
443 PyErr_SetString(PyExc_TypeError,
443 PyErr_SetString(PyExc_TypeError,
444 "expected a dirstate tuple");
444 "expected a dirstate tuple");
445 goto bail;
445 goto bail;
446 }
446 }
447 tuple = (dirstateTupleObject *)v;
447 tuple = (dirstateTupleObject *)v;
448
448
449 state = tuple->state;
449 state = tuple->state;
450 mode = tuple->mode;
450 mode = tuple->mode;
451 size = tuple->size;
451 size = tuple->size;
452 mtime = tuple->mtime;
452 mtime = tuple->mtime;
453 if (state == 'n' && mtime == now) {
453 if (state == 'n' && mtime == now) {
454 /* See pure/parsers.py:pack_dirstate for why we do
454 /* See pure/parsers.py:pack_dirstate for why we do
455 * this. */
455 * this. */
456 mtime = -1;
456 mtime = -1;
457 mtime_unset = (PyObject *)make_dirstate_tuple(
457 mtime_unset = (PyObject *)make_dirstate_tuple(
458 state, mode, size, mtime);
458 state, mode, size, mtime);
459 if (!mtime_unset)
459 if (!mtime_unset)
460 goto bail;
460 goto bail;
461 if (PyDict_SetItem(map, k, mtime_unset) == -1)
461 if (PyDict_SetItem(map, k, mtime_unset) == -1)
462 goto bail;
462 goto bail;
463 Py_DECREF(mtime_unset);
463 Py_DECREF(mtime_unset);
464 mtime_unset = NULL;
464 mtime_unset = NULL;
465 }
465 }
466 *p++ = state;
466 *p++ = state;
467 putbe32((uint32_t)mode, p);
467 putbe32((uint32_t)mode, p);
468 putbe32((uint32_t)size, p + 4);
468 putbe32((uint32_t)size, p + 4);
469 putbe32((uint32_t)mtime, p + 8);
469 putbe32((uint32_t)mtime, p + 8);
470 t = p + 12;
470 t = p + 12;
471 p += 16;
471 p += 16;
472 len = PyBytes_GET_SIZE(k);
472 len = PyBytes_GET_SIZE(k);
473 memcpy(p, PyBytes_AS_STRING(k), len);
473 memcpy(p, PyBytes_AS_STRING(k), len);
474 p += len;
474 p += len;
475 o = PyDict_GetItem(copymap, k);
475 o = PyDict_GetItem(copymap, k);
476 if (o) {
476 if (o) {
477 *p++ = '\0';
477 *p++ = '\0';
478 l = PyBytes_GET_SIZE(o);
478 l = PyBytes_GET_SIZE(o);
479 memcpy(p, PyBytes_AS_STRING(o), l);
479 memcpy(p, PyBytes_AS_STRING(o), l);
480 p += l;
480 p += l;
481 len += l + 1;
481 len += l + 1;
482 }
482 }
483 putbe32((uint32_t)len, t);
483 putbe32((uint32_t)len, t);
484 }
484 }
485
485
486 pos = p - PyBytes_AS_STRING(packobj);
486 pos = p - PyBytes_AS_STRING(packobj);
487 if (pos != nbytes) {
487 if (pos != nbytes) {
488 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
488 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
489 (long)pos, (long)nbytes);
489 (long)pos, (long)nbytes);
490 goto bail;
490 goto bail;
491 }
491 }
492
492
493 return packobj;
493 return packobj;
494 bail:
494 bail:
495 Py_XDECREF(mtime_unset);
495 Py_XDECREF(mtime_unset);
496 Py_XDECREF(packobj);
496 Py_XDECREF(packobj);
497 Py_XDECREF(v);
497 Py_XDECREF(v);
498 return NULL;
498 return NULL;
499 }
499 }
500
500
501 #define BUMPED_FIX 1
501 #define BUMPED_FIX 1
502 #define USING_SHA_256 2
502 #define USING_SHA_256 2
503 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
503 #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1)
504
504
505 static PyObject *readshas(const char *source, unsigned char num,
505 static PyObject *readshas(const char *source, unsigned char num,
506 Py_ssize_t hashwidth)
506 Py_ssize_t hashwidth)
507 {
507 {
508 int i;
508 int i;
509 PyObject *list = PyTuple_New(num);
509 PyObject *list = PyTuple_New(num);
510 if (list == NULL) {
510 if (list == NULL) {
511 return NULL;
511 return NULL;
512 }
512 }
513 for (i = 0; i < num; i++) {
513 for (i = 0; i < num; i++) {
514 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
514 PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth);
515 if (hash == NULL) {
515 if (hash == NULL) {
516 Py_DECREF(list);
516 Py_DECREF(list);
517 return NULL;
517 return NULL;
518 }
518 }
519 PyTuple_SET_ITEM(list, i, hash);
519 PyTuple_SET_ITEM(list, i, hash);
520 source += hashwidth;
520 source += hashwidth;
521 }
521 }
522 return list;
522 return list;
523 }
523 }
524
524
525 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
525 static PyObject *fm1readmarker(const char *databegin, const char *dataend,
526 uint32_t *msize)
526 uint32_t *msize)
527 {
527 {
528 const char *data = databegin;
528 const char *data = databegin;
529 const char *meta;
529 const char *meta;
530
530
531 double mtime;
531 double mtime;
532 int16_t tz;
532 int16_t tz;
533 uint16_t flags;
533 uint16_t flags;
534 unsigned char nsuccs, nparents, nmetadata;
534 unsigned char nsuccs, nparents, nmetadata;
535 Py_ssize_t hashwidth = 20;
535 Py_ssize_t hashwidth = 20;
536
536
537 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
537 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
538 PyObject *metadata = NULL, *ret = NULL;
538 PyObject *metadata = NULL, *ret = NULL;
539 int i;
539 int i;
540
540
541 if (data + FM1_HEADER_SIZE > dataend) {
541 if (data + FM1_HEADER_SIZE > dataend) {
542 goto overflow;
542 goto overflow;
543 }
543 }
544
544
545 *msize = getbe32(data);
545 *msize = getbe32(data);
546 data += 4;
546 data += 4;
547 mtime = getbefloat64(data);
547 mtime = getbefloat64(data);
548 data += 8;
548 data += 8;
549 tz = getbeint16(data);
549 tz = getbeint16(data);
550 data += 2;
550 data += 2;
551 flags = getbeuint16(data);
551 flags = getbeuint16(data);
552 data += 2;
552 data += 2;
553
553
554 if (flags & USING_SHA_256) {
554 if (flags & USING_SHA_256) {
555 hashwidth = 32;
555 hashwidth = 32;
556 }
556 }
557
557
558 nsuccs = (unsigned char)(*data++);
558 nsuccs = (unsigned char)(*data++);
559 nparents = (unsigned char)(*data++);
559 nparents = (unsigned char)(*data++);
560 nmetadata = (unsigned char)(*data++);
560 nmetadata = (unsigned char)(*data++);
561
561
562 if (databegin + *msize > dataend) {
562 if (databegin + *msize > dataend) {
563 goto overflow;
563 goto overflow;
564 }
564 }
565 dataend = databegin + *msize; /* narrow down to marker size */
565 dataend = databegin + *msize; /* narrow down to marker size */
566
566
567 if (data + hashwidth > dataend) {
567 if (data + hashwidth > dataend) {
568 goto overflow;
568 goto overflow;
569 }
569 }
570 prec = PyBytes_FromStringAndSize(data, hashwidth);
570 prec = PyBytes_FromStringAndSize(data, hashwidth);
571 data += hashwidth;
571 data += hashwidth;
572 if (prec == NULL) {
572 if (prec == NULL) {
573 goto bail;
573 goto bail;
574 }
574 }
575
575
576 if (data + nsuccs * hashwidth > dataend) {
576 if (data + nsuccs * hashwidth > dataend) {
577 goto overflow;
577 goto overflow;
578 }
578 }
579 succs = readshas(data, nsuccs, hashwidth);
579 succs = readshas(data, nsuccs, hashwidth);
580 if (succs == NULL) {
580 if (succs == NULL) {
581 goto bail;
581 goto bail;
582 }
582 }
583 data += nsuccs * hashwidth;
583 data += nsuccs * hashwidth;
584
584
585 if (nparents == 1 || nparents == 2) {
585 if (nparents == 1 || nparents == 2) {
586 if (data + nparents * hashwidth > dataend) {
586 if (data + nparents * hashwidth > dataend) {
587 goto overflow;
587 goto overflow;
588 }
588 }
589 parents = readshas(data, nparents, hashwidth);
589 parents = readshas(data, nparents, hashwidth);
590 if (parents == NULL) {
590 if (parents == NULL) {
591 goto bail;
591 goto bail;
592 }
592 }
593 data += nparents * hashwidth;
593 data += nparents * hashwidth;
594 } else {
594 } else {
595 parents = Py_None;
595 parents = Py_None;
596 Py_INCREF(parents);
596 Py_INCREF(parents);
597 }
597 }
598
598
599 if (data + 2 * nmetadata > dataend) {
599 if (data + 2 * nmetadata > dataend) {
600 goto overflow;
600 goto overflow;
601 }
601 }
602 meta = data + (2 * nmetadata);
602 meta = data + (2 * nmetadata);
603 metadata = PyTuple_New(nmetadata);
603 metadata = PyTuple_New(nmetadata);
604 if (metadata == NULL) {
604 if (metadata == NULL) {
605 goto bail;
605 goto bail;
606 }
606 }
607 for (i = 0; i < nmetadata; i++) {
607 for (i = 0; i < nmetadata; i++) {
608 PyObject *tmp, *left = NULL, *right = NULL;
608 PyObject *tmp, *left = NULL, *right = NULL;
609 Py_ssize_t leftsize = (unsigned char)(*data++);
609 Py_ssize_t leftsize = (unsigned char)(*data++);
610 Py_ssize_t rightsize = (unsigned char)(*data++);
610 Py_ssize_t rightsize = (unsigned char)(*data++);
611 if (meta + leftsize + rightsize > dataend) {
611 if (meta + leftsize + rightsize > dataend) {
612 goto overflow;
612 goto overflow;
613 }
613 }
614 left = PyBytes_FromStringAndSize(meta, leftsize);
614 left = PyBytes_FromStringAndSize(meta, leftsize);
615 meta += leftsize;
615 meta += leftsize;
616 right = PyBytes_FromStringAndSize(meta, rightsize);
616 right = PyBytes_FromStringAndSize(meta, rightsize);
617 meta += rightsize;
617 meta += rightsize;
618 tmp = PyTuple_New(2);
618 tmp = PyTuple_New(2);
619 if (!left || !right || !tmp) {
619 if (!left || !right || !tmp) {
620 Py_XDECREF(left);
620 Py_XDECREF(left);
621 Py_XDECREF(right);
621 Py_XDECREF(right);
622 Py_XDECREF(tmp);
622 Py_XDECREF(tmp);
623 goto bail;
623 goto bail;
624 }
624 }
625 PyTuple_SET_ITEM(tmp, 0, left);
625 PyTuple_SET_ITEM(tmp, 0, left);
626 PyTuple_SET_ITEM(tmp, 1, right);
626 PyTuple_SET_ITEM(tmp, 1, right);
627 PyTuple_SET_ITEM(metadata, i, tmp);
627 PyTuple_SET_ITEM(metadata, i, tmp);
628 }
628 }
629 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
629 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime,
630 (int)tz * 60, parents);
630 (int)tz * 60, parents);
631 goto bail; /* return successfully */
631 goto bail; /* return successfully */
632
632
633 overflow:
633 overflow:
634 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
634 PyErr_SetString(PyExc_ValueError, "overflow in obsstore");
635 bail:
635 bail:
636 Py_XDECREF(prec);
636 Py_XDECREF(prec);
637 Py_XDECREF(succs);
637 Py_XDECREF(succs);
638 Py_XDECREF(metadata);
638 Py_XDECREF(metadata);
639 Py_XDECREF(parents);
639 Py_XDECREF(parents);
640 return ret;
640 return ret;
641 }
641 }
642
642
643 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
643 static PyObject *fm1readmarkers(PyObject *self, PyObject *args)
644 {
644 {
645 const char *data, *dataend;
645 const char *data, *dataend;
646 int datalen;
646 int datalen;
647 Py_ssize_t offset, stop;
647 Py_ssize_t offset, stop;
648 PyObject *markers = NULL;
648 PyObject *markers = NULL;
649
649
650 if (!PyArg_ParseTuple(args, PY23("s#nn", "y#nn"), &data, &datalen,
650 if (!PyArg_ParseTuple(args, PY23("s#nn", "y#nn"), &data, &datalen,
651 &offset, &stop)) {
651 &offset, &stop)) {
652 return NULL;
652 return NULL;
653 }
653 }
654 dataend = data + datalen;
654 dataend = data + datalen;
655 data += offset;
655 data += offset;
656 markers = PyList_New(0);
656 markers = PyList_New(0);
657 if (!markers) {
657 if (!markers) {
658 return NULL;
658 return NULL;
659 }
659 }
660 while (offset < stop) {
660 while (offset < stop) {
661 uint32_t msize;
661 uint32_t msize;
662 int error;
662 int error;
663 PyObject *record = fm1readmarker(data, dataend, &msize);
663 PyObject *record = fm1readmarker(data, dataend, &msize);
664 if (!record) {
664 if (!record) {
665 goto bail;
665 goto bail;
666 }
666 }
667 error = PyList_Append(markers, record);
667 error = PyList_Append(markers, record);
668 Py_DECREF(record);
668 Py_DECREF(record);
669 if (error) {
669 if (error) {
670 goto bail;
670 goto bail;
671 }
671 }
672 data += msize;
672 data += msize;
673 offset += msize;
673 offset += msize;
674 }
674 }
675 return markers;
675 return markers;
676 bail:
676 bail:
677 Py_DECREF(markers);
677 Py_DECREF(markers);
678 return NULL;
678 return NULL;
679 }
679 }
680
680
681 static char parsers_doc[] = "Efficient content parsing.";
681 static char parsers_doc[] = "Efficient content parsing.";
682
682
683 PyObject *encodedir(PyObject *self, PyObject *args);
683 PyObject *encodedir(PyObject *self, PyObject *args);
684 PyObject *pathencode(PyObject *self, PyObject *args);
684 PyObject *pathencode(PyObject *self, PyObject *args);
685 PyObject *lowerencode(PyObject *self, PyObject *args);
685 PyObject *lowerencode(PyObject *self, PyObject *args);
686 PyObject *parse_index2(PyObject *self, PyObject *args);
686 PyObject *parse_index2(PyObject *self, PyObject *args);
687
687
688 static PyMethodDef methods[] = {
688 static PyMethodDef methods[] = {
689 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
689 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
690 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
690 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
691 "create a set containing non-normal and other parent entries of given "
691 "create a set containing non-normal and other parent entries of given "
692 "dirstate\n"},
692 "dirstate\n"},
693 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
693 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
694 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
694 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
695 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
695 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
696 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
696 {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"},
697 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
697 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
698 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
698 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
699 {"dict_new_presized", dict_new_presized, METH_VARARGS,
699 {"dict_new_presized", dict_new_presized, METH_VARARGS,
700 "construct a dict with an expected size\n"},
700 "construct a dict with an expected size\n"},
701 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
701 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
702 "make file foldmap\n"},
702 "make file foldmap\n"},
703 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
703 {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS,
704 "escape a UTF-8 byte string to JSON (fast path)\n"},
704 "escape a UTF-8 byte string to JSON (fast path)\n"},
705 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
705 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
706 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
706 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
707 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
707 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
708 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
708 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
709 "parse v1 obsolete markers\n"},
709 "parse v1 obsolete markers\n"},
710 {NULL, NULL}};
710 {NULL, NULL}};
711
711
712 void dirs_module_init(PyObject *mod);
712 void dirs_module_init(PyObject *mod);
713 void manifest_module_init(PyObject *mod);
713 void manifest_module_init(PyObject *mod);
714 void revlog_module_init(PyObject *mod);
714 void revlog_module_init(PyObject *mod);
715
715
716 static const int version = 11;
716 static const int version = 12;
717
717
718 static void module_init(PyObject *mod)
718 static void module_init(PyObject *mod)
719 {
719 {
720 PyModule_AddIntConstant(mod, "version", version);
720 PyModule_AddIntConstant(mod, "version", version);
721
721
722 /* This module constant has two purposes. First, it lets us unit test
722 /* This module constant has two purposes. First, it lets us unit test
723 * the ImportError raised without hard-coding any error text. This
723 * the ImportError raised without hard-coding any error text. This
724 * means we can change the text in the future without breaking tests,
724 * means we can change the text in the future without breaking tests,
725 * even across changesets without a recompile. Second, its presence
725 * even across changesets without a recompile. Second, its presence
726 * can be used to determine whether the version-checking logic is
726 * can be used to determine whether the version-checking logic is
727 * present, which also helps in testing across changesets without a
727 * present, which also helps in testing across changesets without a
728 * recompile. Note that this means the pure-Python version of parsers
728 * recompile. Note that this means the pure-Python version of parsers
729 * should not have this module constant. */
729 * should not have this module constant. */
730 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
730 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
731
731
732 dirs_module_init(mod);
732 dirs_module_init(mod);
733 manifest_module_init(mod);
733 manifest_module_init(mod);
734 revlog_module_init(mod);
734 revlog_module_init(mod);
735
735
736 if (PyType_Ready(&dirstateTupleType) < 0)
736 if (PyType_Ready(&dirstateTupleType) < 0)
737 return;
737 return;
738 Py_INCREF(&dirstateTupleType);
738 Py_INCREF(&dirstateTupleType);
739 PyModule_AddObject(mod, "dirstatetuple",
739 PyModule_AddObject(mod, "dirstatetuple",
740 (PyObject *)&dirstateTupleType);
740 (PyObject *)&dirstateTupleType);
741 }
741 }
742
742
743 static int check_python_version(void)
743 static int check_python_version(void)
744 {
744 {
745 PyObject *sys = PyImport_ImportModule("sys"), *ver;
745 PyObject *sys = PyImport_ImportModule("sys"), *ver;
746 long hexversion;
746 long hexversion;
747 if (!sys)
747 if (!sys)
748 return -1;
748 return -1;
749 ver = PyObject_GetAttrString(sys, "hexversion");
749 ver = PyObject_GetAttrString(sys, "hexversion");
750 Py_DECREF(sys);
750 Py_DECREF(sys);
751 if (!ver)
751 if (!ver)
752 return -1;
752 return -1;
753 hexversion = PyInt_AsLong(ver);
753 hexversion = PyInt_AsLong(ver);
754 Py_DECREF(ver);
754 Py_DECREF(ver);
755 /* sys.hexversion is a 32-bit number by default, so the -1 case
755 /* sys.hexversion is a 32-bit number by default, so the -1 case
756 * should only occur in unusual circumstances (e.g. if sys.hexversion
756 * should only occur in unusual circumstances (e.g. if sys.hexversion
757 * is manually set to an invalid value). */
757 * is manually set to an invalid value). */
758 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
758 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
759 PyErr_Format(PyExc_ImportError,
759 PyErr_Format(PyExc_ImportError,
760 "%s: The Mercurial extension "
760 "%s: The Mercurial extension "
761 "modules were compiled with Python " PY_VERSION
761 "modules were compiled with Python " PY_VERSION
762 ", but "
762 ", but "
763 "Mercurial is currently using Python with "
763 "Mercurial is currently using Python with "
764 "sys.hexversion=%ld: "
764 "sys.hexversion=%ld: "
765 "Python %s\n at: %s",
765 "Python %s\n at: %s",
766 versionerrortext, hexversion, Py_GetVersion(),
766 versionerrortext, hexversion, Py_GetVersion(),
767 Py_GetProgramFullPath());
767 Py_GetProgramFullPath());
768 return -1;
768 return -1;
769 }
769 }
770 return 0;
770 return 0;
771 }
771 }
772
772
773 #ifdef IS_PY3K
773 #ifdef IS_PY3K
774 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
774 static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers",
775 parsers_doc, -1, methods};
775 parsers_doc, -1, methods};
776
776
777 PyMODINIT_FUNC PyInit_parsers(void)
777 PyMODINIT_FUNC PyInit_parsers(void)
778 {
778 {
779 PyObject *mod;
779 PyObject *mod;
780
780
781 if (check_python_version() == -1)
781 if (check_python_version() == -1)
782 return NULL;
782 return NULL;
783 mod = PyModule_Create(&parsers_module);
783 mod = PyModule_Create(&parsers_module);
784 module_init(mod);
784 module_init(mod);
785 return mod;
785 return mod;
786 }
786 }
787 #else
787 #else
788 PyMODINIT_FUNC initparsers(void)
788 PyMODINIT_FUNC initparsers(void)
789 {
789 {
790 PyObject *mod;
790 PyObject *mod;
791
791
792 if (check_python_version() == -1)
792 if (check_python_version() == -1)
793 return;
793 return;
794 mod = Py_InitModule3("parsers", methods, parsers_doc);
794 mod = Py_InitModule3("parsers", methods, parsers_doc);
795 module_init(mod);
795 module_init(mod);
796 }
796 }
797 #endif
797 #endif
@@ -1,109 +1,109 b''
1 # policy.py - module policy logic for Mercurial.
1 # policy.py - module policy logic for Mercurial.
2 #
2 #
3 # Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com>
3 # Copyright 2015 Gregory Szorc <gregory.szorc@gmail.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import os
10 import os
11 import sys
11 import sys
12
12
13 # Rules for how modules can be loaded. Values are:
13 # Rules for how modules can be loaded. Values are:
14 #
14 #
15 # c - require C extensions
15 # c - require C extensions
16 # allow - allow pure Python implementation when C loading fails
16 # allow - allow pure Python implementation when C loading fails
17 # cffi - required cffi versions (implemented within pure module)
17 # cffi - required cffi versions (implemented within pure module)
18 # cffi-allow - allow pure Python implementation if cffi version is missing
18 # cffi-allow - allow pure Python implementation if cffi version is missing
19 # py - only load pure Python modules
19 # py - only load pure Python modules
20 #
20 #
21 # By default, fall back to the pure modules so the in-place build can
21 # By default, fall back to the pure modules so the in-place build can
22 # run without recompiling the C extensions. This will be overridden by
22 # run without recompiling the C extensions. This will be overridden by
23 # __modulepolicy__ generated by setup.py.
23 # __modulepolicy__ generated by setup.py.
24 policy = b'allow'
24 policy = b'allow'
25 _packageprefs = {
25 _packageprefs = {
26 # policy: (versioned package, pure package)
26 # policy: (versioned package, pure package)
27 b'c': (r'cext', None),
27 b'c': (r'cext', None),
28 b'allow': (r'cext', r'pure'),
28 b'allow': (r'cext', r'pure'),
29 b'cffi': (r'cffi', None),
29 b'cffi': (r'cffi', None),
30 b'cffi-allow': (r'cffi', r'pure'),
30 b'cffi-allow': (r'cffi', r'pure'),
31 b'py': (None, r'pure'),
31 b'py': (None, r'pure'),
32 }
32 }
33
33
34 try:
34 try:
35 from . import __modulepolicy__
35 from . import __modulepolicy__
36 policy = __modulepolicy__.modulepolicy
36 policy = __modulepolicy__.modulepolicy
37 except ImportError:
37 except ImportError:
38 pass
38 pass
39
39
40 # PyPy doesn't load C extensions.
40 # PyPy doesn't load C extensions.
41 #
41 #
42 # The canonical way to do this is to test platform.python_implementation().
42 # The canonical way to do this is to test platform.python_implementation().
43 # But we don't import platform and don't bloat for it here.
43 # But we don't import platform and don't bloat for it here.
44 if r'__pypy__' in sys.builtin_module_names:
44 if r'__pypy__' in sys.builtin_module_names:
45 policy = b'cffi'
45 policy = b'cffi'
46
46
47 # Environment variable can always force settings.
47 # Environment variable can always force settings.
48 if sys.version_info[0] >= 3:
48 if sys.version_info[0] >= 3:
49 if r'HGMODULEPOLICY' in os.environ:
49 if r'HGMODULEPOLICY' in os.environ:
50 policy = os.environ[r'HGMODULEPOLICY'].encode(r'utf-8')
50 policy = os.environ[r'HGMODULEPOLICY'].encode(r'utf-8')
51 else:
51 else:
52 policy = os.environ.get(r'HGMODULEPOLICY', policy)
52 policy = os.environ.get(r'HGMODULEPOLICY', policy)
53
53
54 def _importfrom(pkgname, modname):
54 def _importfrom(pkgname, modname):
55 # from .<pkgname> import <modname> (where . is looked through this module)
55 # from .<pkgname> import <modname> (where . is looked through this module)
56 fakelocals = {}
56 fakelocals = {}
57 pkg = __import__(pkgname, globals(), fakelocals, [modname], level=1)
57 pkg = __import__(pkgname, globals(), fakelocals, [modname], level=1)
58 try:
58 try:
59 fakelocals[modname] = mod = getattr(pkg, modname)
59 fakelocals[modname] = mod = getattr(pkg, modname)
60 except AttributeError:
60 except AttributeError:
61 raise ImportError(r'cannot import name %s' % modname)
61 raise ImportError(r'cannot import name %s' % modname)
62 # force import; fakelocals[modname] may be replaced with the real module
62 # force import; fakelocals[modname] may be replaced with the real module
63 getattr(mod, r'__doc__', None)
63 getattr(mod, r'__doc__', None)
64 return fakelocals[modname]
64 return fakelocals[modname]
65
65
66 # keep in sync with "version" in C modules
66 # keep in sync with "version" in C modules
67 _cextversions = {
67 _cextversions = {
68 (r'cext', r'base85'): 1,
68 (r'cext', r'base85'): 1,
69 (r'cext', r'bdiff'): 3,
69 (r'cext', r'bdiff'): 3,
70 (r'cext', r'mpatch'): 1,
70 (r'cext', r'mpatch'): 1,
71 (r'cext', r'osutil'): 4,
71 (r'cext', r'osutil'): 4,
72 (r'cext', r'parsers'): 11,
72 (r'cext', r'parsers'): 12,
73 }
73 }
74
74
75 # map import request to other package or module
75 # map import request to other package or module
76 _modredirects = {
76 _modredirects = {
77 (r'cext', r'charencode'): (r'cext', r'parsers'),
77 (r'cext', r'charencode'): (r'cext', r'parsers'),
78 (r'cffi', r'base85'): (r'pure', r'base85'),
78 (r'cffi', r'base85'): (r'pure', r'base85'),
79 (r'cffi', r'charencode'): (r'pure', r'charencode'),
79 (r'cffi', r'charencode'): (r'pure', r'charencode'),
80 (r'cffi', r'parsers'): (r'pure', r'parsers'),
80 (r'cffi', r'parsers'): (r'pure', r'parsers'),
81 }
81 }
82
82
83 def _checkmod(pkgname, modname, mod):
83 def _checkmod(pkgname, modname, mod):
84 expected = _cextversions.get((pkgname, modname))
84 expected = _cextversions.get((pkgname, modname))
85 actual = getattr(mod, r'version', None)
85 actual = getattr(mod, r'version', None)
86 if actual != expected:
86 if actual != expected:
87 raise ImportError(r'cannot import module %s.%s '
87 raise ImportError(r'cannot import module %s.%s '
88 r'(expected version: %d, actual: %r)'
88 r'(expected version: %d, actual: %r)'
89 % (pkgname, modname, expected, actual))
89 % (pkgname, modname, expected, actual))
90
90
91 def importmod(modname):
91 def importmod(modname):
92 """Import module according to policy and check API version"""
92 """Import module according to policy and check API version"""
93 try:
93 try:
94 verpkg, purepkg = _packageprefs[policy]
94 verpkg, purepkg = _packageprefs[policy]
95 except KeyError:
95 except KeyError:
96 raise ImportError(r'invalid HGMODULEPOLICY %r' % policy)
96 raise ImportError(r'invalid HGMODULEPOLICY %r' % policy)
97 assert verpkg or purepkg
97 assert verpkg or purepkg
98 if verpkg:
98 if verpkg:
99 pn, mn = _modredirects.get((verpkg, modname), (verpkg, modname))
99 pn, mn = _modredirects.get((verpkg, modname), (verpkg, modname))
100 try:
100 try:
101 mod = _importfrom(pn, mn)
101 mod = _importfrom(pn, mn)
102 if pn == verpkg:
102 if pn == verpkg:
103 _checkmod(pn, mn, mod)
103 _checkmod(pn, mn, mod)
104 return mod
104 return mod
105 except ImportError:
105 except ImportError:
106 if not purepkg:
106 if not purepkg:
107 raise
107 raise
108 pn, mn = _modredirects.get((purepkg, modname), (purepkg, modname))
108 pn, mn = _modredirects.get((purepkg, modname), (purepkg, modname))
109 return _importfrom(pn, mn)
109 return _importfrom(pn, mn)
General Comments 0
You need to be logged in to leave comments. Login now