##// END OF EJS Templates
changelog: fix bug in heads computation...
Laurent Charignon -
r25297:3966e39f default
parent child Browse files
Show More
@@ -1,2686 +1,2648
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 "util.h"
15 #include "util.h"
16
16
17 static char *versionerrortext = "Python minor version mismatch";
17 static char *versionerrortext = "Python minor version mismatch";
18
18
19 static int8_t hextable[256] = {
19 static int8_t hextable[256] = {
20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
23 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
23 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
24 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
24 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
26 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
26 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
27 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
27 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
36 };
36 };
37
37
38 static char lowertable[128] = {
38 static char lowertable[128] = {
39 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
39 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
40 '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
40 '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
41 '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
41 '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
42 '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
42 '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
43 '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
43 '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
44 '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
44 '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
45 '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
45 '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
46 '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
46 '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
47 '\x40',
47 '\x40',
48 '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', /* A-G */
48 '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', /* A-G */
49 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f', /* H-O */
49 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f', /* H-O */
50 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', /* P-W */
50 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', /* P-W */
51 '\x78', '\x79', '\x7a', /* X-Z */
51 '\x78', '\x79', '\x7a', /* X-Z */
52 '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
52 '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
53 '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
53 '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
54 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
54 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
55 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
55 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
56 '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f'
56 '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f'
57 };
57 };
58
58
59 static char uppertable[128] = {
59 static char uppertable[128] = {
60 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
60 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
61 '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
61 '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
62 '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
62 '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
63 '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
63 '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
64 '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
64 '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
65 '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
65 '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
66 '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
66 '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
67 '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
67 '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
68 '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47',
68 '\x40', '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47',
69 '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f',
69 '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f',
70 '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57',
70 '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57',
71 '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
71 '\x58', '\x59', '\x5a', '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
72 '\x60',
72 '\x60',
73 '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47', /* a-g */
73 '\x41', '\x42', '\x43', '\x44', '\x45', '\x46', '\x47', /* a-g */
74 '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f', /* h-o */
74 '\x48', '\x49', '\x4a', '\x4b', '\x4c', '\x4d', '\x4e', '\x4f', /* h-o */
75 '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57', /* p-w */
75 '\x50', '\x51', '\x52', '\x53', '\x54', '\x55', '\x56', '\x57', /* p-w */
76 '\x58', '\x59', '\x5a', /* x-z */
76 '\x58', '\x59', '\x5a', /* x-z */
77 '\x7b', '\x7c', '\x7d', '\x7e', '\x7f'
77 '\x7b', '\x7c', '\x7d', '\x7e', '\x7f'
78 };
78 };
79
79
80 static inline int hexdigit(const char *p, Py_ssize_t off)
80 static inline int hexdigit(const char *p, Py_ssize_t off)
81 {
81 {
82 int8_t val = hextable[(unsigned char)p[off]];
82 int8_t val = hextable[(unsigned char)p[off]];
83
83
84 if (val >= 0) {
84 if (val >= 0) {
85 return val;
85 return val;
86 }
86 }
87
87
88 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
88 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
89 return 0;
89 return 0;
90 }
90 }
91
91
92 /*
92 /*
93 * Turn a hex-encoded string into binary.
93 * Turn a hex-encoded string into binary.
94 */
94 */
95 PyObject *unhexlify(const char *str, int len)
95 PyObject *unhexlify(const char *str, int len)
96 {
96 {
97 PyObject *ret;
97 PyObject *ret;
98 char *d;
98 char *d;
99 int i;
99 int i;
100
100
101 ret = PyBytes_FromStringAndSize(NULL, len / 2);
101 ret = PyBytes_FromStringAndSize(NULL, len / 2);
102
102
103 if (!ret)
103 if (!ret)
104 return NULL;
104 return NULL;
105
105
106 d = PyBytes_AsString(ret);
106 d = PyBytes_AsString(ret);
107
107
108 for (i = 0; i < len;) {
108 for (i = 0; i < len;) {
109 int hi = hexdigit(str, i++);
109 int hi = hexdigit(str, i++);
110 int lo = hexdigit(str, i++);
110 int lo = hexdigit(str, i++);
111 *d++ = (hi << 4) | lo;
111 *d++ = (hi << 4) | lo;
112 }
112 }
113
113
114 return ret;
114 return ret;
115 }
115 }
116
116
117 static inline PyObject *_asciitransform(PyObject *str_obj,
117 static inline PyObject *_asciitransform(PyObject *str_obj,
118 const char table[128],
118 const char table[128],
119 PyObject *fallback_fn)
119 PyObject *fallback_fn)
120 {
120 {
121 char *str, *newstr;
121 char *str, *newstr;
122 Py_ssize_t i, len;
122 Py_ssize_t i, len;
123 PyObject *newobj = NULL;
123 PyObject *newobj = NULL;
124 PyObject *ret = NULL;
124 PyObject *ret = NULL;
125
125
126 str = PyBytes_AS_STRING(str_obj);
126 str = PyBytes_AS_STRING(str_obj);
127 len = PyBytes_GET_SIZE(str_obj);
127 len = PyBytes_GET_SIZE(str_obj);
128
128
129 newobj = PyBytes_FromStringAndSize(NULL, len);
129 newobj = PyBytes_FromStringAndSize(NULL, len);
130 if (!newobj)
130 if (!newobj)
131 goto quit;
131 goto quit;
132
132
133 newstr = PyBytes_AS_STRING(newobj);
133 newstr = PyBytes_AS_STRING(newobj);
134
134
135 for (i = 0; i < len; i++) {
135 for (i = 0; i < len; i++) {
136 char c = str[i];
136 char c = str[i];
137 if (c & 0x80) {
137 if (c & 0x80) {
138 if (fallback_fn != NULL) {
138 if (fallback_fn != NULL) {
139 ret = PyObject_CallFunctionObjArgs(fallback_fn,
139 ret = PyObject_CallFunctionObjArgs(fallback_fn,
140 str_obj, NULL);
140 str_obj, NULL);
141 } else {
141 } else {
142 PyObject *err = PyUnicodeDecodeError_Create(
142 PyObject *err = PyUnicodeDecodeError_Create(
143 "ascii", str, len, i, (i + 1),
143 "ascii", str, len, i, (i + 1),
144 "unexpected code byte");
144 "unexpected code byte");
145 PyErr_SetObject(PyExc_UnicodeDecodeError, err);
145 PyErr_SetObject(PyExc_UnicodeDecodeError, err);
146 Py_XDECREF(err);
146 Py_XDECREF(err);
147 }
147 }
148 goto quit;
148 goto quit;
149 }
149 }
150 newstr[i] = table[(unsigned char)c];
150 newstr[i] = table[(unsigned char)c];
151 }
151 }
152
152
153 ret = newobj;
153 ret = newobj;
154 Py_INCREF(ret);
154 Py_INCREF(ret);
155 quit:
155 quit:
156 Py_XDECREF(newobj);
156 Py_XDECREF(newobj);
157 return ret;
157 return ret;
158 }
158 }
159
159
160 static PyObject *asciilower(PyObject *self, PyObject *args)
160 static PyObject *asciilower(PyObject *self, PyObject *args)
161 {
161 {
162 PyObject *str_obj;
162 PyObject *str_obj;
163 if (!PyArg_ParseTuple(args, "O!:asciilower", &PyBytes_Type, &str_obj))
163 if (!PyArg_ParseTuple(args, "O!:asciilower", &PyBytes_Type, &str_obj))
164 return NULL;
164 return NULL;
165 return _asciitransform(str_obj, lowertable, NULL);
165 return _asciitransform(str_obj, lowertable, NULL);
166 }
166 }
167
167
168 static PyObject *asciiupper(PyObject *self, PyObject *args)
168 static PyObject *asciiupper(PyObject *self, PyObject *args)
169 {
169 {
170 PyObject *str_obj;
170 PyObject *str_obj;
171 if (!PyArg_ParseTuple(args, "O!:asciiupper", &PyBytes_Type, &str_obj))
171 if (!PyArg_ParseTuple(args, "O!:asciiupper", &PyBytes_Type, &str_obj))
172 return NULL;
172 return NULL;
173 return _asciitransform(str_obj, uppertable, NULL);
173 return _asciitransform(str_obj, uppertable, NULL);
174 }
174 }
175
175
176 static PyObject *make_file_foldmap(PyObject *self, PyObject *args)
176 static PyObject *make_file_foldmap(PyObject *self, PyObject *args)
177 {
177 {
178 PyObject *dmap, *spec_obj, *normcase_fallback;
178 PyObject *dmap, *spec_obj, *normcase_fallback;
179 PyObject *file_foldmap = NULL;
179 PyObject *file_foldmap = NULL;
180 enum normcase_spec spec;
180 enum normcase_spec spec;
181 PyObject *k, *v;
181 PyObject *k, *v;
182 dirstateTupleObject *tuple;
182 dirstateTupleObject *tuple;
183 Py_ssize_t pos = 0;
183 Py_ssize_t pos = 0;
184 const char *table;
184 const char *table;
185
185
186 if (!PyArg_ParseTuple(args, "O!O!O!:make_file_foldmap",
186 if (!PyArg_ParseTuple(args, "O!O!O!:make_file_foldmap",
187 &PyDict_Type, &dmap,
187 &PyDict_Type, &dmap,
188 &PyInt_Type, &spec_obj,
188 &PyInt_Type, &spec_obj,
189 &PyFunction_Type, &normcase_fallback))
189 &PyFunction_Type, &normcase_fallback))
190 goto quit;
190 goto quit;
191
191
192 spec = (int)PyInt_AS_LONG(spec_obj);
192 spec = (int)PyInt_AS_LONG(spec_obj);
193 switch (spec) {
193 switch (spec) {
194 case NORMCASE_LOWER:
194 case NORMCASE_LOWER:
195 table = lowertable;
195 table = lowertable;
196 break;
196 break;
197 case NORMCASE_UPPER:
197 case NORMCASE_UPPER:
198 table = uppertable;
198 table = uppertable;
199 break;
199 break;
200 case NORMCASE_OTHER:
200 case NORMCASE_OTHER:
201 table = NULL;
201 table = NULL;
202 break;
202 break;
203 default:
203 default:
204 PyErr_SetString(PyExc_TypeError, "invalid normcasespec");
204 PyErr_SetString(PyExc_TypeError, "invalid normcasespec");
205 goto quit;
205 goto quit;
206 }
206 }
207
207
208 #if PY_VERSION_HEX >= 0x02060000
208 #if PY_VERSION_HEX >= 0x02060000
209 /* _PyDict_NewPresized expects a minused parameter, but it actually
209 /* _PyDict_NewPresized expects a minused parameter, but it actually
210 creates a dictionary that's the nearest power of two bigger than the
210 creates a dictionary that's the nearest power of two bigger than the
211 parameter. For example, with the initial minused = 1000, the
211 parameter. For example, with the initial minused = 1000, the
212 dictionary created has size 1024. Of course in a lot of cases that
212 dictionary created has size 1024. Of course in a lot of cases that
213 can be greater than the maximum load factor Python's dict object
213 can be greater than the maximum load factor Python's dict object
214 expects (= 2/3), so as soon as we cross the threshold we'll resize
214 expects (= 2/3), so as soon as we cross the threshold we'll resize
215 anyway. So create a dictionary that's 3/2 the size. Also add some
215 anyway. So create a dictionary that's 3/2 the size. Also add some
216 more to deal with additions outside this function. */
216 more to deal with additions outside this function. */
217 file_foldmap = _PyDict_NewPresized((PyDict_Size(dmap) / 5) * 8);
217 file_foldmap = _PyDict_NewPresized((PyDict_Size(dmap) / 5) * 8);
218 #else
218 #else
219 file_foldmap = PyDict_New();
219 file_foldmap = PyDict_New();
220 #endif
220 #endif
221
221
222 if (file_foldmap == NULL)
222 if (file_foldmap == NULL)
223 goto quit;
223 goto quit;
224
224
225 while (PyDict_Next(dmap, &pos, &k, &v)) {
225 while (PyDict_Next(dmap, &pos, &k, &v)) {
226 if (!dirstate_tuple_check(v)) {
226 if (!dirstate_tuple_check(v)) {
227 PyErr_SetString(PyExc_TypeError,
227 PyErr_SetString(PyExc_TypeError,
228 "expected a dirstate tuple");
228 "expected a dirstate tuple");
229 goto quit;
229 goto quit;
230 }
230 }
231
231
232 tuple = (dirstateTupleObject *)v;
232 tuple = (dirstateTupleObject *)v;
233 if (tuple->state != 'r') {
233 if (tuple->state != 'r') {
234 PyObject *normed;
234 PyObject *normed;
235 if (table != NULL) {
235 if (table != NULL) {
236 normed = _asciitransform(k, table,
236 normed = _asciitransform(k, table,
237 normcase_fallback);
237 normcase_fallback);
238 } else {
238 } else {
239 normed = PyObject_CallFunctionObjArgs(
239 normed = PyObject_CallFunctionObjArgs(
240 normcase_fallback, k, NULL);
240 normcase_fallback, k, NULL);
241 }
241 }
242
242
243 if (normed == NULL)
243 if (normed == NULL)
244 goto quit;
244 goto quit;
245 if (PyDict_SetItem(file_foldmap, normed, k) == -1)
245 if (PyDict_SetItem(file_foldmap, normed, k) == -1)
246 goto quit;
246 goto quit;
247 }
247 }
248 }
248 }
249 return file_foldmap;
249 return file_foldmap;
250 quit:
250 quit:
251 Py_XDECREF(file_foldmap);
251 Py_XDECREF(file_foldmap);
252 return NULL;
252 return NULL;
253 }
253 }
254
254
255 /*
255 /*
256 * This code assumes that a manifest is stitched together with newline
256 * This code assumes that a manifest is stitched together with newline
257 * ('\n') characters.
257 * ('\n') characters.
258 */
258 */
259 static PyObject *parse_manifest(PyObject *self, PyObject *args)
259 static PyObject *parse_manifest(PyObject *self, PyObject *args)
260 {
260 {
261 PyObject *mfdict, *fdict;
261 PyObject *mfdict, *fdict;
262 char *str, *start, *end;
262 char *str, *start, *end;
263 int len;
263 int len;
264
264
265 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
265 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
266 &PyDict_Type, &mfdict,
266 &PyDict_Type, &mfdict,
267 &PyDict_Type, &fdict,
267 &PyDict_Type, &fdict,
268 &str, &len))
268 &str, &len))
269 goto quit;
269 goto quit;
270
270
271 start = str;
271 start = str;
272 end = str + len;
272 end = str + len;
273 while (start < end) {
273 while (start < end) {
274 PyObject *file = NULL, *node = NULL;
274 PyObject *file = NULL, *node = NULL;
275 PyObject *flags = NULL;
275 PyObject *flags = NULL;
276 char *zero = NULL, *newline = NULL;
276 char *zero = NULL, *newline = NULL;
277 ptrdiff_t nlen;
277 ptrdiff_t nlen;
278
278
279 zero = memchr(start, '\0', end - start);
279 zero = memchr(start, '\0', end - start);
280 if (!zero) {
280 if (!zero) {
281 PyErr_SetString(PyExc_ValueError,
281 PyErr_SetString(PyExc_ValueError,
282 "manifest entry has no separator");
282 "manifest entry has no separator");
283 goto quit;
283 goto quit;
284 }
284 }
285
285
286 newline = memchr(zero + 1, '\n', end - (zero + 1));
286 newline = memchr(zero + 1, '\n', end - (zero + 1));
287 if (!newline) {
287 if (!newline) {
288 PyErr_SetString(PyExc_ValueError,
288 PyErr_SetString(PyExc_ValueError,
289 "manifest contains trailing garbage");
289 "manifest contains trailing garbage");
290 goto quit;
290 goto quit;
291 }
291 }
292
292
293 file = PyBytes_FromStringAndSize(start, zero - start);
293 file = PyBytes_FromStringAndSize(start, zero - start);
294
294
295 if (!file)
295 if (!file)
296 goto bail;
296 goto bail;
297
297
298 nlen = newline - zero - 1;
298 nlen = newline - zero - 1;
299
299
300 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
300 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
301 if (!node)
301 if (!node)
302 goto bail;
302 goto bail;
303
303
304 if (nlen > 40) {
304 if (nlen > 40) {
305 flags = PyBytes_FromStringAndSize(zero + 41,
305 flags = PyBytes_FromStringAndSize(zero + 41,
306 nlen - 40);
306 nlen - 40);
307 if (!flags)
307 if (!flags)
308 goto bail;
308 goto bail;
309
309
310 if (PyDict_SetItem(fdict, file, flags) == -1)
310 if (PyDict_SetItem(fdict, file, flags) == -1)
311 goto bail;
311 goto bail;
312 }
312 }
313
313
314 if (PyDict_SetItem(mfdict, file, node) == -1)
314 if (PyDict_SetItem(mfdict, file, node) == -1)
315 goto bail;
315 goto bail;
316
316
317 start = newline + 1;
317 start = newline + 1;
318
318
319 Py_XDECREF(flags);
319 Py_XDECREF(flags);
320 Py_XDECREF(node);
320 Py_XDECREF(node);
321 Py_XDECREF(file);
321 Py_XDECREF(file);
322 continue;
322 continue;
323 bail:
323 bail:
324 Py_XDECREF(flags);
324 Py_XDECREF(flags);
325 Py_XDECREF(node);
325 Py_XDECREF(node);
326 Py_XDECREF(file);
326 Py_XDECREF(file);
327 goto quit;
327 goto quit;
328 }
328 }
329
329
330 Py_INCREF(Py_None);
330 Py_INCREF(Py_None);
331 return Py_None;
331 return Py_None;
332 quit:
332 quit:
333 return NULL;
333 return NULL;
334 }
334 }
335
335
336 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
336 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
337 int size, int mtime)
337 int size, int mtime)
338 {
338 {
339 dirstateTupleObject *t = PyObject_New(dirstateTupleObject,
339 dirstateTupleObject *t = PyObject_New(dirstateTupleObject,
340 &dirstateTupleType);
340 &dirstateTupleType);
341 if (!t)
341 if (!t)
342 return NULL;
342 return NULL;
343 t->state = state;
343 t->state = state;
344 t->mode = mode;
344 t->mode = mode;
345 t->size = size;
345 t->size = size;
346 t->mtime = mtime;
346 t->mtime = mtime;
347 return t;
347 return t;
348 }
348 }
349
349
350 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
350 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
351 PyObject *kwds)
351 PyObject *kwds)
352 {
352 {
353 /* We do all the initialization here and not a tp_init function because
353 /* We do all the initialization here and not a tp_init function because
354 * dirstate_tuple is immutable. */
354 * dirstate_tuple is immutable. */
355 dirstateTupleObject *t;
355 dirstateTupleObject *t;
356 char state;
356 char state;
357 int size, mode, mtime;
357 int size, mode, mtime;
358 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
358 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
359 return NULL;
359 return NULL;
360
360
361 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
361 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
362 if (!t)
362 if (!t)
363 return NULL;
363 return NULL;
364 t->state = state;
364 t->state = state;
365 t->mode = mode;
365 t->mode = mode;
366 t->size = size;
366 t->size = size;
367 t->mtime = mtime;
367 t->mtime = mtime;
368
368
369 return (PyObject *)t;
369 return (PyObject *)t;
370 }
370 }
371
371
372 static void dirstate_tuple_dealloc(PyObject *o)
372 static void dirstate_tuple_dealloc(PyObject *o)
373 {
373 {
374 PyObject_Del(o);
374 PyObject_Del(o);
375 }
375 }
376
376
377 static Py_ssize_t dirstate_tuple_length(PyObject *o)
377 static Py_ssize_t dirstate_tuple_length(PyObject *o)
378 {
378 {
379 return 4;
379 return 4;
380 }
380 }
381
381
382 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
382 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
383 {
383 {
384 dirstateTupleObject *t = (dirstateTupleObject *)o;
384 dirstateTupleObject *t = (dirstateTupleObject *)o;
385 switch (i) {
385 switch (i) {
386 case 0:
386 case 0:
387 return PyBytes_FromStringAndSize(&t->state, 1);
387 return PyBytes_FromStringAndSize(&t->state, 1);
388 case 1:
388 case 1:
389 return PyInt_FromLong(t->mode);
389 return PyInt_FromLong(t->mode);
390 case 2:
390 case 2:
391 return PyInt_FromLong(t->size);
391 return PyInt_FromLong(t->size);
392 case 3:
392 case 3:
393 return PyInt_FromLong(t->mtime);
393 return PyInt_FromLong(t->mtime);
394 default:
394 default:
395 PyErr_SetString(PyExc_IndexError, "index out of range");
395 PyErr_SetString(PyExc_IndexError, "index out of range");
396 return NULL;
396 return NULL;
397 }
397 }
398 }
398 }
399
399
400 static PySequenceMethods dirstate_tuple_sq = {
400 static PySequenceMethods dirstate_tuple_sq = {
401 dirstate_tuple_length, /* sq_length */
401 dirstate_tuple_length, /* sq_length */
402 0, /* sq_concat */
402 0, /* sq_concat */
403 0, /* sq_repeat */
403 0, /* sq_repeat */
404 dirstate_tuple_item, /* sq_item */
404 dirstate_tuple_item, /* sq_item */
405 0, /* sq_ass_item */
405 0, /* sq_ass_item */
406 0, /* sq_contains */
406 0, /* sq_contains */
407 0, /* sq_inplace_concat */
407 0, /* sq_inplace_concat */
408 0 /* sq_inplace_repeat */
408 0 /* sq_inplace_repeat */
409 };
409 };
410
410
411 PyTypeObject dirstateTupleType = {
411 PyTypeObject dirstateTupleType = {
412 PyVarObject_HEAD_INIT(NULL, 0)
412 PyVarObject_HEAD_INIT(NULL, 0)
413 "dirstate_tuple", /* tp_name */
413 "dirstate_tuple", /* tp_name */
414 sizeof(dirstateTupleObject),/* tp_basicsize */
414 sizeof(dirstateTupleObject),/* tp_basicsize */
415 0, /* tp_itemsize */
415 0, /* tp_itemsize */
416 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
416 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
417 0, /* tp_print */
417 0, /* tp_print */
418 0, /* tp_getattr */
418 0, /* tp_getattr */
419 0, /* tp_setattr */
419 0, /* tp_setattr */
420 0, /* tp_compare */
420 0, /* tp_compare */
421 0, /* tp_repr */
421 0, /* tp_repr */
422 0, /* tp_as_number */
422 0, /* tp_as_number */
423 &dirstate_tuple_sq, /* tp_as_sequence */
423 &dirstate_tuple_sq, /* tp_as_sequence */
424 0, /* tp_as_mapping */
424 0, /* tp_as_mapping */
425 0, /* tp_hash */
425 0, /* tp_hash */
426 0, /* tp_call */
426 0, /* tp_call */
427 0, /* tp_str */
427 0, /* tp_str */
428 0, /* tp_getattro */
428 0, /* tp_getattro */
429 0, /* tp_setattro */
429 0, /* tp_setattro */
430 0, /* tp_as_buffer */
430 0, /* tp_as_buffer */
431 Py_TPFLAGS_DEFAULT, /* tp_flags */
431 Py_TPFLAGS_DEFAULT, /* tp_flags */
432 "dirstate tuple", /* tp_doc */
432 "dirstate tuple", /* tp_doc */
433 0, /* tp_traverse */
433 0, /* tp_traverse */
434 0, /* tp_clear */
434 0, /* tp_clear */
435 0, /* tp_richcompare */
435 0, /* tp_richcompare */
436 0, /* tp_weaklistoffset */
436 0, /* tp_weaklistoffset */
437 0, /* tp_iter */
437 0, /* tp_iter */
438 0, /* tp_iternext */
438 0, /* tp_iternext */
439 0, /* tp_methods */
439 0, /* tp_methods */
440 0, /* tp_members */
440 0, /* tp_members */
441 0, /* tp_getset */
441 0, /* tp_getset */
442 0, /* tp_base */
442 0, /* tp_base */
443 0, /* tp_dict */
443 0, /* tp_dict */
444 0, /* tp_descr_get */
444 0, /* tp_descr_get */
445 0, /* tp_descr_set */
445 0, /* tp_descr_set */
446 0, /* tp_dictoffset */
446 0, /* tp_dictoffset */
447 0, /* tp_init */
447 0, /* tp_init */
448 0, /* tp_alloc */
448 0, /* tp_alloc */
449 dirstate_tuple_new, /* tp_new */
449 dirstate_tuple_new, /* tp_new */
450 };
450 };
451
451
452 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
452 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
453 {
453 {
454 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
454 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
455 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
455 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
456 char state, *cur, *str, *cpos;
456 char state, *cur, *str, *cpos;
457 int mode, size, mtime;
457 int mode, size, mtime;
458 unsigned int flen, len, pos = 40;
458 unsigned int flen, len, pos = 40;
459 int readlen;
459 int readlen;
460
460
461 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
461 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
462 &PyDict_Type, &dmap,
462 &PyDict_Type, &dmap,
463 &PyDict_Type, &cmap,
463 &PyDict_Type, &cmap,
464 &str, &readlen))
464 &str, &readlen))
465 goto quit;
465 goto quit;
466
466
467 if (readlen < 0)
467 if (readlen < 0)
468 goto quit;
468 goto quit;
469
469
470 len = readlen;
470 len = readlen;
471
471
472 /* read parents */
472 /* read parents */
473 if (len < 40)
473 if (len < 40)
474 goto quit;
474 goto quit;
475
475
476 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
476 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
477 if (!parents)
477 if (!parents)
478 goto quit;
478 goto quit;
479
479
480 /* read filenames */
480 /* read filenames */
481 while (pos >= 40 && pos < len) {
481 while (pos >= 40 && pos < len) {
482 cur = str + pos;
482 cur = str + pos;
483 /* unpack header */
483 /* unpack header */
484 state = *cur;
484 state = *cur;
485 mode = getbe32(cur + 1);
485 mode = getbe32(cur + 1);
486 size = getbe32(cur + 5);
486 size = getbe32(cur + 5);
487 mtime = getbe32(cur + 9);
487 mtime = getbe32(cur + 9);
488 flen = getbe32(cur + 13);
488 flen = getbe32(cur + 13);
489 pos += 17;
489 pos += 17;
490 cur += 17;
490 cur += 17;
491 if (flen > len - pos) {
491 if (flen > len - pos) {
492 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
492 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
493 goto quit;
493 goto quit;
494 }
494 }
495
495
496 entry = (PyObject *)make_dirstate_tuple(state, mode, size,
496 entry = (PyObject *)make_dirstate_tuple(state, mode, size,
497 mtime);
497 mtime);
498 cpos = memchr(cur, 0, flen);
498 cpos = memchr(cur, 0, flen);
499 if (cpos) {
499 if (cpos) {
500 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
500 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
501 cname = PyBytes_FromStringAndSize(cpos + 1,
501 cname = PyBytes_FromStringAndSize(cpos + 1,
502 flen - (cpos - cur) - 1);
502 flen - (cpos - cur) - 1);
503 if (!fname || !cname ||
503 if (!fname || !cname ||
504 PyDict_SetItem(cmap, fname, cname) == -1 ||
504 PyDict_SetItem(cmap, fname, cname) == -1 ||
505 PyDict_SetItem(dmap, fname, entry) == -1)
505 PyDict_SetItem(dmap, fname, entry) == -1)
506 goto quit;
506 goto quit;
507 Py_DECREF(cname);
507 Py_DECREF(cname);
508 } else {
508 } else {
509 fname = PyBytes_FromStringAndSize(cur, flen);
509 fname = PyBytes_FromStringAndSize(cur, flen);
510 if (!fname ||
510 if (!fname ||
511 PyDict_SetItem(dmap, fname, entry) == -1)
511 PyDict_SetItem(dmap, fname, entry) == -1)
512 goto quit;
512 goto quit;
513 }
513 }
514 Py_DECREF(fname);
514 Py_DECREF(fname);
515 Py_DECREF(entry);
515 Py_DECREF(entry);
516 fname = cname = entry = NULL;
516 fname = cname = entry = NULL;
517 pos += flen;
517 pos += flen;
518 }
518 }
519
519
520 ret = parents;
520 ret = parents;
521 Py_INCREF(ret);
521 Py_INCREF(ret);
522 quit:
522 quit:
523 Py_XDECREF(fname);
523 Py_XDECREF(fname);
524 Py_XDECREF(cname);
524 Py_XDECREF(cname);
525 Py_XDECREF(entry);
525 Py_XDECREF(entry);
526 Py_XDECREF(parents);
526 Py_XDECREF(parents);
527 return ret;
527 return ret;
528 }
528 }
529
529
530 /*
530 /*
531 * Efficiently pack a dirstate object into its on-disk format.
531 * Efficiently pack a dirstate object into its on-disk format.
532 */
532 */
533 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
533 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
534 {
534 {
535 PyObject *packobj = NULL;
535 PyObject *packobj = NULL;
536 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
536 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
537 Py_ssize_t nbytes, pos, l;
537 Py_ssize_t nbytes, pos, l;
538 PyObject *k, *v = NULL, *pn;
538 PyObject *k, *v = NULL, *pn;
539 char *p, *s;
539 char *p, *s;
540 double now;
540 double now;
541
541
542 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
542 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
543 &PyDict_Type, &map, &PyDict_Type, &copymap,
543 &PyDict_Type, &map, &PyDict_Type, &copymap,
544 &pl, &now))
544 &pl, &now))
545 return NULL;
545 return NULL;
546
546
547 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
547 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
548 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
548 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
549 return NULL;
549 return NULL;
550 }
550 }
551
551
552 /* Figure out how much we need to allocate. */
552 /* Figure out how much we need to allocate. */
553 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
553 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
554 PyObject *c;
554 PyObject *c;
555 if (!PyString_Check(k)) {
555 if (!PyString_Check(k)) {
556 PyErr_SetString(PyExc_TypeError, "expected string key");
556 PyErr_SetString(PyExc_TypeError, "expected string key");
557 goto bail;
557 goto bail;
558 }
558 }
559 nbytes += PyString_GET_SIZE(k) + 17;
559 nbytes += PyString_GET_SIZE(k) + 17;
560 c = PyDict_GetItem(copymap, k);
560 c = PyDict_GetItem(copymap, k);
561 if (c) {
561 if (c) {
562 if (!PyString_Check(c)) {
562 if (!PyString_Check(c)) {
563 PyErr_SetString(PyExc_TypeError,
563 PyErr_SetString(PyExc_TypeError,
564 "expected string key");
564 "expected string key");
565 goto bail;
565 goto bail;
566 }
566 }
567 nbytes += PyString_GET_SIZE(c) + 1;
567 nbytes += PyString_GET_SIZE(c) + 1;
568 }
568 }
569 }
569 }
570
570
571 packobj = PyString_FromStringAndSize(NULL, nbytes);
571 packobj = PyString_FromStringAndSize(NULL, nbytes);
572 if (packobj == NULL)
572 if (packobj == NULL)
573 goto bail;
573 goto bail;
574
574
575 p = PyString_AS_STRING(packobj);
575 p = PyString_AS_STRING(packobj);
576
576
577 pn = PySequence_ITEM(pl, 0);
577 pn = PySequence_ITEM(pl, 0);
578 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
578 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
579 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
579 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
580 goto bail;
580 goto bail;
581 }
581 }
582 memcpy(p, s, l);
582 memcpy(p, s, l);
583 p += 20;
583 p += 20;
584 pn = PySequence_ITEM(pl, 1);
584 pn = PySequence_ITEM(pl, 1);
585 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
585 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
586 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
586 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
587 goto bail;
587 goto bail;
588 }
588 }
589 memcpy(p, s, l);
589 memcpy(p, s, l);
590 p += 20;
590 p += 20;
591
591
592 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
592 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
593 dirstateTupleObject *tuple;
593 dirstateTupleObject *tuple;
594 char state;
594 char state;
595 uint32_t mode, size, mtime;
595 uint32_t mode, size, mtime;
596 Py_ssize_t len, l;
596 Py_ssize_t len, l;
597 PyObject *o;
597 PyObject *o;
598 char *t;
598 char *t;
599
599
600 if (!dirstate_tuple_check(v)) {
600 if (!dirstate_tuple_check(v)) {
601 PyErr_SetString(PyExc_TypeError,
601 PyErr_SetString(PyExc_TypeError,
602 "expected a dirstate tuple");
602 "expected a dirstate tuple");
603 goto bail;
603 goto bail;
604 }
604 }
605 tuple = (dirstateTupleObject *)v;
605 tuple = (dirstateTupleObject *)v;
606
606
607 state = tuple->state;
607 state = tuple->state;
608 mode = tuple->mode;
608 mode = tuple->mode;
609 size = tuple->size;
609 size = tuple->size;
610 mtime = tuple->mtime;
610 mtime = tuple->mtime;
611 if (state == 'n' && mtime == (uint32_t)now) {
611 if (state == 'n' && mtime == (uint32_t)now) {
612 /* See pure/parsers.py:pack_dirstate for why we do
612 /* See pure/parsers.py:pack_dirstate for why we do
613 * this. */
613 * this. */
614 mtime = -1;
614 mtime = -1;
615 mtime_unset = (PyObject *)make_dirstate_tuple(
615 mtime_unset = (PyObject *)make_dirstate_tuple(
616 state, mode, size, mtime);
616 state, mode, size, mtime);
617 if (!mtime_unset)
617 if (!mtime_unset)
618 goto bail;
618 goto bail;
619 if (PyDict_SetItem(map, k, mtime_unset) == -1)
619 if (PyDict_SetItem(map, k, mtime_unset) == -1)
620 goto bail;
620 goto bail;
621 Py_DECREF(mtime_unset);
621 Py_DECREF(mtime_unset);
622 mtime_unset = NULL;
622 mtime_unset = NULL;
623 }
623 }
624 *p++ = state;
624 *p++ = state;
625 putbe32(mode, p);
625 putbe32(mode, p);
626 putbe32(size, p + 4);
626 putbe32(size, p + 4);
627 putbe32(mtime, p + 8);
627 putbe32(mtime, p + 8);
628 t = p + 12;
628 t = p + 12;
629 p += 16;
629 p += 16;
630 len = PyString_GET_SIZE(k);
630 len = PyString_GET_SIZE(k);
631 memcpy(p, PyString_AS_STRING(k), len);
631 memcpy(p, PyString_AS_STRING(k), len);
632 p += len;
632 p += len;
633 o = PyDict_GetItem(copymap, k);
633 o = PyDict_GetItem(copymap, k);
634 if (o) {
634 if (o) {
635 *p++ = '\0';
635 *p++ = '\0';
636 l = PyString_GET_SIZE(o);
636 l = PyString_GET_SIZE(o);
637 memcpy(p, PyString_AS_STRING(o), l);
637 memcpy(p, PyString_AS_STRING(o), l);
638 p += l;
638 p += l;
639 len += l + 1;
639 len += l + 1;
640 }
640 }
641 putbe32((uint32_t)len, t);
641 putbe32((uint32_t)len, t);
642 }
642 }
643
643
644 pos = p - PyString_AS_STRING(packobj);
644 pos = p - PyString_AS_STRING(packobj);
645 if (pos != nbytes) {
645 if (pos != nbytes) {
646 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
646 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
647 (long)pos, (long)nbytes);
647 (long)pos, (long)nbytes);
648 goto bail;
648 goto bail;
649 }
649 }
650
650
651 return packobj;
651 return packobj;
652 bail:
652 bail:
653 Py_XDECREF(mtime_unset);
653 Py_XDECREF(mtime_unset);
654 Py_XDECREF(packobj);
654 Py_XDECREF(packobj);
655 Py_XDECREF(v);
655 Py_XDECREF(v);
656 return NULL;
656 return NULL;
657 }
657 }
658
658
659 /*
659 /*
660 * A base-16 trie for fast node->rev mapping.
660 * A base-16 trie for fast node->rev mapping.
661 *
661 *
662 * Positive value is index of the next node in the trie
662 * Positive value is index of the next node in the trie
663 * Negative value is a leaf: -(rev + 1)
663 * Negative value is a leaf: -(rev + 1)
664 * Zero is empty
664 * Zero is empty
665 */
665 */
666 typedef struct {
666 typedef struct {
667 int children[16];
667 int children[16];
668 } nodetree;
668 } nodetree;
669
669
670 /*
670 /*
671 * This class has two behaviours.
671 * This class has two behaviours.
672 *
672 *
673 * When used in a list-like way (with integer keys), we decode an
673 * When used in a list-like way (with integer keys), we decode an
674 * entry in a RevlogNG index file on demand. Our last entry is a
674 * entry in a RevlogNG index file on demand. Our last entry is a
675 * sentinel, always a nullid. We have limited support for
675 * sentinel, always a nullid. We have limited support for
676 * integer-keyed insert and delete, only at elements right before the
676 * integer-keyed insert and delete, only at elements right before the
677 * sentinel.
677 * sentinel.
678 *
678 *
679 * With string keys, we lazily perform a reverse mapping from node to
679 * With string keys, we lazily perform a reverse mapping from node to
680 * rev, using a base-16 trie.
680 * rev, using a base-16 trie.
681 */
681 */
682 typedef struct {
682 typedef struct {
683 PyObject_HEAD
683 PyObject_HEAD
684 /* Type-specific fields go here. */
684 /* Type-specific fields go here. */
685 PyObject *data; /* raw bytes of index */
685 PyObject *data; /* raw bytes of index */
686 PyObject **cache; /* cached tuples */
686 PyObject **cache; /* cached tuples */
687 const char **offsets; /* populated on demand */
687 const char **offsets; /* populated on demand */
688 Py_ssize_t raw_length; /* original number of elements */
688 Py_ssize_t raw_length; /* original number of elements */
689 Py_ssize_t length; /* current number of elements */
689 Py_ssize_t length; /* current number of elements */
690 PyObject *added; /* populated on demand */
690 PyObject *added; /* populated on demand */
691 PyObject *headrevs; /* cache, invalidated on changes */
691 PyObject *headrevs; /* cache, invalidated on changes */
692 PyObject *filteredrevs;/* filtered revs set */
692 PyObject *filteredrevs;/* filtered revs set */
693 nodetree *nt; /* base-16 trie */
693 nodetree *nt; /* base-16 trie */
694 int ntlength; /* # nodes in use */
694 int ntlength; /* # nodes in use */
695 int ntcapacity; /* # nodes allocated */
695 int ntcapacity; /* # nodes allocated */
696 int ntdepth; /* maximum depth of tree */
696 int ntdepth; /* maximum depth of tree */
697 int ntsplits; /* # splits performed */
697 int ntsplits; /* # splits performed */
698 int ntrev; /* last rev scanned */
698 int ntrev; /* last rev scanned */
699 int ntlookups; /* # lookups */
699 int ntlookups; /* # lookups */
700 int ntmisses; /* # lookups that miss the cache */
700 int ntmisses; /* # lookups that miss the cache */
701 int inlined;
701 int inlined;
702 } indexObject;
702 } indexObject;
703
703
704 static Py_ssize_t index_length(const indexObject *self)
704 static Py_ssize_t index_length(const indexObject *self)
705 {
705 {
706 if (self->added == NULL)
706 if (self->added == NULL)
707 return self->length;
707 return self->length;
708 return self->length + PyList_GET_SIZE(self->added);
708 return self->length + PyList_GET_SIZE(self->added);
709 }
709 }
710
710
711 static PyObject *nullentry;
711 static PyObject *nullentry;
712 static const char nullid[20];
712 static const char nullid[20];
713
713
714 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
714 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
715
715
716 #if LONG_MAX == 0x7fffffffL
716 #if LONG_MAX == 0x7fffffffL
717 static char *tuple_format = "Kiiiiiis#";
717 static char *tuple_format = "Kiiiiiis#";
718 #else
718 #else
719 static char *tuple_format = "kiiiiiis#";
719 static char *tuple_format = "kiiiiiis#";
720 #endif
720 #endif
721
721
722 /* A RevlogNG v1 index entry is 64 bytes long. */
722 /* A RevlogNG v1 index entry is 64 bytes long. */
723 static const long v1_hdrsize = 64;
723 static const long v1_hdrsize = 64;
724
724
725 /*
725 /*
726 * Return a pointer to the beginning of a RevlogNG record.
726 * Return a pointer to the beginning of a RevlogNG record.
727 */
727 */
728 static const char *index_deref(indexObject *self, Py_ssize_t pos)
728 static const char *index_deref(indexObject *self, Py_ssize_t pos)
729 {
729 {
730 if (self->inlined && pos > 0) {
730 if (self->inlined && pos > 0) {
731 if (self->offsets == NULL) {
731 if (self->offsets == NULL) {
732 self->offsets = malloc(self->raw_length *
732 self->offsets = malloc(self->raw_length *
733 sizeof(*self->offsets));
733 sizeof(*self->offsets));
734 if (self->offsets == NULL)
734 if (self->offsets == NULL)
735 return (const char *)PyErr_NoMemory();
735 return (const char *)PyErr_NoMemory();
736 inline_scan(self, self->offsets);
736 inline_scan(self, self->offsets);
737 }
737 }
738 return self->offsets[pos];
738 return self->offsets[pos];
739 }
739 }
740
740
741 return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
741 return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
742 }
742 }
743
743
744 /*
744 /*
745 * RevlogNG format (all in big endian, data may be inlined):
745 * RevlogNG format (all in big endian, data may be inlined):
746 * 6 bytes: offset
746 * 6 bytes: offset
747 * 2 bytes: flags
747 * 2 bytes: flags
748 * 4 bytes: compressed length
748 * 4 bytes: compressed length
749 * 4 bytes: uncompressed length
749 * 4 bytes: uncompressed length
750 * 4 bytes: base revision
750 * 4 bytes: base revision
751 * 4 bytes: link revision
751 * 4 bytes: link revision
752 * 4 bytes: parent 1 revision
752 * 4 bytes: parent 1 revision
753 * 4 bytes: parent 2 revision
753 * 4 bytes: parent 2 revision
754 * 32 bytes: nodeid (only 20 bytes used)
754 * 32 bytes: nodeid (only 20 bytes used)
755 */
755 */
756 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
756 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
757 {
757 {
758 uint64_t offset_flags;
758 uint64_t offset_flags;
759 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
759 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
760 const char *c_node_id;
760 const char *c_node_id;
761 const char *data;
761 const char *data;
762 Py_ssize_t length = index_length(self);
762 Py_ssize_t length = index_length(self);
763 PyObject *entry;
763 PyObject *entry;
764
764
765 if (pos < 0)
765 if (pos < 0)
766 pos += length;
766 pos += length;
767
767
768 if (pos < 0 || pos >= length) {
768 if (pos < 0 || pos >= length) {
769 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
769 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
770 return NULL;
770 return NULL;
771 }
771 }
772
772
773 if (pos == length - 1) {
773 if (pos == length - 1) {
774 Py_INCREF(nullentry);
774 Py_INCREF(nullentry);
775 return nullentry;
775 return nullentry;
776 }
776 }
777
777
778 if (pos >= self->length - 1) {
778 if (pos >= self->length - 1) {
779 PyObject *obj;
779 PyObject *obj;
780 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
780 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
781 Py_INCREF(obj);
781 Py_INCREF(obj);
782 return obj;
782 return obj;
783 }
783 }
784
784
785 if (self->cache) {
785 if (self->cache) {
786 if (self->cache[pos]) {
786 if (self->cache[pos]) {
787 Py_INCREF(self->cache[pos]);
787 Py_INCREF(self->cache[pos]);
788 return self->cache[pos];
788 return self->cache[pos];
789 }
789 }
790 } else {
790 } else {
791 self->cache = calloc(self->raw_length, sizeof(PyObject *));
791 self->cache = calloc(self->raw_length, sizeof(PyObject *));
792 if (self->cache == NULL)
792 if (self->cache == NULL)
793 return PyErr_NoMemory();
793 return PyErr_NoMemory();
794 }
794 }
795
795
796 data = index_deref(self, pos);
796 data = index_deref(self, pos);
797 if (data == NULL)
797 if (data == NULL)
798 return NULL;
798 return NULL;
799
799
800 offset_flags = getbe32(data + 4);
800 offset_flags = getbe32(data + 4);
801 if (pos == 0) /* mask out version number for the first entry */
801 if (pos == 0) /* mask out version number for the first entry */
802 offset_flags &= 0xFFFF;
802 offset_flags &= 0xFFFF;
803 else {
803 else {
804 uint32_t offset_high = getbe32(data);
804 uint32_t offset_high = getbe32(data);
805 offset_flags |= ((uint64_t)offset_high) << 32;
805 offset_flags |= ((uint64_t)offset_high) << 32;
806 }
806 }
807
807
808 comp_len = getbe32(data + 8);
808 comp_len = getbe32(data + 8);
809 uncomp_len = getbe32(data + 12);
809 uncomp_len = getbe32(data + 12);
810 base_rev = getbe32(data + 16);
810 base_rev = getbe32(data + 16);
811 link_rev = getbe32(data + 20);
811 link_rev = getbe32(data + 20);
812 parent_1 = getbe32(data + 24);
812 parent_1 = getbe32(data + 24);
813 parent_2 = getbe32(data + 28);
813 parent_2 = getbe32(data + 28);
814 c_node_id = data + 32;
814 c_node_id = data + 32;
815
815
816 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
816 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
817 uncomp_len, base_rev, link_rev,
817 uncomp_len, base_rev, link_rev,
818 parent_1, parent_2, c_node_id, 20);
818 parent_1, parent_2, c_node_id, 20);
819
819
820 if (entry) {
820 if (entry) {
821 PyObject_GC_UnTrack(entry);
821 PyObject_GC_UnTrack(entry);
822 Py_INCREF(entry);
822 Py_INCREF(entry);
823 }
823 }
824
824
825 self->cache[pos] = entry;
825 self->cache[pos] = entry;
826
826
827 return entry;
827 return entry;
828 }
828 }
829
829
830 /*
830 /*
831 * Return the 20-byte SHA of the node corresponding to the given rev.
831 * Return the 20-byte SHA of the node corresponding to the given rev.
832 */
832 */
833 static const char *index_node(indexObject *self, Py_ssize_t pos)
833 static const char *index_node(indexObject *self, Py_ssize_t pos)
834 {
834 {
835 Py_ssize_t length = index_length(self);
835 Py_ssize_t length = index_length(self);
836 const char *data;
836 const char *data;
837
837
838 if (pos == length - 1 || pos == INT_MAX)
838 if (pos == length - 1 || pos == INT_MAX)
839 return nullid;
839 return nullid;
840
840
841 if (pos >= length)
841 if (pos >= length)
842 return NULL;
842 return NULL;
843
843
844 if (pos >= self->length - 1) {
844 if (pos >= self->length - 1) {
845 PyObject *tuple, *str;
845 PyObject *tuple, *str;
846 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
846 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
847 str = PyTuple_GetItem(tuple, 7);
847 str = PyTuple_GetItem(tuple, 7);
848 return str ? PyString_AS_STRING(str) : NULL;
848 return str ? PyString_AS_STRING(str) : NULL;
849 }
849 }
850
850
851 data = index_deref(self, pos);
851 data = index_deref(self, pos);
852 return data ? data + 32 : NULL;
852 return data ? data + 32 : NULL;
853 }
853 }
854
854
855 static int nt_insert(indexObject *self, const char *node, int rev);
855 static int nt_insert(indexObject *self, const char *node, int rev);
856
856
857 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
857 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
858 {
858 {
859 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
859 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
860 return -1;
860 return -1;
861 if (*nodelen == 20)
861 if (*nodelen == 20)
862 return 0;
862 return 0;
863 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
863 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
864 return -1;
864 return -1;
865 }
865 }
866
866
867 static PyObject *index_insert(indexObject *self, PyObject *args)
867 static PyObject *index_insert(indexObject *self, PyObject *args)
868 {
868 {
869 PyObject *obj;
869 PyObject *obj;
870 char *node;
870 char *node;
871 int index;
871 int index;
872 Py_ssize_t len, nodelen;
872 Py_ssize_t len, nodelen;
873
873
874 if (!PyArg_ParseTuple(args, "iO", &index, &obj))
874 if (!PyArg_ParseTuple(args, "iO", &index, &obj))
875 return NULL;
875 return NULL;
876
876
877 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
877 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
878 PyErr_SetString(PyExc_TypeError, "8-tuple required");
878 PyErr_SetString(PyExc_TypeError, "8-tuple required");
879 return NULL;
879 return NULL;
880 }
880 }
881
881
882 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
882 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
883 return NULL;
883 return NULL;
884
884
885 len = index_length(self);
885 len = index_length(self);
886
886
887 if (index < 0)
887 if (index < 0)
888 index += len;
888 index += len;
889
889
890 if (index != len - 1) {
890 if (index != len - 1) {
891 PyErr_SetString(PyExc_IndexError,
891 PyErr_SetString(PyExc_IndexError,
892 "insert only supported at index -1");
892 "insert only supported at index -1");
893 return NULL;
893 return NULL;
894 }
894 }
895
895
896 if (self->added == NULL) {
896 if (self->added == NULL) {
897 self->added = PyList_New(0);
897 self->added = PyList_New(0);
898 if (self->added == NULL)
898 if (self->added == NULL)
899 return NULL;
899 return NULL;
900 }
900 }
901
901
902 if (PyList_Append(self->added, obj) == -1)
902 if (PyList_Append(self->added, obj) == -1)
903 return NULL;
903 return NULL;
904
904
905 if (self->nt)
905 if (self->nt)
906 nt_insert(self, node, index);
906 nt_insert(self, node, index);
907
907
908 Py_CLEAR(self->headrevs);
908 Py_CLEAR(self->headrevs);
909 Py_RETURN_NONE;
909 Py_RETURN_NONE;
910 }
910 }
911
911
912 static void _index_clearcaches(indexObject *self)
912 static void _index_clearcaches(indexObject *self)
913 {
913 {
914 if (self->cache) {
914 if (self->cache) {
915 Py_ssize_t i;
915 Py_ssize_t i;
916
916
917 for (i = 0; i < self->raw_length; i++)
917 for (i = 0; i < self->raw_length; i++)
918 Py_CLEAR(self->cache[i]);
918 Py_CLEAR(self->cache[i]);
919 free(self->cache);
919 free(self->cache);
920 self->cache = NULL;
920 self->cache = NULL;
921 }
921 }
922 if (self->offsets) {
922 if (self->offsets) {
923 free(self->offsets);
923 free(self->offsets);
924 self->offsets = NULL;
924 self->offsets = NULL;
925 }
925 }
926 if (self->nt) {
926 if (self->nt) {
927 free(self->nt);
927 free(self->nt);
928 self->nt = NULL;
928 self->nt = NULL;
929 }
929 }
930 Py_CLEAR(self->headrevs);
930 Py_CLEAR(self->headrevs);
931 }
931 }
932
932
933 static PyObject *index_clearcaches(indexObject *self)
933 static PyObject *index_clearcaches(indexObject *self)
934 {
934 {
935 _index_clearcaches(self);
935 _index_clearcaches(self);
936 self->ntlength = self->ntcapacity = 0;
936 self->ntlength = self->ntcapacity = 0;
937 self->ntdepth = self->ntsplits = 0;
937 self->ntdepth = self->ntsplits = 0;
938 self->ntrev = -1;
938 self->ntrev = -1;
939 self->ntlookups = self->ntmisses = 0;
939 self->ntlookups = self->ntmisses = 0;
940 Py_RETURN_NONE;
940 Py_RETURN_NONE;
941 }
941 }
942
942
943 static PyObject *index_stats(indexObject *self)
943 static PyObject *index_stats(indexObject *self)
944 {
944 {
945 PyObject *obj = PyDict_New();
945 PyObject *obj = PyDict_New();
946 PyObject *t = NULL;
946 PyObject *t = NULL;
947
947
948 if (obj == NULL)
948 if (obj == NULL)
949 return NULL;
949 return NULL;
950
950
951 #define istat(__n, __d) \
951 #define istat(__n, __d) \
952 t = PyInt_FromSsize_t(self->__n); \
952 t = PyInt_FromSsize_t(self->__n); \
953 if (!t) \
953 if (!t) \
954 goto bail; \
954 goto bail; \
955 if (PyDict_SetItemString(obj, __d, t) == -1) \
955 if (PyDict_SetItemString(obj, __d, t) == -1) \
956 goto bail; \
956 goto bail; \
957 Py_DECREF(t);
957 Py_DECREF(t);
958
958
959 if (self->added) {
959 if (self->added) {
960 Py_ssize_t len = PyList_GET_SIZE(self->added);
960 Py_ssize_t len = PyList_GET_SIZE(self->added);
961 t = PyInt_FromSsize_t(len);
961 t = PyInt_FromSsize_t(len);
962 if (!t)
962 if (!t)
963 goto bail;
963 goto bail;
964 if (PyDict_SetItemString(obj, "index entries added", t) == -1)
964 if (PyDict_SetItemString(obj, "index entries added", t) == -1)
965 goto bail;
965 goto bail;
966 Py_DECREF(t);
966 Py_DECREF(t);
967 }
967 }
968
968
969 if (self->raw_length != self->length - 1)
969 if (self->raw_length != self->length - 1)
970 istat(raw_length, "revs on disk");
970 istat(raw_length, "revs on disk");
971 istat(length, "revs in memory");
971 istat(length, "revs in memory");
972 istat(ntcapacity, "node trie capacity");
972 istat(ntcapacity, "node trie capacity");
973 istat(ntdepth, "node trie depth");
973 istat(ntdepth, "node trie depth");
974 istat(ntlength, "node trie count");
974 istat(ntlength, "node trie count");
975 istat(ntlookups, "node trie lookups");
975 istat(ntlookups, "node trie lookups");
976 istat(ntmisses, "node trie misses");
976 istat(ntmisses, "node trie misses");
977 istat(ntrev, "node trie last rev scanned");
977 istat(ntrev, "node trie last rev scanned");
978 istat(ntsplits, "node trie splits");
978 istat(ntsplits, "node trie splits");
979
979
980 #undef istat
980 #undef istat
981
981
982 return obj;
982 return obj;
983
983
984 bail:
984 bail:
985 Py_XDECREF(obj);
985 Py_XDECREF(obj);
986 Py_XDECREF(t);
986 Py_XDECREF(t);
987 return NULL;
987 return NULL;
988 }
988 }
989
989
990 /*
990 /*
991 * When we cache a list, we want to be sure the caller can't mutate
991 * When we cache a list, we want to be sure the caller can't mutate
992 * the cached copy.
992 * the cached copy.
993 */
993 */
994 static PyObject *list_copy(PyObject *list)
994 static PyObject *list_copy(PyObject *list)
995 {
995 {
996 Py_ssize_t len = PyList_GET_SIZE(list);
996 Py_ssize_t len = PyList_GET_SIZE(list);
997 PyObject *newlist = PyList_New(len);
997 PyObject *newlist = PyList_New(len);
998 Py_ssize_t i;
998 Py_ssize_t i;
999
999
1000 if (newlist == NULL)
1000 if (newlist == NULL)
1001 return NULL;
1001 return NULL;
1002
1002
1003 for (i = 0; i < len; i++) {
1003 for (i = 0; i < len; i++) {
1004 PyObject *obj = PyList_GET_ITEM(list, i);
1004 PyObject *obj = PyList_GET_ITEM(list, i);
1005 Py_INCREF(obj);
1005 Py_INCREF(obj);
1006 PyList_SET_ITEM(newlist, i, obj);
1006 PyList_SET_ITEM(newlist, i, obj);
1007 }
1007 }
1008
1008
1009 return newlist;
1009 return newlist;
1010 }
1010 }
1011
1011
1012 /* arg should be Py_ssize_t but Python 2.4 do not support the n format */
1012 /* arg should be Py_ssize_t but Python 2.4 do not support the n format */
1013 static int check_filter(PyObject *filter, unsigned long arg) {
1013 static int check_filter(PyObject *filter, unsigned long arg) {
1014 if (filter) {
1014 if (filter) {
1015 PyObject *arglist, *result;
1015 PyObject *arglist, *result;
1016 int isfiltered;
1016 int isfiltered;
1017
1017
1018 arglist = Py_BuildValue("(k)", arg);
1018 arglist = Py_BuildValue("(k)", arg);
1019 if (!arglist) {
1019 if (!arglist) {
1020 return -1;
1020 return -1;
1021 }
1021 }
1022
1022
1023 result = PyEval_CallObject(filter, arglist);
1023 result = PyEval_CallObject(filter, arglist);
1024 Py_DECREF(arglist);
1024 Py_DECREF(arglist);
1025 if (!result) {
1025 if (!result) {
1026 return -1;
1026 return -1;
1027 }
1027 }
1028
1028
1029 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
1029 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
1030 * same as this function, so we can just return it directly.*/
1030 * same as this function, so we can just return it directly.*/
1031 isfiltered = PyObject_IsTrue(result);
1031 isfiltered = PyObject_IsTrue(result);
1032 Py_DECREF(result);
1032 Py_DECREF(result);
1033 return isfiltered;
1033 return isfiltered;
1034 } else {
1034 } else {
1035 return 0;
1035 return 0;
1036 }
1036 }
1037 }
1037 }
1038
1038
1039 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
1039 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
1040 Py_ssize_t marker, char *phases)
1040 Py_ssize_t marker, char *phases)
1041 {
1041 {
1042 PyObject *iter = NULL;
1042 PyObject *iter = NULL;
1043 PyObject *iter_item = NULL;
1043 PyObject *iter_item = NULL;
1044 Py_ssize_t min_idx = index_length(self) + 1;
1044 Py_ssize_t min_idx = index_length(self) + 1;
1045 long iter_item_long;
1045 long iter_item_long;
1046
1046
1047 if (PyList_GET_SIZE(list) != 0) {
1047 if (PyList_GET_SIZE(list) != 0) {
1048 iter = PyObject_GetIter(list);
1048 iter = PyObject_GetIter(list);
1049 if (iter == NULL)
1049 if (iter == NULL)
1050 return -2;
1050 return -2;
1051 while ((iter_item = PyIter_Next(iter)))
1051 while ((iter_item = PyIter_Next(iter)))
1052 {
1052 {
1053 iter_item_long = PyInt_AS_LONG(iter_item);
1053 iter_item_long = PyInt_AS_LONG(iter_item);
1054 Py_DECREF(iter_item);
1054 Py_DECREF(iter_item);
1055 if (iter_item_long < min_idx)
1055 if (iter_item_long < min_idx)
1056 min_idx = iter_item_long;
1056 min_idx = iter_item_long;
1057 phases[iter_item_long] = marker;
1057 phases[iter_item_long] = marker;
1058 }
1058 }
1059 Py_DECREF(iter);
1059 Py_DECREF(iter);
1060 }
1060 }
1061
1061
1062 return min_idx;
1062 return min_idx;
1063 }
1063 }
1064
1064
1065 static inline void set_phase_from_parents(char *phases, int parent_1,
1065 static inline void set_phase_from_parents(char *phases, int parent_1,
1066 int parent_2, Py_ssize_t i)
1066 int parent_2, Py_ssize_t i)
1067 {
1067 {
1068 if (parent_1 >= 0 && phases[parent_1] > phases[i])
1068 if (parent_1 >= 0 && phases[parent_1] > phases[i])
1069 phases[i] = phases[parent_1];
1069 phases[i] = phases[parent_1];
1070 if (parent_2 >= 0 && phases[parent_2] > phases[i])
1070 if (parent_2 >= 0 && phases[parent_2] > phases[i])
1071 phases[i] = phases[parent_2];
1071 phases[i] = phases[parent_2];
1072 }
1072 }
1073
1073
1074 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
1074 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
1075 {
1075 {
1076 PyObject *roots = Py_None;
1076 PyObject *roots = Py_None;
1077 PyObject *ret = NULL;
1077 PyObject *ret = NULL;
1078 PyObject *phaseslist = NULL;
1078 PyObject *phaseslist = NULL;
1079 PyObject *phaseroots = NULL;
1079 PyObject *phaseroots = NULL;
1080 PyObject *rev = NULL;
1080 PyObject *rev = NULL;
1081 PyObject *p1 = NULL;
1081 PyObject *p1 = NULL;
1082 PyObject *p2 = NULL;
1082 PyObject *p2 = NULL;
1083 PyObject *phaseset = NULL;
1083 PyObject *phaseset = NULL;
1084 PyObject *phasessetlist = NULL;
1084 PyObject *phasessetlist = NULL;
1085 Py_ssize_t addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
1085 Py_ssize_t addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
1086 Py_ssize_t len = index_length(self) - 1;
1086 Py_ssize_t len = index_length(self) - 1;
1087 Py_ssize_t numphase = 0;
1087 Py_ssize_t numphase = 0;
1088 Py_ssize_t minrevallphases = 0;
1088 Py_ssize_t minrevallphases = 0;
1089 Py_ssize_t minrevphase = 0;
1089 Py_ssize_t minrevphase = 0;
1090 Py_ssize_t i = 0;
1090 Py_ssize_t i = 0;
1091 int parent_1, parent_2;
1091 int parent_1, parent_2;
1092 char *phases = NULL;
1092 char *phases = NULL;
1093 const char *data;
1093 const char *data;
1094 long phase;
1094 long phase;
1095
1095
1096 if (!PyArg_ParseTuple(args, "O", &roots))
1096 if (!PyArg_ParseTuple(args, "O", &roots))
1097 goto release_none;
1097 goto release_none;
1098 if (roots == NULL || !PyList_Check(roots))
1098 if (roots == NULL || !PyList_Check(roots))
1099 goto release_none;
1099 goto release_none;
1100
1100
1101 phases = calloc(len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
1101 phases = calloc(len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
1102 if (phases == NULL)
1102 if (phases == NULL)
1103 goto release_none;
1103 goto release_none;
1104 /* Put the phase information of all the roots in phases */
1104 /* Put the phase information of all the roots in phases */
1105 numphase = PyList_GET_SIZE(roots)+1;
1105 numphase = PyList_GET_SIZE(roots)+1;
1106 minrevallphases = len + 1;
1106 minrevallphases = len + 1;
1107 phasessetlist = PyList_New(numphase);
1107 phasessetlist = PyList_New(numphase);
1108 if (phasessetlist == NULL)
1108 if (phasessetlist == NULL)
1109 goto release_none;
1109 goto release_none;
1110
1110
1111 PyList_SET_ITEM(phasessetlist, 0, Py_None);
1111 PyList_SET_ITEM(phasessetlist, 0, Py_None);
1112 Py_INCREF(Py_None);
1112 Py_INCREF(Py_None);
1113
1113
1114 for (i = 0; i < numphase-1; i++) {
1114 for (i = 0; i < numphase-1; i++) {
1115 phaseroots = PyList_GET_ITEM(roots, i);
1115 phaseroots = PyList_GET_ITEM(roots, i);
1116 phaseset = PySet_New(NULL);
1116 phaseset = PySet_New(NULL);
1117 if (phaseset == NULL)
1117 if (phaseset == NULL)
1118 goto release_phasesetlist;
1118 goto release_phasesetlist;
1119 PyList_SET_ITEM(phasessetlist, i+1, phaseset);
1119 PyList_SET_ITEM(phasessetlist, i+1, phaseset);
1120 if (!PyList_Check(phaseroots))
1120 if (!PyList_Check(phaseroots))
1121 goto release_phasesetlist;
1121 goto release_phasesetlist;
1122 minrevphase = add_roots_get_min(self, phaseroots, i+1, phases);
1122 minrevphase = add_roots_get_min(self, phaseroots, i+1, phases);
1123 if (minrevphase == -2) /* Error from add_roots_get_min */
1123 if (minrevphase == -2) /* Error from add_roots_get_min */
1124 goto release_phasesetlist;
1124 goto release_phasesetlist;
1125 minrevallphases = MIN(minrevallphases, minrevphase);
1125 minrevallphases = MIN(minrevallphases, minrevphase);
1126 }
1126 }
1127 /* Propagate the phase information from the roots to the revs */
1127 /* Propagate the phase information from the roots to the revs */
1128 if (minrevallphases != -1) {
1128 if (minrevallphases != -1) {
1129 for (i = minrevallphases; i < self->raw_length; i++) {
1129 for (i = minrevallphases; i < self->raw_length; i++) {
1130 data = index_deref(self, i);
1130 data = index_deref(self, i);
1131 set_phase_from_parents(phases, getbe32(data+24), getbe32(data+28), i);
1131 set_phase_from_parents(phases, getbe32(data+24), getbe32(data+28), i);
1132 }
1132 }
1133 for (i = 0; i < addlen; i++) {
1133 for (i = 0; i < addlen; i++) {
1134 rev = PyList_GET_ITEM(self->added, i);
1134 rev = PyList_GET_ITEM(self->added, i);
1135 p1 = PyTuple_GET_ITEM(rev, 5);
1135 p1 = PyTuple_GET_ITEM(rev, 5);
1136 p2 = PyTuple_GET_ITEM(rev, 6);
1136 p2 = PyTuple_GET_ITEM(rev, 6);
1137 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
1137 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
1138 PyErr_SetString(PyExc_TypeError, "revlog parents are invalid");
1138 PyErr_SetString(PyExc_TypeError, "revlog parents are invalid");
1139 goto release_phasesetlist;
1139 goto release_phasesetlist;
1140 }
1140 }
1141 parent_1 = (int)PyInt_AS_LONG(p1);
1141 parent_1 = (int)PyInt_AS_LONG(p1);
1142 parent_2 = (int)PyInt_AS_LONG(p2);
1142 parent_2 = (int)PyInt_AS_LONG(p2);
1143 set_phase_from_parents(phases, parent_1, parent_2, i+self->raw_length);
1143 set_phase_from_parents(phases, parent_1, parent_2, i+self->raw_length);
1144 }
1144 }
1145 }
1145 }
1146 /* Transform phase list to a python list */
1146 /* Transform phase list to a python list */
1147 phaseslist = PyList_New(len);
1147 phaseslist = PyList_New(len);
1148 if (phaseslist == NULL)
1148 if (phaseslist == NULL)
1149 goto release_phasesetlist;
1149 goto release_phasesetlist;
1150 for (i = 0; i < len; i++) {
1150 for (i = 0; i < len; i++) {
1151 phase = phases[i];
1151 phase = phases[i];
1152 /* We only store the sets of phase for non public phase, the public phase
1152 /* We only store the sets of phase for non public phase, the public phase
1153 * is computed as a difference */
1153 * is computed as a difference */
1154 if (phase != 0) {
1154 if (phase != 0) {
1155 phaseset = PyList_GET_ITEM(phasessetlist, phase);
1155 phaseset = PyList_GET_ITEM(phasessetlist, phase);
1156 PySet_Add(phaseset, PyInt_FromLong(i));
1156 PySet_Add(phaseset, PyInt_FromLong(i));
1157 }
1157 }
1158 PyList_SET_ITEM(phaseslist, i, PyInt_FromLong(phase));
1158 PyList_SET_ITEM(phaseslist, i, PyInt_FromLong(phase));
1159 }
1159 }
1160 ret = PyList_New(2);
1160 ret = PyList_New(2);
1161 if (ret == NULL)
1161 if (ret == NULL)
1162 goto release_phaseslist;
1162 goto release_phaseslist;
1163
1163
1164 PyList_SET_ITEM(ret, 0, phaseslist);
1164 PyList_SET_ITEM(ret, 0, phaseslist);
1165 PyList_SET_ITEM(ret, 1, phasessetlist);
1165 PyList_SET_ITEM(ret, 1, phasessetlist);
1166 /* We don't release phaseslist and phasessetlist as we return them to
1166 /* We don't release phaseslist and phasessetlist as we return them to
1167 * python */
1167 * python */
1168 goto release_phases;
1168 goto release_phases;
1169
1169
1170 release_phaseslist:
1170 release_phaseslist:
1171 Py_XDECREF(phaseslist);
1171 Py_XDECREF(phaseslist);
1172 release_phasesetlist:
1172 release_phasesetlist:
1173 Py_XDECREF(phasessetlist);
1173 Py_XDECREF(phasessetlist);
1174 release_phases:
1174 release_phases:
1175 free(phases);
1175 free(phases);
1176 release_none:
1176 release_none:
1177 return ret;
1177 return ret;
1178 }
1178 }
1179
1179
1180 static inline void index_get_parents(indexObject *self, Py_ssize_t rev,
1180 static inline void index_get_parents(indexObject *self, Py_ssize_t rev,
1181 int *ps)
1181 int *ps)
1182 {
1182 {
1183 if (rev >= self->length - 1) {
1183 if (rev >= self->length - 1) {
1184 PyObject *tuple = PyList_GET_ITEM(self->added,
1184 PyObject *tuple = PyList_GET_ITEM(self->added,
1185 rev - self->length + 1);
1185 rev - self->length + 1);
1186 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
1186 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
1187 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
1187 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
1188 } else {
1188 } else {
1189 const char *data = index_deref(self, rev);
1189 const char *data = index_deref(self, rev);
1190 ps[0] = getbe32(data + 24);
1190 ps[0] = getbe32(data + 24);
1191 ps[1] = getbe32(data + 28);
1191 ps[1] = getbe32(data + 28);
1192 }
1192 }
1193 }
1193 }
1194
1194
1195 static PyObject *index_headrevs(indexObject *self, PyObject *args)
1195 static PyObject *index_headrevs(indexObject *self, PyObject *args)
1196 {
1196 {
1197 Py_ssize_t i, len, addlen;
1197 Py_ssize_t i, j, len;
1198 char *nothead = NULL;
1198 char *nothead = NULL;
1199 PyObject *heads = NULL;
1199 PyObject *heads = NULL;
1200 PyObject *filter = NULL;
1200 PyObject *filter = NULL;
1201 PyObject *filteredrevs = Py_None;
1201 PyObject *filteredrevs = Py_None;
1202
1202
1203 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
1203 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
1204 return NULL;
1204 return NULL;
1205 }
1205 }
1206
1206
1207 if (self->headrevs && filteredrevs == self->filteredrevs)
1207 if (self->headrevs && filteredrevs == self->filteredrevs)
1208 return list_copy(self->headrevs);
1208 return list_copy(self->headrevs);
1209
1209
1210 Py_DECREF(self->filteredrevs);
1210 Py_DECREF(self->filteredrevs);
1211 self->filteredrevs = filteredrevs;
1211 self->filteredrevs = filteredrevs;
1212 Py_INCREF(filteredrevs);
1212 Py_INCREF(filteredrevs);
1213
1213
1214 if (filteredrevs != Py_None) {
1214 if (filteredrevs != Py_None) {
1215 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
1215 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
1216 if (!filter) {
1216 if (!filter) {
1217 PyErr_SetString(PyExc_TypeError,
1217 PyErr_SetString(PyExc_TypeError,
1218 "filteredrevs has no attribute __contains__");
1218 "filteredrevs has no attribute __contains__");
1219 goto bail;
1219 goto bail;
1220 }
1220 }
1221 }
1221 }
1222
1222
1223 len = index_length(self) - 1;
1223 len = index_length(self) - 1;
1224 heads = PyList_New(0);
1224 heads = PyList_New(0);
1225 if (heads == NULL)
1225 if (heads == NULL)
1226 goto bail;
1226 goto bail;
1227 if (len == 0) {
1227 if (len == 0) {
1228 PyObject *nullid = PyInt_FromLong(-1);
1228 PyObject *nullid = PyInt_FromLong(-1);
1229 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
1229 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
1230 Py_XDECREF(nullid);
1230 Py_XDECREF(nullid);
1231 goto bail;
1231 goto bail;
1232 }
1232 }
1233 goto done;
1233 goto done;
1234 }
1234 }
1235
1235
1236 nothead = calloc(len, 1);
1236 nothead = calloc(len, 1);
1237 if (nothead == NULL)
1237 if (nothead == NULL)
1238 goto bail;
1238 goto bail;
1239
1239
1240 for (i = 0; i < self->raw_length; i++) {
1240 for (i = 0; i < len; i++) {
1241 const char *data;
1241 int isfiltered;
1242 int parent_1, parent_2, isfiltered;
1242 int parents[2];
1243
1243
1244 isfiltered = check_filter(filter, i);
1244 isfiltered = check_filter(filter, i);
1245 if (isfiltered == -1) {
1245 if (isfiltered == -1) {
1246 PyErr_SetString(PyExc_TypeError,
1246 PyErr_SetString(PyExc_TypeError,
1247 "unable to check filter");
1247 "unable to check filter");
1248 goto bail;
1248 goto bail;
1249 }
1249 }
1250
1250
1251 if (isfiltered) {
1251 if (isfiltered) {
1252 nothead[i] = 1;
1252 nothead[i] = 1;
1253 continue;
1253 continue;
1254 }
1254 }
1255
1255
1256 data = index_deref(self, i);
1256 index_get_parents(self, i, parents);
1257 parent_1 = getbe32(data + 24);
1257 for (j = 0; j < 2; j++) {
1258 parent_2 = getbe32(data + 28);
1258 if (parents[j] >= 0)
1259
1259 nothead[parents[j]] = 1;
1260 if (parent_1 >= 0)
1261 nothead[parent_1] = 1;
1262 if (parent_2 >= 0)
1263 nothead[parent_2] = 1;
1264 }
1260 }
1265
1266 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
1267
1268 for (i = 0; i < addlen; i++) {
1269 PyObject *rev = PyList_GET_ITEM(self->added, i);
1270 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
1271 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
1272 long parent_1, parent_2;
1273 int isfiltered;
1274
1275 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
1276 PyErr_SetString(PyExc_TypeError,
1277 "revlog parents are invalid");
1278 goto bail;
1279 }
1280
1281 isfiltered = check_filter(filter, i);
1282 if (isfiltered == -1) {
1283 PyErr_SetString(PyExc_TypeError,
1284 "unable to check filter");
1285 goto bail;
1286 }
1287
1288 if (isfiltered) {
1289 nothead[i] = 1;
1290 continue;
1291 }
1292
1293 parent_1 = PyInt_AS_LONG(p1);
1294 parent_2 = PyInt_AS_LONG(p2);
1295 if (parent_1 >= 0)
1296 nothead[parent_1] = 1;
1297 if (parent_2 >= 0)
1298 nothead[parent_2] = 1;
1299 }
1261 }
1300
1262
1301 for (i = 0; i < len; i++) {
1263 for (i = 0; i < len; i++) {
1302 PyObject *head;
1264 PyObject *head;
1303
1265
1304 if (nothead[i])
1266 if (nothead[i])
1305 continue;
1267 continue;
1306 head = PyInt_FromSsize_t(i);
1268 head = PyInt_FromSsize_t(i);
1307 if (head == NULL || PyList_Append(heads, head) == -1) {
1269 if (head == NULL || PyList_Append(heads, head) == -1) {
1308 Py_XDECREF(head);
1270 Py_XDECREF(head);
1309 goto bail;
1271 goto bail;
1310 }
1272 }
1311 }
1273 }
1312
1274
1313 done:
1275 done:
1314 self->headrevs = heads;
1276 self->headrevs = heads;
1315 Py_XDECREF(filter);
1277 Py_XDECREF(filter);
1316 free(nothead);
1278 free(nothead);
1317 return list_copy(self->headrevs);
1279 return list_copy(self->headrevs);
1318 bail:
1280 bail:
1319 Py_XDECREF(filter);
1281 Py_XDECREF(filter);
1320 Py_XDECREF(heads);
1282 Py_XDECREF(heads);
1321 free(nothead);
1283 free(nothead);
1322 return NULL;
1284 return NULL;
1323 }
1285 }
1324
1286
1325 static inline int nt_level(const char *node, Py_ssize_t level)
1287 static inline int nt_level(const char *node, Py_ssize_t level)
1326 {
1288 {
1327 int v = node[level>>1];
1289 int v = node[level>>1];
1328 if (!(level & 1))
1290 if (!(level & 1))
1329 v >>= 4;
1291 v >>= 4;
1330 return v & 0xf;
1292 return v & 0xf;
1331 }
1293 }
1332
1294
1333 /*
1295 /*
1334 * Return values:
1296 * Return values:
1335 *
1297 *
1336 * -4: match is ambiguous (multiple candidates)
1298 * -4: match is ambiguous (multiple candidates)
1337 * -2: not found
1299 * -2: not found
1338 * rest: valid rev
1300 * rest: valid rev
1339 */
1301 */
1340 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
1302 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
1341 int hex)
1303 int hex)
1342 {
1304 {
1343 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1305 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1344 int level, maxlevel, off;
1306 int level, maxlevel, off;
1345
1307
1346 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
1308 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
1347 return -1;
1309 return -1;
1348
1310
1349 if (self->nt == NULL)
1311 if (self->nt == NULL)
1350 return -2;
1312 return -2;
1351
1313
1352 if (hex)
1314 if (hex)
1353 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
1315 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
1354 else
1316 else
1355 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1317 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1356
1318
1357 for (level = off = 0; level < maxlevel; level++) {
1319 for (level = off = 0; level < maxlevel; level++) {
1358 int k = getnybble(node, level);
1320 int k = getnybble(node, level);
1359 nodetree *n = &self->nt[off];
1321 nodetree *n = &self->nt[off];
1360 int v = n->children[k];
1322 int v = n->children[k];
1361
1323
1362 if (v < 0) {
1324 if (v < 0) {
1363 const char *n;
1325 const char *n;
1364 Py_ssize_t i;
1326 Py_ssize_t i;
1365
1327
1366 v = -(v + 1);
1328 v = -(v + 1);
1367 n = index_node(self, v);
1329 n = index_node(self, v);
1368 if (n == NULL)
1330 if (n == NULL)
1369 return -2;
1331 return -2;
1370 for (i = level; i < maxlevel; i++)
1332 for (i = level; i < maxlevel; i++)
1371 if (getnybble(node, i) != nt_level(n, i))
1333 if (getnybble(node, i) != nt_level(n, i))
1372 return -2;
1334 return -2;
1373 return v;
1335 return v;
1374 }
1336 }
1375 if (v == 0)
1337 if (v == 0)
1376 return -2;
1338 return -2;
1377 off = v;
1339 off = v;
1378 }
1340 }
1379 /* multiple matches against an ambiguous prefix */
1341 /* multiple matches against an ambiguous prefix */
1380 return -4;
1342 return -4;
1381 }
1343 }
1382
1344
1383 static int nt_new(indexObject *self)
1345 static int nt_new(indexObject *self)
1384 {
1346 {
1385 if (self->ntlength == self->ntcapacity) {
1347 if (self->ntlength == self->ntcapacity) {
1386 if (self->ntcapacity >= INT_MAX / (sizeof(nodetree) * 2)) {
1348 if (self->ntcapacity >= INT_MAX / (sizeof(nodetree) * 2)) {
1387 PyErr_SetString(PyExc_MemoryError,
1349 PyErr_SetString(PyExc_MemoryError,
1388 "overflow in nt_new");
1350 "overflow in nt_new");
1389 return -1;
1351 return -1;
1390 }
1352 }
1391 self->ntcapacity *= 2;
1353 self->ntcapacity *= 2;
1392 self->nt = realloc(self->nt,
1354 self->nt = realloc(self->nt,
1393 self->ntcapacity * sizeof(nodetree));
1355 self->ntcapacity * sizeof(nodetree));
1394 if (self->nt == NULL) {
1356 if (self->nt == NULL) {
1395 PyErr_SetString(PyExc_MemoryError, "out of memory");
1357 PyErr_SetString(PyExc_MemoryError, "out of memory");
1396 return -1;
1358 return -1;
1397 }
1359 }
1398 memset(&self->nt[self->ntlength], 0,
1360 memset(&self->nt[self->ntlength], 0,
1399 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
1361 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
1400 }
1362 }
1401 return self->ntlength++;
1363 return self->ntlength++;
1402 }
1364 }
1403
1365
1404 static int nt_insert(indexObject *self, const char *node, int rev)
1366 static int nt_insert(indexObject *self, const char *node, int rev)
1405 {
1367 {
1406 int level = 0;
1368 int level = 0;
1407 int off = 0;
1369 int off = 0;
1408
1370
1409 while (level < 40) {
1371 while (level < 40) {
1410 int k = nt_level(node, level);
1372 int k = nt_level(node, level);
1411 nodetree *n;
1373 nodetree *n;
1412 int v;
1374 int v;
1413
1375
1414 n = &self->nt[off];
1376 n = &self->nt[off];
1415 v = n->children[k];
1377 v = n->children[k];
1416
1378
1417 if (v == 0) {
1379 if (v == 0) {
1418 n->children[k] = -rev - 1;
1380 n->children[k] = -rev - 1;
1419 return 0;
1381 return 0;
1420 }
1382 }
1421 if (v < 0) {
1383 if (v < 0) {
1422 const char *oldnode = index_node(self, -(v + 1));
1384 const char *oldnode = index_node(self, -(v + 1));
1423 int noff;
1385 int noff;
1424
1386
1425 if (!oldnode || !memcmp(oldnode, node, 20)) {
1387 if (!oldnode || !memcmp(oldnode, node, 20)) {
1426 n->children[k] = -rev - 1;
1388 n->children[k] = -rev - 1;
1427 return 0;
1389 return 0;
1428 }
1390 }
1429 noff = nt_new(self);
1391 noff = nt_new(self);
1430 if (noff == -1)
1392 if (noff == -1)
1431 return -1;
1393 return -1;
1432 /* self->nt may have been changed by realloc */
1394 /* self->nt may have been changed by realloc */
1433 self->nt[off].children[k] = noff;
1395 self->nt[off].children[k] = noff;
1434 off = noff;
1396 off = noff;
1435 n = &self->nt[off];
1397 n = &self->nt[off];
1436 n->children[nt_level(oldnode, ++level)] = v;
1398 n->children[nt_level(oldnode, ++level)] = v;
1437 if (level > self->ntdepth)
1399 if (level > self->ntdepth)
1438 self->ntdepth = level;
1400 self->ntdepth = level;
1439 self->ntsplits += 1;
1401 self->ntsplits += 1;
1440 } else {
1402 } else {
1441 level += 1;
1403 level += 1;
1442 off = v;
1404 off = v;
1443 }
1405 }
1444 }
1406 }
1445
1407
1446 return -1;
1408 return -1;
1447 }
1409 }
1448
1410
1449 static int nt_init(indexObject *self)
1411 static int nt_init(indexObject *self)
1450 {
1412 {
1451 if (self->nt == NULL) {
1413 if (self->nt == NULL) {
1452 if (self->raw_length > INT_MAX / sizeof(nodetree)) {
1414 if (self->raw_length > INT_MAX / sizeof(nodetree)) {
1453 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
1415 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
1454 return -1;
1416 return -1;
1455 }
1417 }
1456 self->ntcapacity = self->raw_length < 4
1418 self->ntcapacity = self->raw_length < 4
1457 ? 4 : (int)self->raw_length / 2;
1419 ? 4 : (int)self->raw_length / 2;
1458
1420
1459 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
1421 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
1460 if (self->nt == NULL) {
1422 if (self->nt == NULL) {
1461 PyErr_NoMemory();
1423 PyErr_NoMemory();
1462 return -1;
1424 return -1;
1463 }
1425 }
1464 self->ntlength = 1;
1426 self->ntlength = 1;
1465 self->ntrev = (int)index_length(self) - 1;
1427 self->ntrev = (int)index_length(self) - 1;
1466 self->ntlookups = 1;
1428 self->ntlookups = 1;
1467 self->ntmisses = 0;
1429 self->ntmisses = 0;
1468 if (nt_insert(self, nullid, INT_MAX) == -1)
1430 if (nt_insert(self, nullid, INT_MAX) == -1)
1469 return -1;
1431 return -1;
1470 }
1432 }
1471 return 0;
1433 return 0;
1472 }
1434 }
1473
1435
1474 /*
1436 /*
1475 * Return values:
1437 * Return values:
1476 *
1438 *
1477 * -3: error (exception set)
1439 * -3: error (exception set)
1478 * -2: not found (no exception set)
1440 * -2: not found (no exception set)
1479 * rest: valid rev
1441 * rest: valid rev
1480 */
1442 */
1481 static int index_find_node(indexObject *self,
1443 static int index_find_node(indexObject *self,
1482 const char *node, Py_ssize_t nodelen)
1444 const char *node, Py_ssize_t nodelen)
1483 {
1445 {
1484 int rev;
1446 int rev;
1485
1447
1486 self->ntlookups++;
1448 self->ntlookups++;
1487 rev = nt_find(self, node, nodelen, 0);
1449 rev = nt_find(self, node, nodelen, 0);
1488 if (rev >= -1)
1450 if (rev >= -1)
1489 return rev;
1451 return rev;
1490
1452
1491 if (nt_init(self) == -1)
1453 if (nt_init(self) == -1)
1492 return -3;
1454 return -3;
1493
1455
1494 /*
1456 /*
1495 * For the first handful of lookups, we scan the entire index,
1457 * For the first handful of lookups, we scan the entire index,
1496 * and cache only the matching nodes. This optimizes for cases
1458 * and cache only the matching nodes. This optimizes for cases
1497 * like "hg tip", where only a few nodes are accessed.
1459 * like "hg tip", where only a few nodes are accessed.
1498 *
1460 *
1499 * After that, we cache every node we visit, using a single
1461 * After that, we cache every node we visit, using a single
1500 * scan amortized over multiple lookups. This gives the best
1462 * scan amortized over multiple lookups. This gives the best
1501 * bulk performance, e.g. for "hg log".
1463 * bulk performance, e.g. for "hg log".
1502 */
1464 */
1503 if (self->ntmisses++ < 4) {
1465 if (self->ntmisses++ < 4) {
1504 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1466 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1505 const char *n = index_node(self, rev);
1467 const char *n = index_node(self, rev);
1506 if (n == NULL)
1468 if (n == NULL)
1507 return -2;
1469 return -2;
1508 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1470 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1509 if (nt_insert(self, n, rev) == -1)
1471 if (nt_insert(self, n, rev) == -1)
1510 return -3;
1472 return -3;
1511 break;
1473 break;
1512 }
1474 }
1513 }
1475 }
1514 } else {
1476 } else {
1515 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1477 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1516 const char *n = index_node(self, rev);
1478 const char *n = index_node(self, rev);
1517 if (n == NULL) {
1479 if (n == NULL) {
1518 self->ntrev = rev + 1;
1480 self->ntrev = rev + 1;
1519 return -2;
1481 return -2;
1520 }
1482 }
1521 if (nt_insert(self, n, rev) == -1) {
1483 if (nt_insert(self, n, rev) == -1) {
1522 self->ntrev = rev + 1;
1484 self->ntrev = rev + 1;
1523 return -3;
1485 return -3;
1524 }
1486 }
1525 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1487 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1526 break;
1488 break;
1527 }
1489 }
1528 }
1490 }
1529 self->ntrev = rev;
1491 self->ntrev = rev;
1530 }
1492 }
1531
1493
1532 if (rev >= 0)
1494 if (rev >= 0)
1533 return rev;
1495 return rev;
1534 return -2;
1496 return -2;
1535 }
1497 }
1536
1498
1537 static PyObject *raise_revlog_error(void)
1499 static PyObject *raise_revlog_error(void)
1538 {
1500 {
1539 static PyObject *errclass;
1501 static PyObject *errclass;
1540 PyObject *mod = NULL, *errobj;
1502 PyObject *mod = NULL, *errobj;
1541
1503
1542 if (errclass == NULL) {
1504 if (errclass == NULL) {
1543 PyObject *dict;
1505 PyObject *dict;
1544
1506
1545 mod = PyImport_ImportModule("mercurial.error");
1507 mod = PyImport_ImportModule("mercurial.error");
1546 if (mod == NULL)
1508 if (mod == NULL)
1547 goto classfail;
1509 goto classfail;
1548
1510
1549 dict = PyModule_GetDict(mod);
1511 dict = PyModule_GetDict(mod);
1550 if (dict == NULL)
1512 if (dict == NULL)
1551 goto classfail;
1513 goto classfail;
1552
1514
1553 errclass = PyDict_GetItemString(dict, "RevlogError");
1515 errclass = PyDict_GetItemString(dict, "RevlogError");
1554 if (errclass == NULL) {
1516 if (errclass == NULL) {
1555 PyErr_SetString(PyExc_SystemError,
1517 PyErr_SetString(PyExc_SystemError,
1556 "could not find RevlogError");
1518 "could not find RevlogError");
1557 goto classfail;
1519 goto classfail;
1558 }
1520 }
1559 Py_INCREF(errclass);
1521 Py_INCREF(errclass);
1560 Py_DECREF(mod);
1522 Py_DECREF(mod);
1561 }
1523 }
1562
1524
1563 errobj = PyObject_CallFunction(errclass, NULL);
1525 errobj = PyObject_CallFunction(errclass, NULL);
1564 if (errobj == NULL)
1526 if (errobj == NULL)
1565 return NULL;
1527 return NULL;
1566 PyErr_SetObject(errclass, errobj);
1528 PyErr_SetObject(errclass, errobj);
1567 return errobj;
1529 return errobj;
1568
1530
1569 classfail:
1531 classfail:
1570 Py_XDECREF(mod);
1532 Py_XDECREF(mod);
1571 return NULL;
1533 return NULL;
1572 }
1534 }
1573
1535
1574 static PyObject *index_getitem(indexObject *self, PyObject *value)
1536 static PyObject *index_getitem(indexObject *self, PyObject *value)
1575 {
1537 {
1576 char *node;
1538 char *node;
1577 Py_ssize_t nodelen;
1539 Py_ssize_t nodelen;
1578 int rev;
1540 int rev;
1579
1541
1580 if (PyInt_Check(value))
1542 if (PyInt_Check(value))
1581 return index_get(self, PyInt_AS_LONG(value));
1543 return index_get(self, PyInt_AS_LONG(value));
1582
1544
1583 if (node_check(value, &node, &nodelen) == -1)
1545 if (node_check(value, &node, &nodelen) == -1)
1584 return NULL;
1546 return NULL;
1585 rev = index_find_node(self, node, nodelen);
1547 rev = index_find_node(self, node, nodelen);
1586 if (rev >= -1)
1548 if (rev >= -1)
1587 return PyInt_FromLong(rev);
1549 return PyInt_FromLong(rev);
1588 if (rev == -2)
1550 if (rev == -2)
1589 raise_revlog_error();
1551 raise_revlog_error();
1590 return NULL;
1552 return NULL;
1591 }
1553 }
1592
1554
1593 static int nt_partialmatch(indexObject *self, const char *node,
1555 static int nt_partialmatch(indexObject *self, const char *node,
1594 Py_ssize_t nodelen)
1556 Py_ssize_t nodelen)
1595 {
1557 {
1596 int rev;
1558 int rev;
1597
1559
1598 if (nt_init(self) == -1)
1560 if (nt_init(self) == -1)
1599 return -3;
1561 return -3;
1600
1562
1601 if (self->ntrev > 0) {
1563 if (self->ntrev > 0) {
1602 /* ensure that the radix tree is fully populated */
1564 /* ensure that the radix tree is fully populated */
1603 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1565 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1604 const char *n = index_node(self, rev);
1566 const char *n = index_node(self, rev);
1605 if (n == NULL)
1567 if (n == NULL)
1606 return -2;
1568 return -2;
1607 if (nt_insert(self, n, rev) == -1)
1569 if (nt_insert(self, n, rev) == -1)
1608 return -3;
1570 return -3;
1609 }
1571 }
1610 self->ntrev = rev;
1572 self->ntrev = rev;
1611 }
1573 }
1612
1574
1613 return nt_find(self, node, nodelen, 1);
1575 return nt_find(self, node, nodelen, 1);
1614 }
1576 }
1615
1577
1616 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1578 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1617 {
1579 {
1618 const char *fullnode;
1580 const char *fullnode;
1619 int nodelen;
1581 int nodelen;
1620 char *node;
1582 char *node;
1621 int rev, i;
1583 int rev, i;
1622
1584
1623 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1585 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1624 return NULL;
1586 return NULL;
1625
1587
1626 if (nodelen < 4) {
1588 if (nodelen < 4) {
1627 PyErr_SetString(PyExc_ValueError, "key too short");
1589 PyErr_SetString(PyExc_ValueError, "key too short");
1628 return NULL;
1590 return NULL;
1629 }
1591 }
1630
1592
1631 if (nodelen > 40) {
1593 if (nodelen > 40) {
1632 PyErr_SetString(PyExc_ValueError, "key too long");
1594 PyErr_SetString(PyExc_ValueError, "key too long");
1633 return NULL;
1595 return NULL;
1634 }
1596 }
1635
1597
1636 for (i = 0; i < nodelen; i++)
1598 for (i = 0; i < nodelen; i++)
1637 hexdigit(node, i);
1599 hexdigit(node, i);
1638 if (PyErr_Occurred()) {
1600 if (PyErr_Occurred()) {
1639 /* input contains non-hex characters */
1601 /* input contains non-hex characters */
1640 PyErr_Clear();
1602 PyErr_Clear();
1641 Py_RETURN_NONE;
1603 Py_RETURN_NONE;
1642 }
1604 }
1643
1605
1644 rev = nt_partialmatch(self, node, nodelen);
1606 rev = nt_partialmatch(self, node, nodelen);
1645
1607
1646 switch (rev) {
1608 switch (rev) {
1647 case -4:
1609 case -4:
1648 raise_revlog_error();
1610 raise_revlog_error();
1649 case -3:
1611 case -3:
1650 return NULL;
1612 return NULL;
1651 case -2:
1613 case -2:
1652 Py_RETURN_NONE;
1614 Py_RETURN_NONE;
1653 case -1:
1615 case -1:
1654 return PyString_FromStringAndSize(nullid, 20);
1616 return PyString_FromStringAndSize(nullid, 20);
1655 }
1617 }
1656
1618
1657 fullnode = index_node(self, rev);
1619 fullnode = index_node(self, rev);
1658 if (fullnode == NULL) {
1620 if (fullnode == NULL) {
1659 PyErr_Format(PyExc_IndexError,
1621 PyErr_Format(PyExc_IndexError,
1660 "could not access rev %d", rev);
1622 "could not access rev %d", rev);
1661 return NULL;
1623 return NULL;
1662 }
1624 }
1663 return PyString_FromStringAndSize(fullnode, 20);
1625 return PyString_FromStringAndSize(fullnode, 20);
1664 }
1626 }
1665
1627
1666 static PyObject *index_m_get(indexObject *self, PyObject *args)
1628 static PyObject *index_m_get(indexObject *self, PyObject *args)
1667 {
1629 {
1668 Py_ssize_t nodelen;
1630 Py_ssize_t nodelen;
1669 PyObject *val;
1631 PyObject *val;
1670 char *node;
1632 char *node;
1671 int rev;
1633 int rev;
1672
1634
1673 if (!PyArg_ParseTuple(args, "O", &val))
1635 if (!PyArg_ParseTuple(args, "O", &val))
1674 return NULL;
1636 return NULL;
1675 if (node_check(val, &node, &nodelen) == -1)
1637 if (node_check(val, &node, &nodelen) == -1)
1676 return NULL;
1638 return NULL;
1677 rev = index_find_node(self, node, nodelen);
1639 rev = index_find_node(self, node, nodelen);
1678 if (rev == -3)
1640 if (rev == -3)
1679 return NULL;
1641 return NULL;
1680 if (rev == -2)
1642 if (rev == -2)
1681 Py_RETURN_NONE;
1643 Py_RETURN_NONE;
1682 return PyInt_FromLong(rev);
1644 return PyInt_FromLong(rev);
1683 }
1645 }
1684
1646
1685 static int index_contains(indexObject *self, PyObject *value)
1647 static int index_contains(indexObject *self, PyObject *value)
1686 {
1648 {
1687 char *node;
1649 char *node;
1688 Py_ssize_t nodelen;
1650 Py_ssize_t nodelen;
1689
1651
1690 if (PyInt_Check(value)) {
1652 if (PyInt_Check(value)) {
1691 long rev = PyInt_AS_LONG(value);
1653 long rev = PyInt_AS_LONG(value);
1692 return rev >= -1 && rev < index_length(self);
1654 return rev >= -1 && rev < index_length(self);
1693 }
1655 }
1694
1656
1695 if (node_check(value, &node, &nodelen) == -1)
1657 if (node_check(value, &node, &nodelen) == -1)
1696 return -1;
1658 return -1;
1697
1659
1698 switch (index_find_node(self, node, nodelen)) {
1660 switch (index_find_node(self, node, nodelen)) {
1699 case -3:
1661 case -3:
1700 return -1;
1662 return -1;
1701 case -2:
1663 case -2:
1702 return 0;
1664 return 0;
1703 default:
1665 default:
1704 return 1;
1666 return 1;
1705 }
1667 }
1706 }
1668 }
1707
1669
1708 typedef uint64_t bitmask;
1670 typedef uint64_t bitmask;
1709
1671
1710 /*
1672 /*
1711 * Given a disjoint set of revs, return all candidates for the
1673 * Given a disjoint set of revs, return all candidates for the
1712 * greatest common ancestor. In revset notation, this is the set
1674 * greatest common ancestor. In revset notation, this is the set
1713 * "heads(::a and ::b and ...)"
1675 * "heads(::a and ::b and ...)"
1714 */
1676 */
1715 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1677 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1716 int revcount)
1678 int revcount)
1717 {
1679 {
1718 const bitmask allseen = (1ull << revcount) - 1;
1680 const bitmask allseen = (1ull << revcount) - 1;
1719 const bitmask poison = 1ull << revcount;
1681 const bitmask poison = 1ull << revcount;
1720 PyObject *gca = PyList_New(0);
1682 PyObject *gca = PyList_New(0);
1721 int i, v, interesting;
1683 int i, v, interesting;
1722 int maxrev = -1;
1684 int maxrev = -1;
1723 bitmask sp;
1685 bitmask sp;
1724 bitmask *seen;
1686 bitmask *seen;
1725
1687
1726 if (gca == NULL)
1688 if (gca == NULL)
1727 return PyErr_NoMemory();
1689 return PyErr_NoMemory();
1728
1690
1729 for (i = 0; i < revcount; i++) {
1691 for (i = 0; i < revcount; i++) {
1730 if (revs[i] > maxrev)
1692 if (revs[i] > maxrev)
1731 maxrev = revs[i];
1693 maxrev = revs[i];
1732 }
1694 }
1733
1695
1734 seen = calloc(sizeof(*seen), maxrev + 1);
1696 seen = calloc(sizeof(*seen), maxrev + 1);
1735 if (seen == NULL) {
1697 if (seen == NULL) {
1736 Py_DECREF(gca);
1698 Py_DECREF(gca);
1737 return PyErr_NoMemory();
1699 return PyErr_NoMemory();
1738 }
1700 }
1739
1701
1740 for (i = 0; i < revcount; i++)
1702 for (i = 0; i < revcount; i++)
1741 seen[revs[i]] = 1ull << i;
1703 seen[revs[i]] = 1ull << i;
1742
1704
1743 interesting = revcount;
1705 interesting = revcount;
1744
1706
1745 for (v = maxrev; v >= 0 && interesting; v--) {
1707 for (v = maxrev; v >= 0 && interesting; v--) {
1746 bitmask sv = seen[v];
1708 bitmask sv = seen[v];
1747 int parents[2];
1709 int parents[2];
1748
1710
1749 if (!sv)
1711 if (!sv)
1750 continue;
1712 continue;
1751
1713
1752 if (sv < poison) {
1714 if (sv < poison) {
1753 interesting -= 1;
1715 interesting -= 1;
1754 if (sv == allseen) {
1716 if (sv == allseen) {
1755 PyObject *obj = PyInt_FromLong(v);
1717 PyObject *obj = PyInt_FromLong(v);
1756 if (obj == NULL)
1718 if (obj == NULL)
1757 goto bail;
1719 goto bail;
1758 if (PyList_Append(gca, obj) == -1) {
1720 if (PyList_Append(gca, obj) == -1) {
1759 Py_DECREF(obj);
1721 Py_DECREF(obj);
1760 goto bail;
1722 goto bail;
1761 }
1723 }
1762 sv |= poison;
1724 sv |= poison;
1763 for (i = 0; i < revcount; i++) {
1725 for (i = 0; i < revcount; i++) {
1764 if (revs[i] == v)
1726 if (revs[i] == v)
1765 goto done;
1727 goto done;
1766 }
1728 }
1767 }
1729 }
1768 }
1730 }
1769 index_get_parents(self, v, parents);
1731 index_get_parents(self, v, parents);
1770
1732
1771 for (i = 0; i < 2; i++) {
1733 for (i = 0; i < 2; i++) {
1772 int p = parents[i];
1734 int p = parents[i];
1773 if (p == -1)
1735 if (p == -1)
1774 continue;
1736 continue;
1775 sp = seen[p];
1737 sp = seen[p];
1776 if (sv < poison) {
1738 if (sv < poison) {
1777 if (sp == 0) {
1739 if (sp == 0) {
1778 seen[p] = sv;
1740 seen[p] = sv;
1779 interesting++;
1741 interesting++;
1780 }
1742 }
1781 else if (sp != sv)
1743 else if (sp != sv)
1782 seen[p] |= sv;
1744 seen[p] |= sv;
1783 } else {
1745 } else {
1784 if (sp && sp < poison)
1746 if (sp && sp < poison)
1785 interesting--;
1747 interesting--;
1786 seen[p] = sv;
1748 seen[p] = sv;
1787 }
1749 }
1788 }
1750 }
1789 }
1751 }
1790
1752
1791 done:
1753 done:
1792 free(seen);
1754 free(seen);
1793 return gca;
1755 return gca;
1794 bail:
1756 bail:
1795 free(seen);
1757 free(seen);
1796 Py_XDECREF(gca);
1758 Py_XDECREF(gca);
1797 return NULL;
1759 return NULL;
1798 }
1760 }
1799
1761
1800 /*
1762 /*
1801 * Given a disjoint set of revs, return the subset with the longest
1763 * Given a disjoint set of revs, return the subset with the longest
1802 * path to the root.
1764 * path to the root.
1803 */
1765 */
1804 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1766 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1805 {
1767 {
1806 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1768 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1807 static const Py_ssize_t capacity = 24;
1769 static const Py_ssize_t capacity = 24;
1808 int *depth, *interesting = NULL;
1770 int *depth, *interesting = NULL;
1809 int i, j, v, ninteresting;
1771 int i, j, v, ninteresting;
1810 PyObject *dict = NULL, *keys = NULL;
1772 PyObject *dict = NULL, *keys = NULL;
1811 long *seen = NULL;
1773 long *seen = NULL;
1812 int maxrev = -1;
1774 int maxrev = -1;
1813 long final;
1775 long final;
1814
1776
1815 if (revcount > capacity) {
1777 if (revcount > capacity) {
1816 PyErr_Format(PyExc_OverflowError,
1778 PyErr_Format(PyExc_OverflowError,
1817 "bitset size (%ld) > capacity (%ld)",
1779 "bitset size (%ld) > capacity (%ld)",
1818 (long)revcount, (long)capacity);
1780 (long)revcount, (long)capacity);
1819 return NULL;
1781 return NULL;
1820 }
1782 }
1821
1783
1822 for (i = 0; i < revcount; i++) {
1784 for (i = 0; i < revcount; i++) {
1823 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1785 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1824 if (n > maxrev)
1786 if (n > maxrev)
1825 maxrev = n;
1787 maxrev = n;
1826 }
1788 }
1827
1789
1828 depth = calloc(sizeof(*depth), maxrev + 1);
1790 depth = calloc(sizeof(*depth), maxrev + 1);
1829 if (depth == NULL)
1791 if (depth == NULL)
1830 return PyErr_NoMemory();
1792 return PyErr_NoMemory();
1831
1793
1832 seen = calloc(sizeof(*seen), maxrev + 1);
1794 seen = calloc(sizeof(*seen), maxrev + 1);
1833 if (seen == NULL) {
1795 if (seen == NULL) {
1834 PyErr_NoMemory();
1796 PyErr_NoMemory();
1835 goto bail;
1797 goto bail;
1836 }
1798 }
1837
1799
1838 interesting = calloc(sizeof(*interesting), 2 << revcount);
1800 interesting = calloc(sizeof(*interesting), 2 << revcount);
1839 if (interesting == NULL) {
1801 if (interesting == NULL) {
1840 PyErr_NoMemory();
1802 PyErr_NoMemory();
1841 goto bail;
1803 goto bail;
1842 }
1804 }
1843
1805
1844 if (PyList_Sort(revs) == -1)
1806 if (PyList_Sort(revs) == -1)
1845 goto bail;
1807 goto bail;
1846
1808
1847 for (i = 0; i < revcount; i++) {
1809 for (i = 0; i < revcount; i++) {
1848 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1810 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1849 long b = 1l << i;
1811 long b = 1l << i;
1850 depth[n] = 1;
1812 depth[n] = 1;
1851 seen[n] = b;
1813 seen[n] = b;
1852 interesting[b] = 1;
1814 interesting[b] = 1;
1853 }
1815 }
1854
1816
1855 ninteresting = (int)revcount;
1817 ninteresting = (int)revcount;
1856
1818
1857 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1819 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1858 int dv = depth[v];
1820 int dv = depth[v];
1859 int parents[2];
1821 int parents[2];
1860 long sv;
1822 long sv;
1861
1823
1862 if (dv == 0)
1824 if (dv == 0)
1863 continue;
1825 continue;
1864
1826
1865 sv = seen[v];
1827 sv = seen[v];
1866 index_get_parents(self, v, parents);
1828 index_get_parents(self, v, parents);
1867
1829
1868 for (i = 0; i < 2; i++) {
1830 for (i = 0; i < 2; i++) {
1869 int p = parents[i];
1831 int p = parents[i];
1870 long nsp, sp;
1832 long nsp, sp;
1871 int dp;
1833 int dp;
1872
1834
1873 if (p == -1)
1835 if (p == -1)
1874 continue;
1836 continue;
1875
1837
1876 dp = depth[p];
1838 dp = depth[p];
1877 nsp = sp = seen[p];
1839 nsp = sp = seen[p];
1878 if (dp <= dv) {
1840 if (dp <= dv) {
1879 depth[p] = dv + 1;
1841 depth[p] = dv + 1;
1880 if (sp != sv) {
1842 if (sp != sv) {
1881 interesting[sv] += 1;
1843 interesting[sv] += 1;
1882 nsp = seen[p] = sv;
1844 nsp = seen[p] = sv;
1883 if (sp) {
1845 if (sp) {
1884 interesting[sp] -= 1;
1846 interesting[sp] -= 1;
1885 if (interesting[sp] == 0)
1847 if (interesting[sp] == 0)
1886 ninteresting -= 1;
1848 ninteresting -= 1;
1887 }
1849 }
1888 }
1850 }
1889 }
1851 }
1890 else if (dv == dp - 1) {
1852 else if (dv == dp - 1) {
1891 nsp = sp | sv;
1853 nsp = sp | sv;
1892 if (nsp == sp)
1854 if (nsp == sp)
1893 continue;
1855 continue;
1894 seen[p] = nsp;
1856 seen[p] = nsp;
1895 interesting[sp] -= 1;
1857 interesting[sp] -= 1;
1896 if (interesting[sp] == 0 && interesting[nsp] > 0)
1858 if (interesting[sp] == 0 && interesting[nsp] > 0)
1897 ninteresting -= 1;
1859 ninteresting -= 1;
1898 interesting[nsp] += 1;
1860 interesting[nsp] += 1;
1899 }
1861 }
1900 }
1862 }
1901 interesting[sv] -= 1;
1863 interesting[sv] -= 1;
1902 if (interesting[sv] == 0)
1864 if (interesting[sv] == 0)
1903 ninteresting -= 1;
1865 ninteresting -= 1;
1904 }
1866 }
1905
1867
1906 final = 0;
1868 final = 0;
1907 j = ninteresting;
1869 j = ninteresting;
1908 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1870 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1909 if (interesting[i] == 0)
1871 if (interesting[i] == 0)
1910 continue;
1872 continue;
1911 final |= i;
1873 final |= i;
1912 j -= 1;
1874 j -= 1;
1913 }
1875 }
1914 if (final == 0) {
1876 if (final == 0) {
1915 keys = PyList_New(0);
1877 keys = PyList_New(0);
1916 goto bail;
1878 goto bail;
1917 }
1879 }
1918
1880
1919 dict = PyDict_New();
1881 dict = PyDict_New();
1920 if (dict == NULL)
1882 if (dict == NULL)
1921 goto bail;
1883 goto bail;
1922
1884
1923 for (i = 0; i < revcount; i++) {
1885 for (i = 0; i < revcount; i++) {
1924 PyObject *key;
1886 PyObject *key;
1925
1887
1926 if ((final & (1 << i)) == 0)
1888 if ((final & (1 << i)) == 0)
1927 continue;
1889 continue;
1928
1890
1929 key = PyList_GET_ITEM(revs, i);
1891 key = PyList_GET_ITEM(revs, i);
1930 Py_INCREF(key);
1892 Py_INCREF(key);
1931 Py_INCREF(Py_None);
1893 Py_INCREF(Py_None);
1932 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1894 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1933 Py_DECREF(key);
1895 Py_DECREF(key);
1934 Py_DECREF(Py_None);
1896 Py_DECREF(Py_None);
1935 goto bail;
1897 goto bail;
1936 }
1898 }
1937 }
1899 }
1938
1900
1939 keys = PyDict_Keys(dict);
1901 keys = PyDict_Keys(dict);
1940
1902
1941 bail:
1903 bail:
1942 free(depth);
1904 free(depth);
1943 free(seen);
1905 free(seen);
1944 free(interesting);
1906 free(interesting);
1945 Py_XDECREF(dict);
1907 Py_XDECREF(dict);
1946
1908
1947 return keys;
1909 return keys;
1948 }
1910 }
1949
1911
1950 /*
1912 /*
1951 * Given a (possibly overlapping) set of revs, return all the
1913 * Given a (possibly overlapping) set of revs, return all the
1952 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1914 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1953 */
1915 */
1954 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1916 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1955 {
1917 {
1956 PyObject *ret = NULL;
1918 PyObject *ret = NULL;
1957 Py_ssize_t argcount, i, len;
1919 Py_ssize_t argcount, i, len;
1958 bitmask repeat = 0;
1920 bitmask repeat = 0;
1959 int revcount = 0;
1921 int revcount = 0;
1960 int *revs;
1922 int *revs;
1961
1923
1962 argcount = PySequence_Length(args);
1924 argcount = PySequence_Length(args);
1963 revs = malloc(argcount * sizeof(*revs));
1925 revs = malloc(argcount * sizeof(*revs));
1964 if (argcount > 0 && revs == NULL)
1926 if (argcount > 0 && revs == NULL)
1965 return PyErr_NoMemory();
1927 return PyErr_NoMemory();
1966 len = index_length(self) - 1;
1928 len = index_length(self) - 1;
1967
1929
1968 for (i = 0; i < argcount; i++) {
1930 for (i = 0; i < argcount; i++) {
1969 static const int capacity = 24;
1931 static const int capacity = 24;
1970 PyObject *obj = PySequence_GetItem(args, i);
1932 PyObject *obj = PySequence_GetItem(args, i);
1971 bitmask x;
1933 bitmask x;
1972 long val;
1934 long val;
1973
1935
1974 if (!PyInt_Check(obj)) {
1936 if (!PyInt_Check(obj)) {
1975 PyErr_SetString(PyExc_TypeError,
1937 PyErr_SetString(PyExc_TypeError,
1976 "arguments must all be ints");
1938 "arguments must all be ints");
1977 Py_DECREF(obj);
1939 Py_DECREF(obj);
1978 goto bail;
1940 goto bail;
1979 }
1941 }
1980 val = PyInt_AsLong(obj);
1942 val = PyInt_AsLong(obj);
1981 Py_DECREF(obj);
1943 Py_DECREF(obj);
1982 if (val == -1) {
1944 if (val == -1) {
1983 ret = PyList_New(0);
1945 ret = PyList_New(0);
1984 goto done;
1946 goto done;
1985 }
1947 }
1986 if (val < 0 || val >= len) {
1948 if (val < 0 || val >= len) {
1987 PyErr_SetString(PyExc_IndexError,
1949 PyErr_SetString(PyExc_IndexError,
1988 "index out of range");
1950 "index out of range");
1989 goto bail;
1951 goto bail;
1990 }
1952 }
1991 /* this cheesy bloom filter lets us avoid some more
1953 /* this cheesy bloom filter lets us avoid some more
1992 * expensive duplicate checks in the common set-is-disjoint
1954 * expensive duplicate checks in the common set-is-disjoint
1993 * case */
1955 * case */
1994 x = 1ull << (val & 0x3f);
1956 x = 1ull << (val & 0x3f);
1995 if (repeat & x) {
1957 if (repeat & x) {
1996 int k;
1958 int k;
1997 for (k = 0; k < revcount; k++) {
1959 for (k = 0; k < revcount; k++) {
1998 if (val == revs[k])
1960 if (val == revs[k])
1999 goto duplicate;
1961 goto duplicate;
2000 }
1962 }
2001 }
1963 }
2002 else repeat |= x;
1964 else repeat |= x;
2003 if (revcount >= capacity) {
1965 if (revcount >= capacity) {
2004 PyErr_Format(PyExc_OverflowError,
1966 PyErr_Format(PyExc_OverflowError,
2005 "bitset size (%d) > capacity (%d)",
1967 "bitset size (%d) > capacity (%d)",
2006 revcount, capacity);
1968 revcount, capacity);
2007 goto bail;
1969 goto bail;
2008 }
1970 }
2009 revs[revcount++] = (int)val;
1971 revs[revcount++] = (int)val;
2010 duplicate:;
1972 duplicate:;
2011 }
1973 }
2012
1974
2013 if (revcount == 0) {
1975 if (revcount == 0) {
2014 ret = PyList_New(0);
1976 ret = PyList_New(0);
2015 goto done;
1977 goto done;
2016 }
1978 }
2017 if (revcount == 1) {
1979 if (revcount == 1) {
2018 PyObject *obj;
1980 PyObject *obj;
2019 ret = PyList_New(1);
1981 ret = PyList_New(1);
2020 if (ret == NULL)
1982 if (ret == NULL)
2021 goto bail;
1983 goto bail;
2022 obj = PyInt_FromLong(revs[0]);
1984 obj = PyInt_FromLong(revs[0]);
2023 if (obj == NULL)
1985 if (obj == NULL)
2024 goto bail;
1986 goto bail;
2025 PyList_SET_ITEM(ret, 0, obj);
1987 PyList_SET_ITEM(ret, 0, obj);
2026 goto done;
1988 goto done;
2027 }
1989 }
2028
1990
2029 ret = find_gca_candidates(self, revs, revcount);
1991 ret = find_gca_candidates(self, revs, revcount);
2030 if (ret == NULL)
1992 if (ret == NULL)
2031 goto bail;
1993 goto bail;
2032
1994
2033 done:
1995 done:
2034 free(revs);
1996 free(revs);
2035 return ret;
1997 return ret;
2036
1998
2037 bail:
1999 bail:
2038 free(revs);
2000 free(revs);
2039 Py_XDECREF(ret);
2001 Py_XDECREF(ret);
2040 return NULL;
2002 return NULL;
2041 }
2003 }
2042
2004
2043 /*
2005 /*
2044 * Given a (possibly overlapping) set of revs, return the greatest
2006 * Given a (possibly overlapping) set of revs, return the greatest
2045 * common ancestors: those with the longest path to the root.
2007 * common ancestors: those with the longest path to the root.
2046 */
2008 */
2047 static PyObject *index_ancestors(indexObject *self, PyObject *args)
2009 static PyObject *index_ancestors(indexObject *self, PyObject *args)
2048 {
2010 {
2049 PyObject *gca = index_commonancestorsheads(self, args);
2011 PyObject *gca = index_commonancestorsheads(self, args);
2050 if (gca == NULL)
2012 if (gca == NULL)
2051 return NULL;
2013 return NULL;
2052
2014
2053 if (PyList_GET_SIZE(gca) <= 1) {
2015 if (PyList_GET_SIZE(gca) <= 1) {
2054 Py_INCREF(gca);
2016 Py_INCREF(gca);
2055 return gca;
2017 return gca;
2056 }
2018 }
2057
2019
2058 return find_deepest(self, gca);
2020 return find_deepest(self, gca);
2059 }
2021 }
2060
2022
2061 /*
2023 /*
2062 * Invalidate any trie entries introduced by added revs.
2024 * Invalidate any trie entries introduced by added revs.
2063 */
2025 */
2064 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
2026 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
2065 {
2027 {
2066 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
2028 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
2067
2029
2068 for (i = start; i < len; i++) {
2030 for (i = start; i < len; i++) {
2069 PyObject *tuple = PyList_GET_ITEM(self->added, i);
2031 PyObject *tuple = PyList_GET_ITEM(self->added, i);
2070 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
2032 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
2071
2033
2072 nt_insert(self, PyString_AS_STRING(node), -1);
2034 nt_insert(self, PyString_AS_STRING(node), -1);
2073 }
2035 }
2074
2036
2075 if (start == 0)
2037 if (start == 0)
2076 Py_CLEAR(self->added);
2038 Py_CLEAR(self->added);
2077 }
2039 }
2078
2040
2079 /*
2041 /*
2080 * Delete a numeric range of revs, which must be at the end of the
2042 * Delete a numeric range of revs, which must be at the end of the
2081 * range, but exclude the sentinel nullid entry.
2043 * range, but exclude the sentinel nullid entry.
2082 */
2044 */
2083 static int index_slice_del(indexObject *self, PyObject *item)
2045 static int index_slice_del(indexObject *self, PyObject *item)
2084 {
2046 {
2085 Py_ssize_t start, stop, step, slicelength;
2047 Py_ssize_t start, stop, step, slicelength;
2086 Py_ssize_t length = index_length(self);
2048 Py_ssize_t length = index_length(self);
2087 int ret = 0;
2049 int ret = 0;
2088
2050
2089 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
2051 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
2090 &start, &stop, &step, &slicelength) < 0)
2052 &start, &stop, &step, &slicelength) < 0)
2091 return -1;
2053 return -1;
2092
2054
2093 if (slicelength <= 0)
2055 if (slicelength <= 0)
2094 return 0;
2056 return 0;
2095
2057
2096 if ((step < 0 && start < stop) || (step > 0 && start > stop))
2058 if ((step < 0 && start < stop) || (step > 0 && start > stop))
2097 stop = start;
2059 stop = start;
2098
2060
2099 if (step < 0) {
2061 if (step < 0) {
2100 stop = start + 1;
2062 stop = start + 1;
2101 start = stop + step*(slicelength - 1) - 1;
2063 start = stop + step*(slicelength - 1) - 1;
2102 step = -step;
2064 step = -step;
2103 }
2065 }
2104
2066
2105 if (step != 1) {
2067 if (step != 1) {
2106 PyErr_SetString(PyExc_ValueError,
2068 PyErr_SetString(PyExc_ValueError,
2107 "revlog index delete requires step size of 1");
2069 "revlog index delete requires step size of 1");
2108 return -1;
2070 return -1;
2109 }
2071 }
2110
2072
2111 if (stop != length - 1) {
2073 if (stop != length - 1) {
2112 PyErr_SetString(PyExc_IndexError,
2074 PyErr_SetString(PyExc_IndexError,
2113 "revlog index deletion indices are invalid");
2075 "revlog index deletion indices are invalid");
2114 return -1;
2076 return -1;
2115 }
2077 }
2116
2078
2117 if (start < self->length - 1) {
2079 if (start < self->length - 1) {
2118 if (self->nt) {
2080 if (self->nt) {
2119 Py_ssize_t i;
2081 Py_ssize_t i;
2120
2082
2121 for (i = start + 1; i < self->length - 1; i++) {
2083 for (i = start + 1; i < self->length - 1; i++) {
2122 const char *node = index_node(self, i);
2084 const char *node = index_node(self, i);
2123
2085
2124 if (node)
2086 if (node)
2125 nt_insert(self, node, -1);
2087 nt_insert(self, node, -1);
2126 }
2088 }
2127 if (self->added)
2089 if (self->added)
2128 nt_invalidate_added(self, 0);
2090 nt_invalidate_added(self, 0);
2129 if (self->ntrev > start)
2091 if (self->ntrev > start)
2130 self->ntrev = (int)start;
2092 self->ntrev = (int)start;
2131 }
2093 }
2132 self->length = start + 1;
2094 self->length = start + 1;
2133 if (start < self->raw_length) {
2095 if (start < self->raw_length) {
2134 if (self->cache) {
2096 if (self->cache) {
2135 Py_ssize_t i;
2097 Py_ssize_t i;
2136 for (i = start; i < self->raw_length; i++)
2098 for (i = start; i < self->raw_length; i++)
2137 Py_CLEAR(self->cache[i]);
2099 Py_CLEAR(self->cache[i]);
2138 }
2100 }
2139 self->raw_length = start;
2101 self->raw_length = start;
2140 }
2102 }
2141 goto done;
2103 goto done;
2142 }
2104 }
2143
2105
2144 if (self->nt) {
2106 if (self->nt) {
2145 nt_invalidate_added(self, start - self->length + 1);
2107 nt_invalidate_added(self, start - self->length + 1);
2146 if (self->ntrev > start)
2108 if (self->ntrev > start)
2147 self->ntrev = (int)start;
2109 self->ntrev = (int)start;
2148 }
2110 }
2149 if (self->added)
2111 if (self->added)
2150 ret = PyList_SetSlice(self->added, start - self->length + 1,
2112 ret = PyList_SetSlice(self->added, start - self->length + 1,
2151 PyList_GET_SIZE(self->added), NULL);
2113 PyList_GET_SIZE(self->added), NULL);
2152 done:
2114 done:
2153 Py_CLEAR(self->headrevs);
2115 Py_CLEAR(self->headrevs);
2154 return ret;
2116 return ret;
2155 }
2117 }
2156
2118
2157 /*
2119 /*
2158 * Supported ops:
2120 * Supported ops:
2159 *
2121 *
2160 * slice deletion
2122 * slice deletion
2161 * string assignment (extend node->rev mapping)
2123 * string assignment (extend node->rev mapping)
2162 * string deletion (shrink node->rev mapping)
2124 * string deletion (shrink node->rev mapping)
2163 */
2125 */
2164 static int index_assign_subscript(indexObject *self, PyObject *item,
2126 static int index_assign_subscript(indexObject *self, PyObject *item,
2165 PyObject *value)
2127 PyObject *value)
2166 {
2128 {
2167 char *node;
2129 char *node;
2168 Py_ssize_t nodelen;
2130 Py_ssize_t nodelen;
2169 long rev;
2131 long rev;
2170
2132
2171 if (PySlice_Check(item) && value == NULL)
2133 if (PySlice_Check(item) && value == NULL)
2172 return index_slice_del(self, item);
2134 return index_slice_del(self, item);
2173
2135
2174 if (node_check(item, &node, &nodelen) == -1)
2136 if (node_check(item, &node, &nodelen) == -1)
2175 return -1;
2137 return -1;
2176
2138
2177 if (value == NULL)
2139 if (value == NULL)
2178 return self->nt ? nt_insert(self, node, -1) : 0;
2140 return self->nt ? nt_insert(self, node, -1) : 0;
2179 rev = PyInt_AsLong(value);
2141 rev = PyInt_AsLong(value);
2180 if (rev > INT_MAX || rev < 0) {
2142 if (rev > INT_MAX || rev < 0) {
2181 if (!PyErr_Occurred())
2143 if (!PyErr_Occurred())
2182 PyErr_SetString(PyExc_ValueError, "rev out of range");
2144 PyErr_SetString(PyExc_ValueError, "rev out of range");
2183 return -1;
2145 return -1;
2184 }
2146 }
2185
2147
2186 if (nt_init(self) == -1)
2148 if (nt_init(self) == -1)
2187 return -1;
2149 return -1;
2188 return nt_insert(self, node, (int)rev);
2150 return nt_insert(self, node, (int)rev);
2189 }
2151 }
2190
2152
2191 /*
2153 /*
2192 * Find all RevlogNG entries in an index that has inline data. Update
2154 * Find all RevlogNG entries in an index that has inline data. Update
2193 * the optional "offsets" table with those entries.
2155 * the optional "offsets" table with those entries.
2194 */
2156 */
2195 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
2157 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
2196 {
2158 {
2197 const char *data = PyString_AS_STRING(self->data);
2159 const char *data = PyString_AS_STRING(self->data);
2198 Py_ssize_t pos = 0;
2160 Py_ssize_t pos = 0;
2199 Py_ssize_t end = PyString_GET_SIZE(self->data);
2161 Py_ssize_t end = PyString_GET_SIZE(self->data);
2200 long incr = v1_hdrsize;
2162 long incr = v1_hdrsize;
2201 Py_ssize_t len = 0;
2163 Py_ssize_t len = 0;
2202
2164
2203 while (pos + v1_hdrsize <= end && pos >= 0) {
2165 while (pos + v1_hdrsize <= end && pos >= 0) {
2204 uint32_t comp_len;
2166 uint32_t comp_len;
2205 /* 3rd element of header is length of compressed inline data */
2167 /* 3rd element of header is length of compressed inline data */
2206 comp_len = getbe32(data + pos + 8);
2168 comp_len = getbe32(data + pos + 8);
2207 incr = v1_hdrsize + comp_len;
2169 incr = v1_hdrsize + comp_len;
2208 if (offsets)
2170 if (offsets)
2209 offsets[len] = data + pos;
2171 offsets[len] = data + pos;
2210 len++;
2172 len++;
2211 pos += incr;
2173 pos += incr;
2212 }
2174 }
2213
2175
2214 if (pos != end) {
2176 if (pos != end) {
2215 if (!PyErr_Occurred())
2177 if (!PyErr_Occurred())
2216 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2178 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2217 return -1;
2179 return -1;
2218 }
2180 }
2219
2181
2220 return len;
2182 return len;
2221 }
2183 }
2222
2184
2223 static int index_init(indexObject *self, PyObject *args)
2185 static int index_init(indexObject *self, PyObject *args)
2224 {
2186 {
2225 PyObject *data_obj, *inlined_obj;
2187 PyObject *data_obj, *inlined_obj;
2226 Py_ssize_t size;
2188 Py_ssize_t size;
2227
2189
2228 /* Initialize before argument-checking to avoid index_dealloc() crash. */
2190 /* Initialize before argument-checking to avoid index_dealloc() crash. */
2229 self->raw_length = 0;
2191 self->raw_length = 0;
2230 self->added = NULL;
2192 self->added = NULL;
2231 self->cache = NULL;
2193 self->cache = NULL;
2232 self->data = NULL;
2194 self->data = NULL;
2233 self->headrevs = NULL;
2195 self->headrevs = NULL;
2234 self->filteredrevs = Py_None;
2196 self->filteredrevs = Py_None;
2235 Py_INCREF(Py_None);
2197 Py_INCREF(Py_None);
2236 self->nt = NULL;
2198 self->nt = NULL;
2237 self->offsets = NULL;
2199 self->offsets = NULL;
2238
2200
2239 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
2201 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
2240 return -1;
2202 return -1;
2241 if (!PyString_Check(data_obj)) {
2203 if (!PyString_Check(data_obj)) {
2242 PyErr_SetString(PyExc_TypeError, "data is not a string");
2204 PyErr_SetString(PyExc_TypeError, "data is not a string");
2243 return -1;
2205 return -1;
2244 }
2206 }
2245 size = PyString_GET_SIZE(data_obj);
2207 size = PyString_GET_SIZE(data_obj);
2246
2208
2247 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
2209 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
2248 self->data = data_obj;
2210 self->data = data_obj;
2249
2211
2250 self->ntlength = self->ntcapacity = 0;
2212 self->ntlength = self->ntcapacity = 0;
2251 self->ntdepth = self->ntsplits = 0;
2213 self->ntdepth = self->ntsplits = 0;
2252 self->ntlookups = self->ntmisses = 0;
2214 self->ntlookups = self->ntmisses = 0;
2253 self->ntrev = -1;
2215 self->ntrev = -1;
2254 Py_INCREF(self->data);
2216 Py_INCREF(self->data);
2255
2217
2256 if (self->inlined) {
2218 if (self->inlined) {
2257 Py_ssize_t len = inline_scan(self, NULL);
2219 Py_ssize_t len = inline_scan(self, NULL);
2258 if (len == -1)
2220 if (len == -1)
2259 goto bail;
2221 goto bail;
2260 self->raw_length = len;
2222 self->raw_length = len;
2261 self->length = len + 1;
2223 self->length = len + 1;
2262 } else {
2224 } else {
2263 if (size % v1_hdrsize) {
2225 if (size % v1_hdrsize) {
2264 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2226 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2265 goto bail;
2227 goto bail;
2266 }
2228 }
2267 self->raw_length = size / v1_hdrsize;
2229 self->raw_length = size / v1_hdrsize;
2268 self->length = self->raw_length + 1;
2230 self->length = self->raw_length + 1;
2269 }
2231 }
2270
2232
2271 return 0;
2233 return 0;
2272 bail:
2234 bail:
2273 return -1;
2235 return -1;
2274 }
2236 }
2275
2237
2276 static PyObject *index_nodemap(indexObject *self)
2238 static PyObject *index_nodemap(indexObject *self)
2277 {
2239 {
2278 Py_INCREF(self);
2240 Py_INCREF(self);
2279 return (PyObject *)self;
2241 return (PyObject *)self;
2280 }
2242 }
2281
2243
2282 static void index_dealloc(indexObject *self)
2244 static void index_dealloc(indexObject *self)
2283 {
2245 {
2284 _index_clearcaches(self);
2246 _index_clearcaches(self);
2285 Py_XDECREF(self->filteredrevs);
2247 Py_XDECREF(self->filteredrevs);
2286 Py_XDECREF(self->data);
2248 Py_XDECREF(self->data);
2287 Py_XDECREF(self->added);
2249 Py_XDECREF(self->added);
2288 PyObject_Del(self);
2250 PyObject_Del(self);
2289 }
2251 }
2290
2252
2291 static PySequenceMethods index_sequence_methods = {
2253 static PySequenceMethods index_sequence_methods = {
2292 (lenfunc)index_length, /* sq_length */
2254 (lenfunc)index_length, /* sq_length */
2293 0, /* sq_concat */
2255 0, /* sq_concat */
2294 0, /* sq_repeat */
2256 0, /* sq_repeat */
2295 (ssizeargfunc)index_get, /* sq_item */
2257 (ssizeargfunc)index_get, /* sq_item */
2296 0, /* sq_slice */
2258 0, /* sq_slice */
2297 0, /* sq_ass_item */
2259 0, /* sq_ass_item */
2298 0, /* sq_ass_slice */
2260 0, /* sq_ass_slice */
2299 (objobjproc)index_contains, /* sq_contains */
2261 (objobjproc)index_contains, /* sq_contains */
2300 };
2262 };
2301
2263
2302 static PyMappingMethods index_mapping_methods = {
2264 static PyMappingMethods index_mapping_methods = {
2303 (lenfunc)index_length, /* mp_length */
2265 (lenfunc)index_length, /* mp_length */
2304 (binaryfunc)index_getitem, /* mp_subscript */
2266 (binaryfunc)index_getitem, /* mp_subscript */
2305 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2267 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2306 };
2268 };
2307
2269
2308 static PyMethodDef index_methods[] = {
2270 static PyMethodDef index_methods[] = {
2309 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2271 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2310 "return the gca set of the given revs"},
2272 "return the gca set of the given revs"},
2311 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2273 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2312 METH_VARARGS,
2274 METH_VARARGS,
2313 "return the heads of the common ancestors of the given revs"},
2275 "return the heads of the common ancestors of the given revs"},
2314 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2276 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2315 "clear the index caches"},
2277 "clear the index caches"},
2316 {"get", (PyCFunction)index_m_get, METH_VARARGS,
2278 {"get", (PyCFunction)index_m_get, METH_VARARGS,
2317 "get an index entry"},
2279 "get an index entry"},
2318 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets,
2280 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets,
2319 METH_VARARGS, "compute phases"},
2281 METH_VARARGS, "compute phases"},
2320 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
2282 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
2321 "get head revisions"}, /* Can do filtering since 3.2 */
2283 "get head revisions"}, /* Can do filtering since 3.2 */
2322 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
2284 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
2323 "get filtered head revisions"}, /* Can always do filtering */
2285 "get filtered head revisions"}, /* Can always do filtering */
2324 {"insert", (PyCFunction)index_insert, METH_VARARGS,
2286 {"insert", (PyCFunction)index_insert, METH_VARARGS,
2325 "insert an index entry"},
2287 "insert an index entry"},
2326 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2288 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2327 "match a potentially ambiguous node ID"},
2289 "match a potentially ambiguous node ID"},
2328 {"stats", (PyCFunction)index_stats, METH_NOARGS,
2290 {"stats", (PyCFunction)index_stats, METH_NOARGS,
2329 "stats for the index"},
2291 "stats for the index"},
2330 {NULL} /* Sentinel */
2292 {NULL} /* Sentinel */
2331 };
2293 };
2332
2294
2333 static PyGetSetDef index_getset[] = {
2295 static PyGetSetDef index_getset[] = {
2334 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2296 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2335 {NULL} /* Sentinel */
2297 {NULL} /* Sentinel */
2336 };
2298 };
2337
2299
2338 static PyTypeObject indexType = {
2300 static PyTypeObject indexType = {
2339 PyObject_HEAD_INIT(NULL)
2301 PyObject_HEAD_INIT(NULL)
2340 0, /* ob_size */
2302 0, /* ob_size */
2341 "parsers.index", /* tp_name */
2303 "parsers.index", /* tp_name */
2342 sizeof(indexObject), /* tp_basicsize */
2304 sizeof(indexObject), /* tp_basicsize */
2343 0, /* tp_itemsize */
2305 0, /* tp_itemsize */
2344 (destructor)index_dealloc, /* tp_dealloc */
2306 (destructor)index_dealloc, /* tp_dealloc */
2345 0, /* tp_print */
2307 0, /* tp_print */
2346 0, /* tp_getattr */
2308 0, /* tp_getattr */
2347 0, /* tp_setattr */
2309 0, /* tp_setattr */
2348 0, /* tp_compare */
2310 0, /* tp_compare */
2349 0, /* tp_repr */
2311 0, /* tp_repr */
2350 0, /* tp_as_number */
2312 0, /* tp_as_number */
2351 &index_sequence_methods, /* tp_as_sequence */
2313 &index_sequence_methods, /* tp_as_sequence */
2352 &index_mapping_methods, /* tp_as_mapping */
2314 &index_mapping_methods, /* tp_as_mapping */
2353 0, /* tp_hash */
2315 0, /* tp_hash */
2354 0, /* tp_call */
2316 0, /* tp_call */
2355 0, /* tp_str */
2317 0, /* tp_str */
2356 0, /* tp_getattro */
2318 0, /* tp_getattro */
2357 0, /* tp_setattro */
2319 0, /* tp_setattro */
2358 0, /* tp_as_buffer */
2320 0, /* tp_as_buffer */
2359 Py_TPFLAGS_DEFAULT, /* tp_flags */
2321 Py_TPFLAGS_DEFAULT, /* tp_flags */
2360 "revlog index", /* tp_doc */
2322 "revlog index", /* tp_doc */
2361 0, /* tp_traverse */
2323 0, /* tp_traverse */
2362 0, /* tp_clear */
2324 0, /* tp_clear */
2363 0, /* tp_richcompare */
2325 0, /* tp_richcompare */
2364 0, /* tp_weaklistoffset */
2326 0, /* tp_weaklistoffset */
2365 0, /* tp_iter */
2327 0, /* tp_iter */
2366 0, /* tp_iternext */
2328 0, /* tp_iternext */
2367 index_methods, /* tp_methods */
2329 index_methods, /* tp_methods */
2368 0, /* tp_members */
2330 0, /* tp_members */
2369 index_getset, /* tp_getset */
2331 index_getset, /* tp_getset */
2370 0, /* tp_base */
2332 0, /* tp_base */
2371 0, /* tp_dict */
2333 0, /* tp_dict */
2372 0, /* tp_descr_get */
2334 0, /* tp_descr_get */
2373 0, /* tp_descr_set */
2335 0, /* tp_descr_set */
2374 0, /* tp_dictoffset */
2336 0, /* tp_dictoffset */
2375 (initproc)index_init, /* tp_init */
2337 (initproc)index_init, /* tp_init */
2376 0, /* tp_alloc */
2338 0, /* tp_alloc */
2377 };
2339 };
2378
2340
2379 /*
2341 /*
2380 * returns a tuple of the form (index, index, cache) with elements as
2342 * returns a tuple of the form (index, index, cache) with elements as
2381 * follows:
2343 * follows:
2382 *
2344 *
2383 * index: an index object that lazily parses RevlogNG records
2345 * index: an index object that lazily parses RevlogNG records
2384 * cache: if data is inlined, a tuple (index_file_content, 0), else None
2346 * cache: if data is inlined, a tuple (index_file_content, 0), else None
2385 *
2347 *
2386 * added complications are for backwards compatibility
2348 * added complications are for backwards compatibility
2387 */
2349 */
2388 static PyObject *parse_index2(PyObject *self, PyObject *args)
2350 static PyObject *parse_index2(PyObject *self, PyObject *args)
2389 {
2351 {
2390 PyObject *tuple = NULL, *cache = NULL;
2352 PyObject *tuple = NULL, *cache = NULL;
2391 indexObject *idx;
2353 indexObject *idx;
2392 int ret;
2354 int ret;
2393
2355
2394 idx = PyObject_New(indexObject, &indexType);
2356 idx = PyObject_New(indexObject, &indexType);
2395 if (idx == NULL)
2357 if (idx == NULL)
2396 goto bail;
2358 goto bail;
2397
2359
2398 ret = index_init(idx, args);
2360 ret = index_init(idx, args);
2399 if (ret == -1)
2361 if (ret == -1)
2400 goto bail;
2362 goto bail;
2401
2363
2402 if (idx->inlined) {
2364 if (idx->inlined) {
2403 cache = Py_BuildValue("iO", 0, idx->data);
2365 cache = Py_BuildValue("iO", 0, idx->data);
2404 if (cache == NULL)
2366 if (cache == NULL)
2405 goto bail;
2367 goto bail;
2406 } else {
2368 } else {
2407 cache = Py_None;
2369 cache = Py_None;
2408 Py_INCREF(cache);
2370 Py_INCREF(cache);
2409 }
2371 }
2410
2372
2411 tuple = Py_BuildValue("NN", idx, cache);
2373 tuple = Py_BuildValue("NN", idx, cache);
2412 if (!tuple)
2374 if (!tuple)
2413 goto bail;
2375 goto bail;
2414 return tuple;
2376 return tuple;
2415
2377
2416 bail:
2378 bail:
2417 Py_XDECREF(idx);
2379 Py_XDECREF(idx);
2418 Py_XDECREF(cache);
2380 Py_XDECREF(cache);
2419 Py_XDECREF(tuple);
2381 Py_XDECREF(tuple);
2420 return NULL;
2382 return NULL;
2421 }
2383 }
2422
2384
2423 #define BUMPED_FIX 1
2385 #define BUMPED_FIX 1
2424 #define USING_SHA_256 2
2386 #define USING_SHA_256 2
2425
2387
2426 static PyObject *readshas(
2388 static PyObject *readshas(
2427 const char *source, unsigned char num, Py_ssize_t hashwidth)
2389 const char *source, unsigned char num, Py_ssize_t hashwidth)
2428 {
2390 {
2429 int i;
2391 int i;
2430 PyObject *list = PyTuple_New(num);
2392 PyObject *list = PyTuple_New(num);
2431 if (list == NULL) {
2393 if (list == NULL) {
2432 return NULL;
2394 return NULL;
2433 }
2395 }
2434 for (i = 0; i < num; i++) {
2396 for (i = 0; i < num; i++) {
2435 PyObject *hash = PyString_FromStringAndSize(source, hashwidth);
2397 PyObject *hash = PyString_FromStringAndSize(source, hashwidth);
2436 if (hash == NULL) {
2398 if (hash == NULL) {
2437 Py_DECREF(list);
2399 Py_DECREF(list);
2438 return NULL;
2400 return NULL;
2439 }
2401 }
2440 PyTuple_SetItem(list, i, hash);
2402 PyTuple_SetItem(list, i, hash);
2441 source += hashwidth;
2403 source += hashwidth;
2442 }
2404 }
2443 return list;
2405 return list;
2444 }
2406 }
2445
2407
2446 static PyObject *fm1readmarker(const char *data, uint32_t *msize)
2408 static PyObject *fm1readmarker(const char *data, uint32_t *msize)
2447 {
2409 {
2448 const char *meta;
2410 const char *meta;
2449
2411
2450 double mtime;
2412 double mtime;
2451 int16_t tz;
2413 int16_t tz;
2452 uint16_t flags;
2414 uint16_t flags;
2453 unsigned char nsuccs, nparents, nmetadata;
2415 unsigned char nsuccs, nparents, nmetadata;
2454 Py_ssize_t hashwidth = 20;
2416 Py_ssize_t hashwidth = 20;
2455
2417
2456 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
2418 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
2457 PyObject *metadata = NULL, *ret = NULL;
2419 PyObject *metadata = NULL, *ret = NULL;
2458 int i;
2420 int i;
2459
2421
2460 *msize = getbe32(data);
2422 *msize = getbe32(data);
2461 data += 4;
2423 data += 4;
2462 mtime = getbefloat64(data);
2424 mtime = getbefloat64(data);
2463 data += 8;
2425 data += 8;
2464 tz = getbeint16(data);
2426 tz = getbeint16(data);
2465 data += 2;
2427 data += 2;
2466 flags = getbeuint16(data);
2428 flags = getbeuint16(data);
2467 data += 2;
2429 data += 2;
2468
2430
2469 if (flags & USING_SHA_256) {
2431 if (flags & USING_SHA_256) {
2470 hashwidth = 32;
2432 hashwidth = 32;
2471 }
2433 }
2472
2434
2473 nsuccs = (unsigned char)(*data++);
2435 nsuccs = (unsigned char)(*data++);
2474 nparents = (unsigned char)(*data++);
2436 nparents = (unsigned char)(*data++);
2475 nmetadata = (unsigned char)(*data++);
2437 nmetadata = (unsigned char)(*data++);
2476
2438
2477 prec = PyString_FromStringAndSize(data, hashwidth);
2439 prec = PyString_FromStringAndSize(data, hashwidth);
2478 data += hashwidth;
2440 data += hashwidth;
2479 if (prec == NULL) {
2441 if (prec == NULL) {
2480 goto bail;
2442 goto bail;
2481 }
2443 }
2482
2444
2483 succs = readshas(data, nsuccs, hashwidth);
2445 succs = readshas(data, nsuccs, hashwidth);
2484 if (succs == NULL) {
2446 if (succs == NULL) {
2485 goto bail;
2447 goto bail;
2486 }
2448 }
2487 data += nsuccs * hashwidth;
2449 data += nsuccs * hashwidth;
2488
2450
2489 if (nparents == 1 || nparents == 2) {
2451 if (nparents == 1 || nparents == 2) {
2490 parents = readshas(data, nparents, hashwidth);
2452 parents = readshas(data, nparents, hashwidth);
2491 if (parents == NULL) {
2453 if (parents == NULL) {
2492 goto bail;
2454 goto bail;
2493 }
2455 }
2494 data += nparents * hashwidth;
2456 data += nparents * hashwidth;
2495 } else {
2457 } else {
2496 parents = Py_None;
2458 parents = Py_None;
2497 }
2459 }
2498
2460
2499 meta = data + (2 * nmetadata);
2461 meta = data + (2 * nmetadata);
2500 metadata = PyTuple_New(nmetadata);
2462 metadata = PyTuple_New(nmetadata);
2501 if (metadata == NULL) {
2463 if (metadata == NULL) {
2502 goto bail;
2464 goto bail;
2503 }
2465 }
2504 for (i = 0; i < nmetadata; i++) {
2466 for (i = 0; i < nmetadata; i++) {
2505 PyObject *tmp, *left = NULL, *right = NULL;
2467 PyObject *tmp, *left = NULL, *right = NULL;
2506 Py_ssize_t metasize = (unsigned char)(*data++);
2468 Py_ssize_t metasize = (unsigned char)(*data++);
2507 left = PyString_FromStringAndSize(meta, metasize);
2469 left = PyString_FromStringAndSize(meta, metasize);
2508 meta += metasize;
2470 meta += metasize;
2509 metasize = (unsigned char)(*data++);
2471 metasize = (unsigned char)(*data++);
2510 right = PyString_FromStringAndSize(meta, metasize);
2472 right = PyString_FromStringAndSize(meta, metasize);
2511 meta += metasize;
2473 meta += metasize;
2512 if (!left || !right) {
2474 if (!left || !right) {
2513 Py_XDECREF(left);
2475 Py_XDECREF(left);
2514 Py_XDECREF(right);
2476 Py_XDECREF(right);
2515 goto bail;
2477 goto bail;
2516 }
2478 }
2517 tmp = PyTuple_Pack(2, left, right);
2479 tmp = PyTuple_Pack(2, left, right);
2518 Py_DECREF(left);
2480 Py_DECREF(left);
2519 Py_DECREF(right);
2481 Py_DECREF(right);
2520 if (!tmp) {
2482 if (!tmp) {
2521 goto bail;
2483 goto bail;
2522 }
2484 }
2523 PyTuple_SetItem(metadata, i, tmp);
2485 PyTuple_SetItem(metadata, i, tmp);
2524 }
2486 }
2525 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags,
2487 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags,
2526 metadata, mtime, (int)tz * 60, parents);
2488 metadata, mtime, (int)tz * 60, parents);
2527 bail:
2489 bail:
2528 Py_XDECREF(prec);
2490 Py_XDECREF(prec);
2529 Py_XDECREF(succs);
2491 Py_XDECREF(succs);
2530 Py_XDECREF(metadata);
2492 Py_XDECREF(metadata);
2531 if (parents != Py_None)
2493 if (parents != Py_None)
2532 Py_XDECREF(parents);
2494 Py_XDECREF(parents);
2533 return ret;
2495 return ret;
2534 }
2496 }
2535
2497
2536
2498
2537 static PyObject *fm1readmarkers(PyObject *self, PyObject *args) {
2499 static PyObject *fm1readmarkers(PyObject *self, PyObject *args) {
2538 const char *data;
2500 const char *data;
2539 Py_ssize_t datalen;
2501 Py_ssize_t datalen;
2540 /* only unsigned long because python 2.4, should be Py_ssize_t */
2502 /* only unsigned long because python 2.4, should be Py_ssize_t */
2541 unsigned long offset, stop;
2503 unsigned long offset, stop;
2542 PyObject *markers = NULL;
2504 PyObject *markers = NULL;
2543
2505
2544 /* replace kk with nn when we drop Python 2.4 */
2506 /* replace kk with nn when we drop Python 2.4 */
2545 if (!PyArg_ParseTuple(args, "s#kk", &data, &datalen, &offset, &stop)) {
2507 if (!PyArg_ParseTuple(args, "s#kk", &data, &datalen, &offset, &stop)) {
2546 return NULL;
2508 return NULL;
2547 }
2509 }
2548 data += offset;
2510 data += offset;
2549 markers = PyList_New(0);
2511 markers = PyList_New(0);
2550 if (!markers) {
2512 if (!markers) {
2551 return NULL;
2513 return NULL;
2552 }
2514 }
2553 while (offset < stop) {
2515 while (offset < stop) {
2554 uint32_t msize;
2516 uint32_t msize;
2555 int error;
2517 int error;
2556 PyObject *record = fm1readmarker(data, &msize);
2518 PyObject *record = fm1readmarker(data, &msize);
2557 if (!record) {
2519 if (!record) {
2558 goto bail;
2520 goto bail;
2559 }
2521 }
2560 error = PyList_Append(markers, record);
2522 error = PyList_Append(markers, record);
2561 Py_DECREF(record);
2523 Py_DECREF(record);
2562 if (error) {
2524 if (error) {
2563 goto bail;
2525 goto bail;
2564 }
2526 }
2565 data += msize;
2527 data += msize;
2566 offset += msize;
2528 offset += msize;
2567 }
2529 }
2568 return markers;
2530 return markers;
2569 bail:
2531 bail:
2570 Py_DECREF(markers);
2532 Py_DECREF(markers);
2571 return NULL;
2533 return NULL;
2572 }
2534 }
2573
2535
2574 static char parsers_doc[] = "Efficient content parsing.";
2536 static char parsers_doc[] = "Efficient content parsing.";
2575
2537
2576 PyObject *encodedir(PyObject *self, PyObject *args);
2538 PyObject *encodedir(PyObject *self, PyObject *args);
2577 PyObject *pathencode(PyObject *self, PyObject *args);
2539 PyObject *pathencode(PyObject *self, PyObject *args);
2578 PyObject *lowerencode(PyObject *self, PyObject *args);
2540 PyObject *lowerencode(PyObject *self, PyObject *args);
2579
2541
2580 static PyMethodDef methods[] = {
2542 static PyMethodDef methods[] = {
2581 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
2543 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
2582 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
2544 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
2583 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
2545 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
2584 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
2546 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
2585 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
2547 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
2586 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
2548 {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"},
2587 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
2549 {"make_file_foldmap", make_file_foldmap, METH_VARARGS,
2588 "make file foldmap\n"},
2550 "make file foldmap\n"},
2589 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
2551 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
2590 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
2552 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
2591 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
2553 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
2592 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
2554 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
2593 "parse v1 obsolete markers\n"},
2555 "parse v1 obsolete markers\n"},
2594 {NULL, NULL}
2556 {NULL, NULL}
2595 };
2557 };
2596
2558
2597 void dirs_module_init(PyObject *mod);
2559 void dirs_module_init(PyObject *mod);
2598 void manifest_module_init(PyObject *mod);
2560 void manifest_module_init(PyObject *mod);
2599
2561
2600 static void module_init(PyObject *mod)
2562 static void module_init(PyObject *mod)
2601 {
2563 {
2602 /* This module constant has two purposes. First, it lets us unit test
2564 /* This module constant has two purposes. First, it lets us unit test
2603 * the ImportError raised without hard-coding any error text. This
2565 * the ImportError raised without hard-coding any error text. This
2604 * means we can change the text in the future without breaking tests,
2566 * means we can change the text in the future without breaking tests,
2605 * even across changesets without a recompile. Second, its presence
2567 * even across changesets without a recompile. Second, its presence
2606 * can be used to determine whether the version-checking logic is
2568 * can be used to determine whether the version-checking logic is
2607 * present, which also helps in testing across changesets without a
2569 * present, which also helps in testing across changesets without a
2608 * recompile. Note that this means the pure-Python version of parsers
2570 * recompile. Note that this means the pure-Python version of parsers
2609 * should not have this module constant. */
2571 * should not have this module constant. */
2610 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
2572 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
2611
2573
2612 dirs_module_init(mod);
2574 dirs_module_init(mod);
2613 manifest_module_init(mod);
2575 manifest_module_init(mod);
2614
2576
2615 indexType.tp_new = PyType_GenericNew;
2577 indexType.tp_new = PyType_GenericNew;
2616 if (PyType_Ready(&indexType) < 0 ||
2578 if (PyType_Ready(&indexType) < 0 ||
2617 PyType_Ready(&dirstateTupleType) < 0)
2579 PyType_Ready(&dirstateTupleType) < 0)
2618 return;
2580 return;
2619 Py_INCREF(&indexType);
2581 Py_INCREF(&indexType);
2620 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2582 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2621 Py_INCREF(&dirstateTupleType);
2583 Py_INCREF(&dirstateTupleType);
2622 PyModule_AddObject(mod, "dirstatetuple",
2584 PyModule_AddObject(mod, "dirstatetuple",
2623 (PyObject *)&dirstateTupleType);
2585 (PyObject *)&dirstateTupleType);
2624
2586
2625 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
2587 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
2626 -1, -1, -1, -1, nullid, 20);
2588 -1, -1, -1, -1, nullid, 20);
2627 if (nullentry)
2589 if (nullentry)
2628 PyObject_GC_UnTrack(nullentry);
2590 PyObject_GC_UnTrack(nullentry);
2629 }
2591 }
2630
2592
2631 static int check_python_version(void)
2593 static int check_python_version(void)
2632 {
2594 {
2633 PyObject *sys = PyImport_ImportModule("sys"), *ver;
2595 PyObject *sys = PyImport_ImportModule("sys"), *ver;
2634 long hexversion;
2596 long hexversion;
2635 if (!sys)
2597 if (!sys)
2636 return -1;
2598 return -1;
2637 ver = PyObject_GetAttrString(sys, "hexversion");
2599 ver = PyObject_GetAttrString(sys, "hexversion");
2638 Py_DECREF(sys);
2600 Py_DECREF(sys);
2639 if (!ver)
2601 if (!ver)
2640 return -1;
2602 return -1;
2641 hexversion = PyInt_AsLong(ver);
2603 hexversion = PyInt_AsLong(ver);
2642 Py_DECREF(ver);
2604 Py_DECREF(ver);
2643 /* sys.hexversion is a 32-bit number by default, so the -1 case
2605 /* sys.hexversion is a 32-bit number by default, so the -1 case
2644 * should only occur in unusual circumstances (e.g. if sys.hexversion
2606 * should only occur in unusual circumstances (e.g. if sys.hexversion
2645 * is manually set to an invalid value). */
2607 * is manually set to an invalid value). */
2646 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
2608 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
2647 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
2609 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
2648 "modules were compiled with Python " PY_VERSION ", but "
2610 "modules were compiled with Python " PY_VERSION ", but "
2649 "Mercurial is currently using Python with sys.hexversion=%ld: "
2611 "Mercurial is currently using Python with sys.hexversion=%ld: "
2650 "Python %s\n at: %s", versionerrortext, hexversion,
2612 "Python %s\n at: %s", versionerrortext, hexversion,
2651 Py_GetVersion(), Py_GetProgramFullPath());
2613 Py_GetVersion(), Py_GetProgramFullPath());
2652 return -1;
2614 return -1;
2653 }
2615 }
2654 return 0;
2616 return 0;
2655 }
2617 }
2656
2618
2657 #ifdef IS_PY3K
2619 #ifdef IS_PY3K
2658 static struct PyModuleDef parsers_module = {
2620 static struct PyModuleDef parsers_module = {
2659 PyModuleDef_HEAD_INIT,
2621 PyModuleDef_HEAD_INIT,
2660 "parsers",
2622 "parsers",
2661 parsers_doc,
2623 parsers_doc,
2662 -1,
2624 -1,
2663 methods
2625 methods
2664 };
2626 };
2665
2627
2666 PyMODINIT_FUNC PyInit_parsers(void)
2628 PyMODINIT_FUNC PyInit_parsers(void)
2667 {
2629 {
2668 PyObject *mod;
2630 PyObject *mod;
2669
2631
2670 if (check_python_version() == -1)
2632 if (check_python_version() == -1)
2671 return;
2633 return;
2672 mod = PyModule_Create(&parsers_module);
2634 mod = PyModule_Create(&parsers_module);
2673 module_init(mod);
2635 module_init(mod);
2674 return mod;
2636 return mod;
2675 }
2637 }
2676 #else
2638 #else
2677 PyMODINIT_FUNC initparsers(void)
2639 PyMODINIT_FUNC initparsers(void)
2678 {
2640 {
2679 PyObject *mod;
2641 PyObject *mod;
2680
2642
2681 if (check_python_version() == -1)
2643 if (check_python_version() == -1)
2682 return;
2644 return;
2683 mod = Py_InitModule3("parsers", methods, parsers_doc);
2645 mod = Py_InitModule3("parsers", methods, parsers_doc);
2684 module_init(mod);
2646 module_init(mod);
2685 }
2647 }
2686 #endif
2648 #endif
@@ -1,888 +1,918
1 $ cat >> $HGRCPATH << EOF
1 $ cat >> $HGRCPATH << EOF
2 > [phases]
2 > [phases]
3 > # public changeset are not obsolete
3 > # public changeset are not obsolete
4 > publish=false
4 > publish=false
5 > [ui]
5 > [ui]
6 > logtemplate="{rev}:{node|short} ({phase}) [{tags} {bookmarks}] {desc|firstline}\n"
6 > logtemplate="{rev}:{node|short} ({phase}) [{tags} {bookmarks}] {desc|firstline}\n"
7 > EOF
7 > EOF
8 $ mkcommit() {
8 $ mkcommit() {
9 > echo "$1" > "$1"
9 > echo "$1" > "$1"
10 > hg add "$1"
10 > hg add "$1"
11 > hg ci -m "add $1"
11 > hg ci -m "add $1"
12 > }
12 > }
13 $ getid() {
13 $ getid() {
14 > hg log -T "{node}\n" --hidden -r "desc('$1')"
14 > hg log -T "{node}\n" --hidden -r "desc('$1')"
15 > }
15 > }
16
16
17 $ cat > debugkeys.py <<EOF
17 $ cat > debugkeys.py <<EOF
18 > def reposetup(ui, repo):
18 > def reposetup(ui, repo):
19 > class debugkeysrepo(repo.__class__):
19 > class debugkeysrepo(repo.__class__):
20 > def listkeys(self, namespace):
20 > def listkeys(self, namespace):
21 > ui.write('listkeys %s\n' % (namespace,))
21 > ui.write('listkeys %s\n' % (namespace,))
22 > return super(debugkeysrepo, self).listkeys(namespace)
22 > return super(debugkeysrepo, self).listkeys(namespace)
23 >
23 >
24 > if repo.local():
24 > if repo.local():
25 > repo.__class__ = debugkeysrepo
25 > repo.__class__ = debugkeysrepo
26 > EOF
26 > EOF
27
27
28 $ hg init tmpa
28 $ hg init tmpa
29 $ cd tmpa
29 $ cd tmpa
30 $ mkcommit kill_me
30 $ mkcommit kill_me
31
31
32 Checking that the feature is properly disabled
32 Checking that the feature is properly disabled
33
33
34 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
34 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
35 abort: creating obsolete markers is not enabled on this repo
35 abort: creating obsolete markers is not enabled on this repo
36 [255]
36 [255]
37
37
38 Enabling it
38 Enabling it
39
39
40 $ cat >> $HGRCPATH << EOF
40 $ cat >> $HGRCPATH << EOF
41 > [experimental]
41 > [experimental]
42 > evolution=createmarkers,exchange
42 > evolution=createmarkers,exchange
43 > EOF
43 > EOF
44
44
45 Killing a single changeset without replacement
45 Killing a single changeset without replacement
46
46
47 $ hg debugobsolete 0
47 $ hg debugobsolete 0
48 abort: changeset references must be full hexadecimal node identifiers
48 abort: changeset references must be full hexadecimal node identifiers
49 [255]
49 [255]
50 $ hg debugobsolete '00'
50 $ hg debugobsolete '00'
51 abort: changeset references must be full hexadecimal node identifiers
51 abort: changeset references must be full hexadecimal node identifiers
52 [255]
52 [255]
53 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
53 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
54 $ hg debugobsolete
54 $ hg debugobsolete
55 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'babar'}
55 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'babar'}
56
56
57 (test that mercurial is not confused)
57 (test that mercurial is not confused)
58
58
59 $ hg up null --quiet # having 0 as parent prevents it to be hidden
59 $ hg up null --quiet # having 0 as parent prevents it to be hidden
60 $ hg tip
60 $ hg tip
61 -1:000000000000 (public) [tip ]
61 -1:000000000000 (public) [tip ]
62 $ hg up --hidden tip --quiet
62 $ hg up --hidden tip --quiet
63
63
64 Killing a single changeset with itself should fail
64 Killing a single changeset with itself should fail
65 (simple local safeguard)
65 (simple local safeguard)
66
66
67 $ hg debugobsolete `getid kill_me` `getid kill_me`
67 $ hg debugobsolete `getid kill_me` `getid kill_me`
68 abort: bad obsmarker input: in-marker cycle with 97b7c2d76b1845ed3eb988cd612611e72406cef0
68 abort: bad obsmarker input: in-marker cycle with 97b7c2d76b1845ed3eb988cd612611e72406cef0
69 [255]
69 [255]
70
70
71 $ cd ..
71 $ cd ..
72
72
73 Killing a single changeset with replacement
73 Killing a single changeset with replacement
74 (and testing the format option)
74 (and testing the format option)
75
75
76 $ hg init tmpb
76 $ hg init tmpb
77 $ cd tmpb
77 $ cd tmpb
78 $ mkcommit a
78 $ mkcommit a
79 $ mkcommit b
79 $ mkcommit b
80 $ mkcommit original_c
80 $ mkcommit original_c
81 $ hg up "desc('b')"
81 $ hg up "desc('b')"
82 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
82 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
83 $ mkcommit new_c
83 $ mkcommit new_c
84 created new head
84 created new head
85 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
85 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
86 $ hg debugobsolete --config format.obsstore-version=0 --flag 12 `getid original_c` `getid new_c` -d '121 120'
86 $ hg debugobsolete --config format.obsstore-version=0 --flag 12 `getid original_c` `getid new_c` -d '121 120'
87 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
87 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
88 2:245bde4270cd add original_c
88 2:245bde4270cd add original_c
89 $ hg debugrevlog -cd
89 $ hg debugrevlog -cd
90 # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads chainlen
90 # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads chainlen
91 0 -1 -1 0 59 0 0 0 0 58 58 0 1 0
91 0 -1 -1 0 59 0 0 0 0 58 58 0 1 0
92 1 0 -1 59 118 59 59 0 0 58 116 0 1 0
92 1 0 -1 59 118 59 59 0 0 58 116 0 1 0
93 2 1 -1 118 193 118 118 59 0 76 192 0 1 0
93 2 1 -1 118 193 118 118 59 0 76 192 0 1 0
94 3 1 -1 193 260 193 193 59 0 66 258 0 2 0
94 3 1 -1 193 260 193 193 59 0 66 258 0 2 0
95 $ hg debugobsolete
95 $ hg debugobsolete
96 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
96 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
97
97
98 (check for version number of the obsstore)
98 (check for version number of the obsstore)
99
99
100 $ dd bs=1 count=1 if=.hg/store/obsstore 2>/dev/null
100 $ dd bs=1 count=1 if=.hg/store/obsstore 2>/dev/null
101 \x00 (no-eol) (esc)
101 \x00 (no-eol) (esc)
102
102
103 do it again (it read the obsstore before adding new changeset)
103 do it again (it read the obsstore before adding new changeset)
104
104
105 $ hg up '.^'
105 $ hg up '.^'
106 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
106 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
107 $ mkcommit new_2_c
107 $ mkcommit new_2_c
108 created new head
108 created new head
109 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
109 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
110 $ hg debugobsolete
110 $ hg debugobsolete
111 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
111 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
112 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
112 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
113
113
114 Register two markers with a missing node
114 Register two markers with a missing node
115
115
116 $ hg up '.^'
116 $ hg up '.^'
117 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
117 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
118 $ mkcommit new_3_c
118 $ mkcommit new_3_c
119 created new head
119 created new head
120 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
120 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
121 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
121 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
122 $ hg debugobsolete
122 $ hg debugobsolete
123 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
123 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
124 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
124 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
125 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
125 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
126 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
126 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
127
127
128 Refuse pathological nullid successors
128 Refuse pathological nullid successors
129 $ hg debugobsolete -d '9001 0' 1337133713371337133713371337133713371337 0000000000000000000000000000000000000000
129 $ hg debugobsolete -d '9001 0' 1337133713371337133713371337133713371337 0000000000000000000000000000000000000000
130 transaction abort!
130 transaction abort!
131 rollback completed
131 rollback completed
132 abort: bad obsolescence marker detected: invalid successors nullid
132 abort: bad obsolescence marker detected: invalid successors nullid
133 [255]
133 [255]
134
134
135 Check that graphlog detect that a changeset is obsolete:
135 Check that graphlog detect that a changeset is obsolete:
136
136
137 $ hg log -G
137 $ hg log -G
138 @ 5:5601fb93a350 (draft) [tip ] add new_3_c
138 @ 5:5601fb93a350 (draft) [tip ] add new_3_c
139 |
139 |
140 o 1:7c3bad9141dc (draft) [ ] add b
140 o 1:7c3bad9141dc (draft) [ ] add b
141 |
141 |
142 o 0:1f0dee641bb7 (draft) [ ] add a
142 o 0:1f0dee641bb7 (draft) [ ] add a
143
143
144
144
145 check that heads does not report them
145 check that heads does not report them
146
146
147 $ hg heads
147 $ hg heads
148 5:5601fb93a350 (draft) [tip ] add new_3_c
148 5:5601fb93a350 (draft) [tip ] add new_3_c
149 $ hg heads --hidden
149 $ hg heads --hidden
150 5:5601fb93a350 (draft) [tip ] add new_3_c
150 5:5601fb93a350 (draft) [tip ] add new_3_c
151 4:ca819180edb9 (draft) [ ] add new_2_c
151 4:ca819180edb9 (draft) [ ] add new_2_c
152 3:cdbce2fbb163 (draft) [ ] add new_c
152 3:cdbce2fbb163 (draft) [ ] add new_c
153 2:245bde4270cd (draft) [ ] add original_c
153 2:245bde4270cd (draft) [ ] add original_c
154
154
155
155
156 check that summary does not report them
156 check that summary does not report them
157
157
158 $ hg init ../sink
158 $ hg init ../sink
159 $ echo '[paths]' >> .hg/hgrc
159 $ echo '[paths]' >> .hg/hgrc
160 $ echo 'default=../sink' >> .hg/hgrc
160 $ echo 'default=../sink' >> .hg/hgrc
161 $ hg summary --remote
161 $ hg summary --remote
162 parent: 5:5601fb93a350 tip
162 parent: 5:5601fb93a350 tip
163 add new_3_c
163 add new_3_c
164 branch: default
164 branch: default
165 commit: (clean)
165 commit: (clean)
166 update: (current)
166 update: (current)
167 phases: 3 draft (draft)
167 phases: 3 draft (draft)
168 remote: 3 outgoing
168 remote: 3 outgoing
169
169
170 $ hg summary --remote --hidden
170 $ hg summary --remote --hidden
171 parent: 5:5601fb93a350 tip
171 parent: 5:5601fb93a350 tip
172 add new_3_c
172 add new_3_c
173 branch: default
173 branch: default
174 commit: (clean)
174 commit: (clean)
175 update: 3 new changesets, 4 branch heads (merge)
175 update: 3 new changesets, 4 branch heads (merge)
176 phases: 6 draft (draft)
176 phases: 6 draft (draft)
177 remote: 3 outgoing
177 remote: 3 outgoing
178
178
179 check that various commands work well with filtering
179 check that various commands work well with filtering
180
180
181 $ hg tip
181 $ hg tip
182 5:5601fb93a350 (draft) [tip ] add new_3_c
182 5:5601fb93a350 (draft) [tip ] add new_3_c
183 $ hg log -r 6
183 $ hg log -r 6
184 abort: unknown revision '6'!
184 abort: unknown revision '6'!
185 [255]
185 [255]
186 $ hg log -r 4
186 $ hg log -r 4
187 abort: hidden revision '4'!
187 abort: hidden revision '4'!
188 (use --hidden to access hidden revisions)
188 (use --hidden to access hidden revisions)
189 [255]
189 [255]
190 $ hg debugrevspec 'rev(6)'
190 $ hg debugrevspec 'rev(6)'
191 $ hg debugrevspec 'rev(4)'
191 $ hg debugrevspec 'rev(4)'
192 $ hg debugrevspec 'null'
192 $ hg debugrevspec 'null'
193 -1
193 -1
194
194
195 Check that public changeset are not accounted as obsolete:
195 Check that public changeset are not accounted as obsolete:
196
196
197 $ hg --hidden phase --public 2
197 $ hg --hidden phase --public 2
198 $ hg log -G
198 $ hg log -G
199 @ 5:5601fb93a350 (draft) [tip ] add new_3_c
199 @ 5:5601fb93a350 (draft) [tip ] add new_3_c
200 |
200 |
201 | o 2:245bde4270cd (public) [ ] add original_c
201 | o 2:245bde4270cd (public) [ ] add original_c
202 |/
202 |/
203 o 1:7c3bad9141dc (public) [ ] add b
203 o 1:7c3bad9141dc (public) [ ] add b
204 |
204 |
205 o 0:1f0dee641bb7 (public) [ ] add a
205 o 0:1f0dee641bb7 (public) [ ] add a
206
206
207
207
208 And that bumped changeset are detected
208 And that bumped changeset are detected
209 --------------------------------------
209 --------------------------------------
210
210
211 If we didn't filtered obsolete changesets out, 3 and 4 would show up too. Also
211 If we didn't filtered obsolete changesets out, 3 and 4 would show up too. Also
212 note that the bumped changeset (5:5601fb93a350) is not a direct successor of
212 note that the bumped changeset (5:5601fb93a350) is not a direct successor of
213 the public changeset
213 the public changeset
214
214
215 $ hg log --hidden -r 'bumped()'
215 $ hg log --hidden -r 'bumped()'
216 5:5601fb93a350 (draft) [tip ] add new_3_c
216 5:5601fb93a350 (draft) [tip ] add new_3_c
217
217
218 And that we can't push bumped changeset
218 And that we can't push bumped changeset
219
219
220 $ hg push ../tmpa -r 0 --force #(make repo related)
220 $ hg push ../tmpa -r 0 --force #(make repo related)
221 pushing to ../tmpa
221 pushing to ../tmpa
222 searching for changes
222 searching for changes
223 warning: repository is unrelated
223 warning: repository is unrelated
224 adding changesets
224 adding changesets
225 adding manifests
225 adding manifests
226 adding file changes
226 adding file changes
227 added 1 changesets with 1 changes to 1 files (+1 heads)
227 added 1 changesets with 1 changes to 1 files (+1 heads)
228 $ hg push ../tmpa
228 $ hg push ../tmpa
229 pushing to ../tmpa
229 pushing to ../tmpa
230 searching for changes
230 searching for changes
231 abort: push includes bumped changeset: 5601fb93a350!
231 abort: push includes bumped changeset: 5601fb93a350!
232 [255]
232 [255]
233
233
234 Fixing "bumped" situation
234 Fixing "bumped" situation
235 We need to create a clone of 5 and add a special marker with a flag
235 We need to create a clone of 5 and add a special marker with a flag
236
236
237 $ hg up '5^'
237 $ hg up '5^'
238 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
238 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
239 $ hg revert -ar 5
239 $ hg revert -ar 5
240 adding new_3_c
240 adding new_3_c
241 $ hg ci -m 'add n3w_3_c'
241 $ hg ci -m 'add n3w_3_c'
242 created new head
242 created new head
243 $ hg debugobsolete -d '1338 0' --flags 1 `getid new_3_c` `getid n3w_3_c`
243 $ hg debugobsolete -d '1338 0' --flags 1 `getid new_3_c` `getid n3w_3_c`
244 $ hg log -r 'bumped()'
244 $ hg log -r 'bumped()'
245 $ hg log -G
245 $ hg log -G
246 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
246 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
247 |
247 |
248 | o 2:245bde4270cd (public) [ ] add original_c
248 | o 2:245bde4270cd (public) [ ] add original_c
249 |/
249 |/
250 o 1:7c3bad9141dc (public) [ ] add b
250 o 1:7c3bad9141dc (public) [ ] add b
251 |
251 |
252 o 0:1f0dee641bb7 (public) [ ] add a
252 o 0:1f0dee641bb7 (public) [ ] add a
253
253
254
254
255 $ cd ..
255 $ cd ..
256
256
257 Revision 0 is hidden
257 Revision 0 is hidden
258 --------------------
258 --------------------
259
259
260 $ hg init rev0hidden
260 $ hg init rev0hidden
261 $ cd rev0hidden
261 $ cd rev0hidden
262
262
263 $ mkcommit kill0
263 $ mkcommit kill0
264 $ hg up -q null
264 $ hg up -q null
265 $ hg debugobsolete `getid kill0`
265 $ hg debugobsolete `getid kill0`
266 $ mkcommit a
266 $ mkcommit a
267 $ mkcommit b
267 $ mkcommit b
268
268
269 Should pick the first visible revision as "repo" node
269 Should pick the first visible revision as "repo" node
270
270
271 $ hg archive ../archive-null
271 $ hg archive ../archive-null
272 $ cat ../archive-null/.hg_archival.txt
272 $ cat ../archive-null/.hg_archival.txt
273 repo: 1f0dee641bb7258c56bd60e93edfa2405381c41e
273 repo: 1f0dee641bb7258c56bd60e93edfa2405381c41e
274 node: 7c3bad9141dcb46ff89abf5f61856facd56e476c
274 node: 7c3bad9141dcb46ff89abf5f61856facd56e476c
275 branch: default
275 branch: default
276 latesttag: null
276 latesttag: null
277 latesttagdistance: 2
277 latesttagdistance: 2
278 changessincelatesttag: 2
278 changessincelatesttag: 2
279
279
280
280
281 $ cd ..
281 $ cd ..
282
282
283 Exchange Test
283 Exchange Test
284 ============================
284 ============================
285
285
286 Destination repo does not have any data
286 Destination repo does not have any data
287 ---------------------------------------
287 ---------------------------------------
288
288
289 Simple incoming test
289 Simple incoming test
290
290
291 $ hg init tmpc
291 $ hg init tmpc
292 $ cd tmpc
292 $ cd tmpc
293 $ hg incoming ../tmpb
293 $ hg incoming ../tmpb
294 comparing with ../tmpb
294 comparing with ../tmpb
295 0:1f0dee641bb7 (public) [ ] add a
295 0:1f0dee641bb7 (public) [ ] add a
296 1:7c3bad9141dc (public) [ ] add b
296 1:7c3bad9141dc (public) [ ] add b
297 2:245bde4270cd (public) [ ] add original_c
297 2:245bde4270cd (public) [ ] add original_c
298 6:6f9641995072 (draft) [tip ] add n3w_3_c
298 6:6f9641995072 (draft) [tip ] add n3w_3_c
299
299
300 Try to pull markers
300 Try to pull markers
301 (extinct changeset are excluded but marker are pushed)
301 (extinct changeset are excluded but marker are pushed)
302
302
303 $ hg pull ../tmpb
303 $ hg pull ../tmpb
304 pulling from ../tmpb
304 pulling from ../tmpb
305 requesting all changes
305 requesting all changes
306 adding changesets
306 adding changesets
307 adding manifests
307 adding manifests
308 adding file changes
308 adding file changes
309 added 4 changesets with 4 changes to 4 files (+1 heads)
309 added 4 changesets with 4 changes to 4 files (+1 heads)
310 (run 'hg heads' to see heads, 'hg merge' to merge)
310 (run 'hg heads' to see heads, 'hg merge' to merge)
311 $ hg debugobsolete
311 $ hg debugobsolete
312 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
312 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
313 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
313 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
314 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
314 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
315 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
315 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
316 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
316 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
317
317
318 Rollback//Transaction support
318 Rollback//Transaction support
319
319
320 $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
320 $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
321 $ hg debugobsolete
321 $ hg debugobsolete
322 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
322 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
323 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
323 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
324 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
324 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
325 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
325 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
326 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
326 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
327 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 (Thu Jan 01 00:22:20 1970 +0000) {'user': 'test'}
327 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 (Thu Jan 01 00:22:20 1970 +0000) {'user': 'test'}
328 $ hg rollback -n
328 $ hg rollback -n
329 repository tip rolled back to revision 3 (undo debugobsolete)
329 repository tip rolled back to revision 3 (undo debugobsolete)
330 $ hg rollback
330 $ hg rollback
331 repository tip rolled back to revision 3 (undo debugobsolete)
331 repository tip rolled back to revision 3 (undo debugobsolete)
332 $ hg debugobsolete
332 $ hg debugobsolete
333 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
333 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
334 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
334 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
335 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
335 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
336 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
336 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
337 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
337 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
338
338
339 $ cd ..
339 $ cd ..
340
340
341 Try to push markers
341 Try to push markers
342
342
343 $ hg init tmpd
343 $ hg init tmpd
344 $ hg -R tmpb push tmpd
344 $ hg -R tmpb push tmpd
345 pushing to tmpd
345 pushing to tmpd
346 searching for changes
346 searching for changes
347 adding changesets
347 adding changesets
348 adding manifests
348 adding manifests
349 adding file changes
349 adding file changes
350 added 4 changesets with 4 changes to 4 files (+1 heads)
350 added 4 changesets with 4 changes to 4 files (+1 heads)
351 $ hg -R tmpd debugobsolete | sort
351 $ hg -R tmpd debugobsolete | sort
352 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
352 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
353 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
353 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
354 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
354 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
355 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
355 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
356 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
356 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
357
357
358 Check obsolete keys are exchanged only if source has an obsolete store
358 Check obsolete keys are exchanged only if source has an obsolete store
359
359
360 $ hg init empty
360 $ hg init empty
361 $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd
361 $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd
362 pushing to tmpd
362 pushing to tmpd
363 listkeys phases
363 listkeys phases
364 listkeys bookmarks
364 listkeys bookmarks
365 no changes found
365 no changes found
366 listkeys phases
366 listkeys phases
367 [1]
367 [1]
368
368
369 clone support
369 clone support
370 (markers are copied and extinct changesets are included to allow hardlinks)
370 (markers are copied and extinct changesets are included to allow hardlinks)
371
371
372 $ hg clone tmpb clone-dest
372 $ hg clone tmpb clone-dest
373 updating to branch default
373 updating to branch default
374 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
374 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
375 $ hg -R clone-dest log -G --hidden
375 $ hg -R clone-dest log -G --hidden
376 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
376 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
377 |
377 |
378 | x 5:5601fb93a350 (draft) [ ] add new_3_c
378 | x 5:5601fb93a350 (draft) [ ] add new_3_c
379 |/
379 |/
380 | x 4:ca819180edb9 (draft) [ ] add new_2_c
380 | x 4:ca819180edb9 (draft) [ ] add new_2_c
381 |/
381 |/
382 | x 3:cdbce2fbb163 (draft) [ ] add new_c
382 | x 3:cdbce2fbb163 (draft) [ ] add new_c
383 |/
383 |/
384 | o 2:245bde4270cd (public) [ ] add original_c
384 | o 2:245bde4270cd (public) [ ] add original_c
385 |/
385 |/
386 o 1:7c3bad9141dc (public) [ ] add b
386 o 1:7c3bad9141dc (public) [ ] add b
387 |
387 |
388 o 0:1f0dee641bb7 (public) [ ] add a
388 o 0:1f0dee641bb7 (public) [ ] add a
389
389
390 $ hg -R clone-dest debugobsolete
390 $ hg -R clone-dest debugobsolete
391 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
391 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
392 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
392 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
393 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
393 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
394 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
394 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
395 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
395 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
396
396
397
397
398 Destination repo have existing data
398 Destination repo have existing data
399 ---------------------------------------
399 ---------------------------------------
400
400
401 On pull
401 On pull
402
402
403 $ hg init tmpe
403 $ hg init tmpe
404 $ cd tmpe
404 $ cd tmpe
405 $ hg debugobsolete -d '1339 0' 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00
405 $ hg debugobsolete -d '1339 0' 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00
406 $ hg pull ../tmpb
406 $ hg pull ../tmpb
407 pulling from ../tmpb
407 pulling from ../tmpb
408 requesting all changes
408 requesting all changes
409 adding changesets
409 adding changesets
410 adding manifests
410 adding manifests
411 adding file changes
411 adding file changes
412 added 4 changesets with 4 changes to 4 files (+1 heads)
412 added 4 changesets with 4 changes to 4 files (+1 heads)
413 (run 'hg heads' to see heads, 'hg merge' to merge)
413 (run 'hg heads' to see heads, 'hg merge' to merge)
414 $ hg debugobsolete
414 $ hg debugobsolete
415 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
415 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
416 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
416 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
417 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
417 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
418 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
418 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
419 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
419 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
420 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
420 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
421
421
422
422
423 On push
423 On push
424
424
425 $ hg push ../tmpc
425 $ hg push ../tmpc
426 pushing to ../tmpc
426 pushing to ../tmpc
427 searching for changes
427 searching for changes
428 no changes found
428 no changes found
429 [1]
429 [1]
430 $ hg -R ../tmpc debugobsolete
430 $ hg -R ../tmpc debugobsolete
431 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
431 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
432 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
432 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
433 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
433 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
434 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
434 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
435 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
435 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
436 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
436 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
437
437
438 detect outgoing obsolete and unstable
438 detect outgoing obsolete and unstable
439 ---------------------------------------
439 ---------------------------------------
440
440
441
441
442 $ hg log -G
442 $ hg log -G
443 o 3:6f9641995072 (draft) [tip ] add n3w_3_c
443 o 3:6f9641995072 (draft) [tip ] add n3w_3_c
444 |
444 |
445 | o 2:245bde4270cd (public) [ ] add original_c
445 | o 2:245bde4270cd (public) [ ] add original_c
446 |/
446 |/
447 o 1:7c3bad9141dc (public) [ ] add b
447 o 1:7c3bad9141dc (public) [ ] add b
448 |
448 |
449 o 0:1f0dee641bb7 (public) [ ] add a
449 o 0:1f0dee641bb7 (public) [ ] add a
450
450
451 $ hg up 'desc("n3w_3_c")'
451 $ hg up 'desc("n3w_3_c")'
452 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
452 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
453 $ mkcommit original_d
453 $ mkcommit original_d
454 $ mkcommit original_e
454 $ mkcommit original_e
455 $ hg debugobsolete --record-parents `getid original_d` -d '0 0'
455 $ hg debugobsolete --record-parents `getid original_d` -d '0 0'
456 $ hg debugobsolete | grep `getid original_d`
456 $ hg debugobsolete | grep `getid original_d`
457 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
457 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
458 $ hg log -r 'obsolete()'
458 $ hg log -r 'obsolete()'
459 4:94b33453f93b (draft) [ ] add original_d
459 4:94b33453f93b (draft) [ ] add original_d
460 $ hg log -G -r '::unstable()'
460 $ hg log -G -r '::unstable()'
461 @ 5:cda648ca50f5 (draft) [tip ] add original_e
461 @ 5:cda648ca50f5 (draft) [tip ] add original_e
462 |
462 |
463 x 4:94b33453f93b (draft) [ ] add original_d
463 x 4:94b33453f93b (draft) [ ] add original_d
464 |
464 |
465 o 3:6f9641995072 (draft) [ ] add n3w_3_c
465 o 3:6f9641995072 (draft) [ ] add n3w_3_c
466 |
466 |
467 o 1:7c3bad9141dc (public) [ ] add b
467 o 1:7c3bad9141dc (public) [ ] add b
468 |
468 |
469 o 0:1f0dee641bb7 (public) [ ] add a
469 o 0:1f0dee641bb7 (public) [ ] add a
470
470
471
471
472 refuse to push obsolete changeset
472 refuse to push obsolete changeset
473
473
474 $ hg push ../tmpc/ -r 'desc("original_d")'
474 $ hg push ../tmpc/ -r 'desc("original_d")'
475 pushing to ../tmpc/
475 pushing to ../tmpc/
476 searching for changes
476 searching for changes
477 abort: push includes obsolete changeset: 94b33453f93b!
477 abort: push includes obsolete changeset: 94b33453f93b!
478 [255]
478 [255]
479
479
480 refuse to push unstable changeset
480 refuse to push unstable changeset
481
481
482 $ hg push ../tmpc/
482 $ hg push ../tmpc/
483 pushing to ../tmpc/
483 pushing to ../tmpc/
484 searching for changes
484 searching for changes
485 abort: push includes unstable changeset: cda648ca50f5!
485 abort: push includes unstable changeset: cda648ca50f5!
486 [255]
486 [255]
487
487
488 Test that extinct changeset are properly detected
488 Test that extinct changeset are properly detected
489
489
490 $ hg log -r 'extinct()'
490 $ hg log -r 'extinct()'
491
491
492 Don't try to push extinct changeset
492 Don't try to push extinct changeset
493
493
494 $ hg init ../tmpf
494 $ hg init ../tmpf
495 $ hg out ../tmpf
495 $ hg out ../tmpf
496 comparing with ../tmpf
496 comparing with ../tmpf
497 searching for changes
497 searching for changes
498 0:1f0dee641bb7 (public) [ ] add a
498 0:1f0dee641bb7 (public) [ ] add a
499 1:7c3bad9141dc (public) [ ] add b
499 1:7c3bad9141dc (public) [ ] add b
500 2:245bde4270cd (public) [ ] add original_c
500 2:245bde4270cd (public) [ ] add original_c
501 3:6f9641995072 (draft) [ ] add n3w_3_c
501 3:6f9641995072 (draft) [ ] add n3w_3_c
502 4:94b33453f93b (draft) [ ] add original_d
502 4:94b33453f93b (draft) [ ] add original_d
503 5:cda648ca50f5 (draft) [tip ] add original_e
503 5:cda648ca50f5 (draft) [tip ] add original_e
504 $ hg push ../tmpf -f # -f because be push unstable too
504 $ hg push ../tmpf -f # -f because be push unstable too
505 pushing to ../tmpf
505 pushing to ../tmpf
506 searching for changes
506 searching for changes
507 adding changesets
507 adding changesets
508 adding manifests
508 adding manifests
509 adding file changes
509 adding file changes
510 added 6 changesets with 6 changes to 6 files (+1 heads)
510 added 6 changesets with 6 changes to 6 files (+1 heads)
511
511
512 no warning displayed
512 no warning displayed
513
513
514 $ hg push ../tmpf
514 $ hg push ../tmpf
515 pushing to ../tmpf
515 pushing to ../tmpf
516 searching for changes
516 searching for changes
517 no changes found
517 no changes found
518 [1]
518 [1]
519
519
520 Do not warn about new head when the new head is a successors of a remote one
520 Do not warn about new head when the new head is a successors of a remote one
521
521
522 $ hg log -G
522 $ hg log -G
523 @ 5:cda648ca50f5 (draft) [tip ] add original_e
523 @ 5:cda648ca50f5 (draft) [tip ] add original_e
524 |
524 |
525 x 4:94b33453f93b (draft) [ ] add original_d
525 x 4:94b33453f93b (draft) [ ] add original_d
526 |
526 |
527 o 3:6f9641995072 (draft) [ ] add n3w_3_c
527 o 3:6f9641995072 (draft) [ ] add n3w_3_c
528 |
528 |
529 | o 2:245bde4270cd (public) [ ] add original_c
529 | o 2:245bde4270cd (public) [ ] add original_c
530 |/
530 |/
531 o 1:7c3bad9141dc (public) [ ] add b
531 o 1:7c3bad9141dc (public) [ ] add b
532 |
532 |
533 o 0:1f0dee641bb7 (public) [ ] add a
533 o 0:1f0dee641bb7 (public) [ ] add a
534
534
535 $ hg up -q 'desc(n3w_3_c)'
535 $ hg up -q 'desc(n3w_3_c)'
536 $ mkcommit obsolete_e
536 $ mkcommit obsolete_e
537 created new head
537 created new head
538 $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'`
538 $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'`
539 $ hg outgoing ../tmpf # parasite hg outgoing testin
539 $ hg outgoing ../tmpf # parasite hg outgoing testin
540 comparing with ../tmpf
540 comparing with ../tmpf
541 searching for changes
541 searching for changes
542 6:3de5eca88c00 (draft) [tip ] add obsolete_e
542 6:3de5eca88c00 (draft) [tip ] add obsolete_e
543 $ hg push ../tmpf
543 $ hg push ../tmpf
544 pushing to ../tmpf
544 pushing to ../tmpf
545 searching for changes
545 searching for changes
546 adding changesets
546 adding changesets
547 adding manifests
547 adding manifests
548 adding file changes
548 adding file changes
549 added 1 changesets with 1 changes to 1 files (+1 heads)
549 added 1 changesets with 1 changes to 1 files (+1 heads)
550
550
551 test relevance computation
551 test relevance computation
552 ---------------------------------------
552 ---------------------------------------
553
553
554 Checking simple case of "marker relevance".
554 Checking simple case of "marker relevance".
555
555
556
556
557 Reminder of the repo situation
557 Reminder of the repo situation
558
558
559 $ hg log --hidden --graph
559 $ hg log --hidden --graph
560 @ 6:3de5eca88c00 (draft) [tip ] add obsolete_e
560 @ 6:3de5eca88c00 (draft) [tip ] add obsolete_e
561 |
561 |
562 | x 5:cda648ca50f5 (draft) [ ] add original_e
562 | x 5:cda648ca50f5 (draft) [ ] add original_e
563 | |
563 | |
564 | x 4:94b33453f93b (draft) [ ] add original_d
564 | x 4:94b33453f93b (draft) [ ] add original_d
565 |/
565 |/
566 o 3:6f9641995072 (draft) [ ] add n3w_3_c
566 o 3:6f9641995072 (draft) [ ] add n3w_3_c
567 |
567 |
568 | o 2:245bde4270cd (public) [ ] add original_c
568 | o 2:245bde4270cd (public) [ ] add original_c
569 |/
569 |/
570 o 1:7c3bad9141dc (public) [ ] add b
570 o 1:7c3bad9141dc (public) [ ] add b
571 |
571 |
572 o 0:1f0dee641bb7 (public) [ ] add a
572 o 0:1f0dee641bb7 (public) [ ] add a
573
573
574
574
575 List of all markers
575 List of all markers
576
576
577 $ hg debugobsolete
577 $ hg debugobsolete
578 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
578 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
579 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
579 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
580 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
580 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
581 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
581 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
582 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
582 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
583 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
583 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
584 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
584 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
585 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test'} (glob)
585 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test'} (glob)
586
586
587 List of changesets with no chain
587 List of changesets with no chain
588
588
589 $ hg debugobsolete --hidden --rev ::2
589 $ hg debugobsolete --hidden --rev ::2
590
590
591 List of changesets that are included on marker chain
591 List of changesets that are included on marker chain
592
592
593 $ hg debugobsolete --hidden --rev 6
593 $ hg debugobsolete --hidden --rev 6
594 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test'} (glob)
594 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test'} (glob)
595
595
596 List of changesets with a longer chain, (including a pruned children)
596 List of changesets with a longer chain, (including a pruned children)
597
597
598 $ hg debugobsolete --hidden --rev 3
598 $ hg debugobsolete --hidden --rev 3
599 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
599 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
600 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
600 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
601 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
601 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
602 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
602 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
603 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
603 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
604 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
604 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
605 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
605 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
606
606
607 List of both
607 List of both
608
608
609 $ hg debugobsolete --hidden --rev 3::6
609 $ hg debugobsolete --hidden --rev 3::6
610 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
610 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
611 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
611 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
612 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
612 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
613 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
613 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
614 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
614 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
615 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
615 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
616 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test'} (glob)
616 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test'} (glob)
617 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
617 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
618
618
619 #if serve
619 #if serve
620
620
621 Test the debug output for exchange
621 Test the debug output for exchange
622 ----------------------------------
622 ----------------------------------
623
623
624 $ hg pull ../tmpb --config 'experimental.obsmarkers-exchange-debug=True' --config 'experimental.bundle2-exp=True'
624 $ hg pull ../tmpb --config 'experimental.obsmarkers-exchange-debug=True' --config 'experimental.bundle2-exp=True'
625 pulling from ../tmpb
625 pulling from ../tmpb
626 searching for changes
626 searching for changes
627 no changes found
627 no changes found
628 obsmarker-exchange: 346 bytes received
628 obsmarker-exchange: 346 bytes received
629
629
630 check hgweb does not explode
630 check hgweb does not explode
631 ====================================
631 ====================================
632
632
633 $ hg unbundle $TESTDIR/bundles/hgweb+obs.hg
633 $ hg unbundle $TESTDIR/bundles/hgweb+obs.hg
634 adding changesets
634 adding changesets
635 adding manifests
635 adding manifests
636 adding file changes
636 adding file changes
637 added 62 changesets with 63 changes to 9 files (+60 heads)
637 added 62 changesets with 63 changes to 9 files (+60 heads)
638 (run 'hg heads .' to see heads, 'hg merge' to merge)
638 (run 'hg heads .' to see heads, 'hg merge' to merge)
639 $ for node in `hg log -r 'desc(babar_)' --template '{node}\n'`;
639 $ for node in `hg log -r 'desc(babar_)' --template '{node}\n'`;
640 > do
640 > do
641 > hg debugobsolete $node
641 > hg debugobsolete $node
642 > done
642 > done
643 $ hg up tip
643 $ hg up tip
644 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
644 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
645
645
646 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
646 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
647 $ cat hg.pid >> $DAEMON_PIDS
647 $ cat hg.pid >> $DAEMON_PIDS
648
648
649 check changelog view
649 check changelog view
650
650
651 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'shortlog/'
651 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'shortlog/'
652 200 Script output follows
652 200 Script output follows
653
653
654 check graph view
654 check graph view
655
655
656 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'graph'
656 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'graph'
657 200 Script output follows
657 200 Script output follows
658
658
659 check filelog view
659 check filelog view
660
660
661 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'log/'`hg log -r . -T "{node}"`/'babar'
661 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'log/'`hg log -r . -T "{node}"`/'babar'
662 200 Script output follows
662 200 Script output follows
663
663
664 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/68'
664 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/68'
665 200 Script output follows
665 200 Script output follows
666 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/67'
666 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/67'
667 404 Not Found
667 404 Not Found
668 [1]
668 [1]
669
669
670 check that web.view config option:
670 check that web.view config option:
671
671
672 $ "$TESTDIR/killdaemons.py" hg.pid
672 $ "$TESTDIR/killdaemons.py" hg.pid
673 $ cat >> .hg/hgrc << EOF
673 $ cat >> .hg/hgrc << EOF
674 > [web]
674 > [web]
675 > view=all
675 > view=all
676 > EOF
676 > EOF
677 $ wait
677 $ wait
678 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
678 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
679 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/67'
679 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/67'
680 200 Script output follows
680 200 Script output follows
681 $ "$TESTDIR/killdaemons.py" hg.pid
681 $ "$TESTDIR/killdaemons.py" hg.pid
682
682
683 Checking _enable=False warning if obsolete marker exists
683 Checking _enable=False warning if obsolete marker exists
684
684
685 $ echo '[experimental]' >> $HGRCPATH
685 $ echo '[experimental]' >> $HGRCPATH
686 $ echo "evolution=" >> $HGRCPATH
686 $ echo "evolution=" >> $HGRCPATH
687 $ hg log -r tip
687 $ hg log -r tip
688 obsolete feature not enabled but 68 markers found!
688 obsolete feature not enabled but 68 markers found!
689 68:c15e9edfca13 (draft) [tip ] add celestine
689 68:c15e9edfca13 (draft) [tip ] add celestine
690
690
691 reenable for later test
691 reenable for later test
692
692
693 $ echo '[experimental]' >> $HGRCPATH
693 $ echo '[experimental]' >> $HGRCPATH
694 $ echo "evolution=createmarkers,exchange" >> $HGRCPATH
694 $ echo "evolution=createmarkers,exchange" >> $HGRCPATH
695
695
696 #endif
696 #endif
697
697
698 Test incoming/outcoming with changesets obsoleted remotely, known locally
698 Test incoming/outcoming with changesets obsoleted remotely, known locally
699 ===============================================================================
699 ===============================================================================
700
700
701 This test issue 3805
701 This test issue 3805
702
702
703 $ hg init repo-issue3805
703 $ hg init repo-issue3805
704 $ cd repo-issue3805
704 $ cd repo-issue3805
705 $ echo "foo" > foo
705 $ echo "foo" > foo
706 $ hg ci -Am "A"
706 $ hg ci -Am "A"
707 adding foo
707 adding foo
708 $ hg clone . ../other-issue3805
708 $ hg clone . ../other-issue3805
709 updating to branch default
709 updating to branch default
710 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
710 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
711 $ echo "bar" >> foo
711 $ echo "bar" >> foo
712 $ hg ci --amend
712 $ hg ci --amend
713 $ cd ../other-issue3805
713 $ cd ../other-issue3805
714 $ hg log -G
714 $ hg log -G
715 @ 0:193e9254ce7e (draft) [tip ] A
715 @ 0:193e9254ce7e (draft) [tip ] A
716
716
717 $ hg log -G -R ../repo-issue3805
717 $ hg log -G -R ../repo-issue3805
718 @ 2:3816541e5485 (draft) [tip ] A
718 @ 2:3816541e5485 (draft) [tip ] A
719
719
720 $ hg incoming
720 $ hg incoming
721 comparing with $TESTTMP/tmpe/repo-issue3805 (glob)
721 comparing with $TESTTMP/tmpe/repo-issue3805 (glob)
722 searching for changes
722 searching for changes
723 2:3816541e5485 (draft) [tip ] A
723 2:3816541e5485 (draft) [tip ] A
724 $ hg incoming --bundle ../issue3805.hg
724 $ hg incoming --bundle ../issue3805.hg
725 comparing with $TESTTMP/tmpe/repo-issue3805 (glob)
725 comparing with $TESTTMP/tmpe/repo-issue3805 (glob)
726 searching for changes
726 searching for changes
727 2:3816541e5485 (draft) [tip ] A
727 2:3816541e5485 (draft) [tip ] A
728 $ hg outgoing
728 $ hg outgoing
729 comparing with $TESTTMP/tmpe/repo-issue3805 (glob)
729 comparing with $TESTTMP/tmpe/repo-issue3805 (glob)
730 searching for changes
730 searching for changes
731 no changes found
731 no changes found
732 [1]
732 [1]
733
733
734 #if serve
734 #if serve
735
735
736 $ hg serve -R ../repo-issue3805 -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
736 $ hg serve -R ../repo-issue3805 -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
737 $ cat hg.pid >> $DAEMON_PIDS
737 $ cat hg.pid >> $DAEMON_PIDS
738
738
739 $ hg incoming http://localhost:$HGPORT
739 $ hg incoming http://localhost:$HGPORT
740 comparing with http://localhost:$HGPORT/
740 comparing with http://localhost:$HGPORT/
741 searching for changes
741 searching for changes
742 1:3816541e5485 (draft) [tip ] A
742 1:3816541e5485 (draft) [tip ] A
743 $ hg outgoing http://localhost:$HGPORT
743 $ hg outgoing http://localhost:$HGPORT
744 comparing with http://localhost:$HGPORT/
744 comparing with http://localhost:$HGPORT/
745 searching for changes
745 searching for changes
746 no changes found
746 no changes found
747 [1]
747 [1]
748
748
749 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
749 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
750
750
751 #endif
751 #endif
752
752
753 This test issue 3814
753 This test issue 3814
754
754
755 (nothing to push but locally hidden changeset)
755 (nothing to push but locally hidden changeset)
756
756
757 $ cd ..
757 $ cd ..
758 $ hg init repo-issue3814
758 $ hg init repo-issue3814
759 $ cd repo-issue3805
759 $ cd repo-issue3805
760 $ hg push -r 3816541e5485 ../repo-issue3814
760 $ hg push -r 3816541e5485 ../repo-issue3814
761 pushing to ../repo-issue3814
761 pushing to ../repo-issue3814
762 searching for changes
762 searching for changes
763 adding changesets
763 adding changesets
764 adding manifests
764 adding manifests
765 adding file changes
765 adding file changes
766 added 1 changesets with 1 changes to 1 files
766 added 1 changesets with 1 changes to 1 files
767 $ hg out ../repo-issue3814
767 $ hg out ../repo-issue3814
768 comparing with ../repo-issue3814
768 comparing with ../repo-issue3814
769 searching for changes
769 searching for changes
770 no changes found
770 no changes found
771 [1]
771 [1]
772
772
773 Test that a local tag blocks a changeset from being hidden
773 Test that a local tag blocks a changeset from being hidden
774
774
775 $ hg tag -l visible -r 0 --hidden
775 $ hg tag -l visible -r 0 --hidden
776 $ hg log -G
776 $ hg log -G
777 @ 2:3816541e5485 (draft) [tip ] A
777 @ 2:3816541e5485 (draft) [tip ] A
778
778
779 x 0:193e9254ce7e (draft) [visible ] A
779 x 0:193e9254ce7e (draft) [visible ] A
780
780
781 Test that removing a local tag does not cause some commands to fail
781 Test that removing a local tag does not cause some commands to fail
782
782
783 $ hg tag -l -r tip tiptag
783 $ hg tag -l -r tip tiptag
784 $ hg tags
784 $ hg tags
785 tiptag 2:3816541e5485
785 tiptag 2:3816541e5485
786 tip 2:3816541e5485
786 tip 2:3816541e5485
787 visible 0:193e9254ce7e
787 visible 0:193e9254ce7e
788 $ hg --config extensions.strip= strip -r tip --no-backup
788 $ hg --config extensions.strip= strip -r tip --no-backup
789 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
789 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
790 $ hg tags
790 $ hg tags
791 visible 0:193e9254ce7e
791 visible 0:193e9254ce7e
792 tip 0:193e9254ce7e
792 tip 0:193e9254ce7e
793
793
794 Test bundle overlay onto hidden revision
794 Test bundle overlay onto hidden revision
795
795
796 $ cd ..
796 $ cd ..
797 $ hg init repo-bundleoverlay
797 $ hg init repo-bundleoverlay
798 $ cd repo-bundleoverlay
798 $ cd repo-bundleoverlay
799 $ echo "A" > foo
799 $ echo "A" > foo
800 $ hg ci -Am "A"
800 $ hg ci -Am "A"
801 adding foo
801 adding foo
802 $ echo "B" >> foo
802 $ echo "B" >> foo
803 $ hg ci -m "B"
803 $ hg ci -m "B"
804 $ hg up 0
804 $ hg up 0
805 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
805 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
806 $ echo "C" >> foo
806 $ echo "C" >> foo
807 $ hg ci -m "C"
807 $ hg ci -m "C"
808 created new head
808 created new head
809 $ hg log -G
809 $ hg log -G
810 @ 2:c186d7714947 (draft) [tip ] C
810 @ 2:c186d7714947 (draft) [tip ] C
811 |
811 |
812 | o 1:44526ebb0f98 (draft) [ ] B
812 | o 1:44526ebb0f98 (draft) [ ] B
813 |/
813 |/
814 o 0:4b34ecfb0d56 (draft) [ ] A
814 o 0:4b34ecfb0d56 (draft) [ ] A
815
815
816
816
817 $ hg clone -r1 . ../other-bundleoverlay
817 $ hg clone -r1 . ../other-bundleoverlay
818 adding changesets
818 adding changesets
819 adding manifests
819 adding manifests
820 adding file changes
820 adding file changes
821 added 2 changesets with 2 changes to 1 files
821 added 2 changesets with 2 changes to 1 files
822 updating to branch default
822 updating to branch default
823 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
823 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
824 $ cd ../other-bundleoverlay
824 $ cd ../other-bundleoverlay
825 $ echo "B+" >> foo
825 $ echo "B+" >> foo
826 $ hg ci --amend -m "B+"
826 $ hg ci --amend -m "B+"
827 $ hg log -G --hidden
827 $ hg log -G --hidden
828 @ 3:b7d587542d40 (draft) [tip ] B+
828 @ 3:b7d587542d40 (draft) [tip ] B+
829 |
829 |
830 | x 2:eb95e9297e18 (draft) [ ] temporary amend commit for 44526ebb0f98
830 | x 2:eb95e9297e18 (draft) [ ] temporary amend commit for 44526ebb0f98
831 | |
831 | |
832 | x 1:44526ebb0f98 (draft) [ ] B
832 | x 1:44526ebb0f98 (draft) [ ] B
833 |/
833 |/
834 o 0:4b34ecfb0d56 (draft) [ ] A
834 o 0:4b34ecfb0d56 (draft) [ ] A
835
835
836
836
837 $ hg incoming ../repo-bundleoverlay --bundle ../bundleoverlay.hg
837 $ hg incoming ../repo-bundleoverlay --bundle ../bundleoverlay.hg
838 comparing with ../repo-bundleoverlay
838 comparing with ../repo-bundleoverlay
839 searching for changes
839 searching for changes
840 1:44526ebb0f98 (draft) [ ] B
840 1:44526ebb0f98 (draft) [ ] B
841 2:c186d7714947 (draft) [tip ] C
841 2:c186d7714947 (draft) [tip ] C
842 $ hg log -G -R ../bundleoverlay.hg
842 $ hg log -G -R ../bundleoverlay.hg
843 o 4:c186d7714947 (draft) [tip ] C
843 o 4:c186d7714947 (draft) [tip ] C
844 |
844 |
845 | @ 3:b7d587542d40 (draft) [ ] B+
845 | @ 3:b7d587542d40 (draft) [ ] B+
846 |/
846 |/
847 o 0:4b34ecfb0d56 (draft) [ ] A
847 o 0:4b34ecfb0d56 (draft) [ ] A
848
848
849
849
850 #if serve
850 #if serve
851
851
852 Test issue 4506
852 Test issue 4506
853
853
854 $ cd ..
854 $ cd ..
855 $ hg init repo-issue4506
855 $ hg init repo-issue4506
856 $ cd repo-issue4506
856 $ cd repo-issue4506
857 $ echo "0" > foo
857 $ echo "0" > foo
858 $ hg add foo
858 $ hg add foo
859 $ hg ci -m "content-0"
859 $ hg ci -m "content-0"
860
860
861 $ hg up null
861 $ hg up null
862 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
862 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
863 $ echo "1" > bar
863 $ echo "1" > bar
864 $ hg add bar
864 $ hg add bar
865 $ hg ci -m "content-1"
865 $ hg ci -m "content-1"
866 created new head
866 created new head
867 $ hg up 0
867 $ hg up 0
868 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
868 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
869 $ hg graft 1
869 $ hg graft 1
870 grafting 1:1c9eddb02162 "content-1" (tip)
870 grafting 1:1c9eddb02162 "content-1" (tip)
871
871
872 $ hg debugobsolete `hg log -r1 -T'{node}'` `hg log -r2 -T'{node}'`
872 $ hg debugobsolete `hg log -r1 -T'{node}'` `hg log -r2 -T'{node}'`
873
873
874 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
874 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
875 $ cat hg.pid >> $DAEMON_PIDS
875 $ cat hg.pid >> $DAEMON_PIDS
876
876
877 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/1'
877 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'rev/1'
878 404 Not Found
878 404 Not Found
879 [1]
879 [1]
880 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'file/tip/bar'
880 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'file/tip/bar'
881 200 Script output follows
881 200 Script output follows
882 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'annotate/tip/bar'
882 $ "$TESTDIR/get-with-headers.py" --headeronly localhost:$HGPORT 'annotate/tip/bar'
883 200 Script output follows
883 200 Script output follows
884
884
885 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
885 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS
886
886
887 #endif
887 #endif
888
888
889 Test heads computation on pending index changes with obsolescence markers
890 $ cd ..
891 $ cat >$TESTTMP/test_extension.py << EOF
892 > from mercurial import cmdutil
893 > from mercurial.i18n import _
894 >
895 > cmdtable = {}
896 > command = cmdutil.command(cmdtable)
897 > @command("amendtransient",[], _('hg amendtransient [rev]'))
898 > def amend(ui, repo, *pats, **opts):
899 > def commitfunc(ui, repo, message, match, opts):
900 > return repo.commit(message, repo['.'].user(), repo['.'].date(), match)
901 > opts['message'] = 'Test'
902 > opts['logfile'] = None
903 > cmdutil.amend(ui, repo, commitfunc, repo['.'], {}, pats, opts)
904 > print repo.changelog.headrevs()
905 > EOF
906 $ cat >> $HGRCPATH << EOF
907 > [extensions]
908 > testextension=$TESTTMP/test_extension.py
909 > EOF
910 $ hg init repo-issue-nativerevs-pending-changes
911 $ cd repo-issue-nativerevs-pending-changes
912 $ mkcommit a
913 $ mkcommit b
914 $ hg up ".^"
915 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
916 $ echo aa > a
917 $ hg amendtransient
918 [1, 3]
General Comments 0
You need to be logged in to leave comments. Login now