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