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