##// END OF EJS Templates
obsolete: use C code for headrevs calculation...
Durham Goode -
r22484:2b5940f6 default
parent child Browse files
Show More
@@ -1,352 +1,357 b''
1 1 # changelog.py - changelog class for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from node import bin, hex, nullid
9 9 from i18n import _
10 10 import util, error, revlog, encoding
11 11
12 12 _defaultextra = {'branch': 'default'}
13 13
14 14 def _string_escape(text):
15 15 """
16 16 >>> d = {'nl': chr(10), 'bs': chr(92), 'cr': chr(13), 'nul': chr(0)}
17 17 >>> s = "ab%(nl)scd%(bs)s%(bs)sn%(nul)sab%(cr)scd%(bs)s%(nl)s" % d
18 18 >>> s
19 19 'ab\\ncd\\\\\\\\n\\x00ab\\rcd\\\\\\n'
20 20 >>> res = _string_escape(s)
21 21 >>> s == res.decode('string_escape')
22 22 True
23 23 """
24 24 # subset of the string_escape codec
25 25 text = text.replace('\\', '\\\\').replace('\n', '\\n').replace('\r', '\\r')
26 26 return text.replace('\0', '\\0')
27 27
28 28 def decodeextra(text):
29 29 """
30 30 >>> sorted(decodeextra(encodeextra({'foo': 'bar', 'baz': chr(0) + '2'})
31 31 ... ).iteritems())
32 32 [('baz', '\\x002'), ('branch', 'default'), ('foo', 'bar')]
33 33 >>> sorted(decodeextra(encodeextra({'foo': 'bar',
34 34 ... 'baz': chr(92) + chr(0) + '2'})
35 35 ... ).iteritems())
36 36 [('baz', '\\\\\\x002'), ('branch', 'default'), ('foo', 'bar')]
37 37 """
38 38 extra = _defaultextra.copy()
39 39 for l in text.split('\0'):
40 40 if l:
41 41 if '\\0' in l:
42 42 # fix up \0 without getting into trouble with \\0
43 43 l = l.replace('\\\\', '\\\\\n')
44 44 l = l.replace('\\0', '\0')
45 45 l = l.replace('\n', '')
46 46 k, v = l.decode('string_escape').split(':', 1)
47 47 extra[k] = v
48 48 return extra
49 49
50 50 def encodeextra(d):
51 51 # keys must be sorted to produce a deterministic changelog entry
52 52 items = [_string_escape('%s:%s' % (k, d[k])) for k in sorted(d)]
53 53 return "\0".join(items)
54 54
55 55 def stripdesc(desc):
56 56 """strip trailing whitespace and leading and trailing empty lines"""
57 57 return '\n'.join([l.rstrip() for l in desc.splitlines()]).strip('\n')
58 58
59 59 class appender(object):
60 60 '''the changelog index must be updated last on disk, so we use this class
61 61 to delay writes to it'''
62 62 def __init__(self, vfs, name, mode, buf):
63 63 self.data = buf
64 64 fp = vfs(name, mode)
65 65 self.fp = fp
66 66 self.offset = fp.tell()
67 67 self.size = vfs.fstat(fp).st_size
68 68
69 69 def end(self):
70 70 return self.size + len("".join(self.data))
71 71 def tell(self):
72 72 return self.offset
73 73 def flush(self):
74 74 pass
75 75 def close(self):
76 76 self.fp.close()
77 77
78 78 def seek(self, offset, whence=0):
79 79 '''virtual file offset spans real file and data'''
80 80 if whence == 0:
81 81 self.offset = offset
82 82 elif whence == 1:
83 83 self.offset += offset
84 84 elif whence == 2:
85 85 self.offset = self.end() + offset
86 86 if self.offset < self.size:
87 87 self.fp.seek(self.offset)
88 88
89 89 def read(self, count=-1):
90 90 '''only trick here is reads that span real file and data'''
91 91 ret = ""
92 92 if self.offset < self.size:
93 93 s = self.fp.read(count)
94 94 ret = s
95 95 self.offset += len(s)
96 96 if count > 0:
97 97 count -= len(s)
98 98 if count != 0:
99 99 doff = self.offset - self.size
100 100 self.data.insert(0, "".join(self.data))
101 101 del self.data[1:]
102 102 s = self.data[0][doff:doff + count]
103 103 self.offset += len(s)
104 104 ret += s
105 105 return ret
106 106
107 107 def write(self, s):
108 108 self.data.append(str(s))
109 109 self.offset += len(s)
110 110
111 111 def delayopener(opener, target, divert, buf):
112 112 def o(name, mode='r'):
113 113 if name != target:
114 114 return opener(name, mode)
115 115 if divert:
116 116 return opener(name + ".a", mode.replace('a', 'w'))
117 117 # otherwise, divert to memory
118 118 return appender(opener, name, mode, buf)
119 119 return o
120 120
121 121 class changelog(revlog.revlog):
122 122 def __init__(self, opener):
123 123 revlog.revlog.__init__(self, opener, "00changelog.i")
124 124 if self._initempty:
125 125 # changelogs don't benefit from generaldelta
126 126 self.version &= ~revlog.REVLOGGENERALDELTA
127 127 self._generaldelta = False
128 128 self._realopener = opener
129 129 self._delayed = False
130 130 self._delaybuf = []
131 131 self._divert = False
132 132 self.filteredrevs = frozenset()
133 133
134 134 def tip(self):
135 135 """filtered version of revlog.tip"""
136 136 for i in xrange(len(self) -1, -2, -1):
137 137 if i not in self.filteredrevs:
138 138 return self.node(i)
139 139
140 140 def __iter__(self):
141 141 """filtered version of revlog.__iter__"""
142 142 if len(self.filteredrevs) == 0:
143 143 return revlog.revlog.__iter__(self)
144 144
145 145 def filterediter():
146 146 for i in xrange(len(self)):
147 147 if i not in self.filteredrevs:
148 148 yield i
149 149
150 150 return filterediter()
151 151
152 152 def revs(self, start=0, stop=None):
153 153 """filtered version of revlog.revs"""
154 154 for i in super(changelog, self).revs(start, stop):
155 155 if i not in self.filteredrevs:
156 156 yield i
157 157
158 158 @util.propertycache
159 159 def nodemap(self):
160 160 # XXX need filtering too
161 161 self.rev(self.node(0))
162 162 return self._nodecache
163 163
164 164 def hasnode(self, node):
165 165 """filtered version of revlog.hasnode"""
166 166 try:
167 167 i = self.rev(node)
168 168 return i not in self.filteredrevs
169 169 except KeyError:
170 170 return False
171 171
172 172 def headrevs(self):
173 173 if self.filteredrevs:
174 # XXX we should fix and use the C version
175 return self._headrevs()
174 try:
175 return self.index.headrevs(self.filteredrevs)
176 # AttributeError covers non-c-extension environments.
177 # TypeError allows us work with old c extensions.
178 except (AttributeError, TypeError):
179 return self._headrevs()
180
176 181 return super(changelog, self).headrevs()
177 182
178 183 def strip(self, *args, **kwargs):
179 184 # XXX make something better than assert
180 185 # We can't expect proper strip behavior if we are filtered.
181 186 assert not self.filteredrevs
182 187 super(changelog, self).strip(*args, **kwargs)
183 188
184 189 def rev(self, node):
185 190 """filtered version of revlog.rev"""
186 191 r = super(changelog, self).rev(node)
187 192 if r in self.filteredrevs:
188 193 raise error.LookupError(hex(node), self.indexfile, _('no node'))
189 194 return r
190 195
191 196 def node(self, rev):
192 197 """filtered version of revlog.node"""
193 198 if rev in self.filteredrevs:
194 199 raise IndexError(rev)
195 200 return super(changelog, self).node(rev)
196 201
197 202 def linkrev(self, rev):
198 203 """filtered version of revlog.linkrev"""
199 204 if rev in self.filteredrevs:
200 205 raise IndexError(rev)
201 206 return super(changelog, self).linkrev(rev)
202 207
203 208 def parentrevs(self, rev):
204 209 """filtered version of revlog.parentrevs"""
205 210 if rev in self.filteredrevs:
206 211 raise IndexError(rev)
207 212 return super(changelog, self).parentrevs(rev)
208 213
209 214 def flags(self, rev):
210 215 """filtered version of revlog.flags"""
211 216 if rev in self.filteredrevs:
212 217 raise IndexError(rev)
213 218 return super(changelog, self).flags(rev)
214 219
215 220 def delayupdate(self):
216 221 "delay visibility of index updates to other readers"
217 222 self._delayed = True
218 223 self._divert = (len(self) == 0)
219 224 self._delaybuf = []
220 225 self.opener = delayopener(self._realopener, self.indexfile,
221 226 self._divert, self._delaybuf)
222 227
223 228 def finalize(self, tr):
224 229 "finalize index updates"
225 230 self._delayed = False
226 231 self.opener = self._realopener
227 232 # move redirected index data back into place
228 233 if self._divert:
229 234 tmpname = self.indexfile + ".a"
230 235 nfile = self.opener.open(tmpname)
231 236 nfile.close()
232 237 self.opener.rename(tmpname, self.indexfile)
233 238 elif self._delaybuf:
234 239 fp = self.opener(self.indexfile, 'a')
235 240 fp.write("".join(self._delaybuf))
236 241 fp.close()
237 242 self._delaybuf = []
238 243 # split when we're done
239 244 self.checkinlinesize(tr)
240 245
241 246 def readpending(self, file):
242 247 r = revlog.revlog(self.opener, file)
243 248 self.index = r.index
244 249 self.nodemap = r.nodemap
245 250 self._nodecache = r._nodecache
246 251 self._chunkcache = r._chunkcache
247 252
248 253 def writepending(self):
249 254 "create a file containing the unfinalized state for pretxnchangegroup"
250 255 if self._delaybuf:
251 256 # make a temporary copy of the index
252 257 fp1 = self._realopener(self.indexfile)
253 258 fp2 = self._realopener(self.indexfile + ".a", "w")
254 259 fp2.write(fp1.read())
255 260 # add pending data
256 261 fp2.write("".join(self._delaybuf))
257 262 fp2.close()
258 263 # switch modes so finalize can simply rename
259 264 self._delaybuf = []
260 265 self._divert = True
261 266
262 267 if self._divert:
263 268 return True
264 269
265 270 return False
266 271
267 272 def checkinlinesize(self, tr, fp=None):
268 273 if not self._delayed:
269 274 revlog.revlog.checkinlinesize(self, tr, fp)
270 275
271 276 def read(self, node):
272 277 """
273 278 format used:
274 279 nodeid\n : manifest node in ascii
275 280 user\n : user, no \n or \r allowed
276 281 time tz extra\n : date (time is int or float, timezone is int)
277 282 : extra is metadata, encoded and separated by '\0'
278 283 : older versions ignore it
279 284 files\n\n : files modified by the cset, no \n or \r allowed
280 285 (.*) : comment (free text, ideally utf-8)
281 286
282 287 changelog v0 doesn't use extra
283 288 """
284 289 text = self.revision(node)
285 290 if not text:
286 291 return (nullid, "", (0, 0), [], "", _defaultextra)
287 292 last = text.index("\n\n")
288 293 desc = encoding.tolocal(text[last + 2:])
289 294 l = text[:last].split('\n')
290 295 manifest = bin(l[0])
291 296 user = encoding.tolocal(l[1])
292 297
293 298 tdata = l[2].split(' ', 2)
294 299 if len(tdata) != 3:
295 300 time = float(tdata[0])
296 301 try:
297 302 # various tools did silly things with the time zone field.
298 303 timezone = int(tdata[1])
299 304 except ValueError:
300 305 timezone = 0
301 306 extra = _defaultextra
302 307 else:
303 308 time, timezone = float(tdata[0]), int(tdata[1])
304 309 extra = decodeextra(tdata[2])
305 310
306 311 files = l[3:]
307 312 return (manifest, user, (time, timezone), files, desc, extra)
308 313
309 314 def add(self, manifest, files, desc, transaction, p1, p2,
310 315 user, date=None, extra=None):
311 316 # Convert to UTF-8 encoded bytestrings as the very first
312 317 # thing: calling any method on a localstr object will turn it
313 318 # into a str object and the cached UTF-8 string is thus lost.
314 319 user, desc = encoding.fromlocal(user), encoding.fromlocal(desc)
315 320
316 321 user = user.strip()
317 322 # An empty username or a username with a "\n" will make the
318 323 # revision text contain two "\n\n" sequences -> corrupt
319 324 # repository since read cannot unpack the revision.
320 325 if not user:
321 326 raise error.RevlogError(_("empty username"))
322 327 if "\n" in user:
323 328 raise error.RevlogError(_("username %s contains a newline")
324 329 % repr(user))
325 330
326 331 desc = stripdesc(desc)
327 332
328 333 if date:
329 334 parseddate = "%d %d" % util.parsedate(date)
330 335 else:
331 336 parseddate = "%d %d" % util.makedate()
332 337 if extra:
333 338 branch = extra.get("branch")
334 339 if branch in ("default", ""):
335 340 del extra["branch"]
336 341 elif branch in (".", "null", "tip"):
337 342 raise error.RevlogError(_('the name \'%s\' is reserved')
338 343 % branch)
339 344 if extra:
340 345 extra = encodeextra(extra)
341 346 parseddate = "%s %s" % (parseddate, extra)
342 347 l = [hex(manifest), user, parseddate] + sorted(files) + ["", desc]
343 348 text = "\n".join(l)
344 349 return self.addrevision(text, transaction, len(self), p1, p2)
345 350
346 351 def branchinfo(self, rev):
347 352 """return the branch name and open/close state of a revision
348 353
349 354 This function exists because creating a changectx object
350 355 just to access this is costly."""
351 356 extra = self.read(rev)[5]
352 357 return encoding.tolocal(extra.get("branch")), 'close' in extra
@@ -1,2177 +1,2258 b''
1 1 /*
2 2 parsers.c - efficient content parsing
3 3
4 4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
5 5
6 6 This software may be used and distributed according to the terms of
7 7 the GNU General Public License, incorporated herein by reference.
8 8 */
9 9
10 10 #include <Python.h>
11 11 #include <ctype.h>
12 12 #include <stddef.h>
13 13 #include <string.h>
14 14
15 15 #include "util.h"
16 16
17 17 static char *versionerrortext = "Python minor version mismatch";
18 18
19 19 static int8_t hextable[256] = {
20 20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
23 23 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
24 24 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
25 25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
26 26 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
27 27 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28 28 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29 29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
35 35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
36 36 };
37 37
38 38 static inline int hexdigit(const char *p, Py_ssize_t off)
39 39 {
40 40 int8_t val = hextable[(unsigned char)p[off]];
41 41
42 42 if (val >= 0) {
43 43 return val;
44 44 }
45 45
46 46 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
47 47 return 0;
48 48 }
49 49
50 50 /*
51 51 * Turn a hex-encoded string into binary.
52 52 */
53 53 static PyObject *unhexlify(const char *str, int len)
54 54 {
55 55 PyObject *ret;
56 56 char *d;
57 57 int i;
58 58
59 59 ret = PyBytes_FromStringAndSize(NULL, len / 2);
60 60
61 61 if (!ret)
62 62 return NULL;
63 63
64 64 d = PyBytes_AsString(ret);
65 65
66 66 for (i = 0; i < len;) {
67 67 int hi = hexdigit(str, i++);
68 68 int lo = hexdigit(str, i++);
69 69 *d++ = (hi << 4) | lo;
70 70 }
71 71
72 72 return ret;
73 73 }
74 74
75 75 /*
76 76 * This code assumes that a manifest is stitched together with newline
77 77 * ('\n') characters.
78 78 */
79 79 static PyObject *parse_manifest(PyObject *self, PyObject *args)
80 80 {
81 81 PyObject *mfdict, *fdict;
82 82 char *str, *start, *end;
83 83 int len;
84 84
85 85 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
86 86 &PyDict_Type, &mfdict,
87 87 &PyDict_Type, &fdict,
88 88 &str, &len))
89 89 goto quit;
90 90
91 91 start = str;
92 92 end = str + len;
93 93 while (start < end) {
94 94 PyObject *file = NULL, *node = NULL;
95 95 PyObject *flags = NULL;
96 96 char *zero = NULL, *newline = NULL;
97 97 ptrdiff_t nlen;
98 98
99 99 zero = memchr(start, '\0', end - start);
100 100 if (!zero) {
101 101 PyErr_SetString(PyExc_ValueError,
102 102 "manifest entry has no separator");
103 103 goto quit;
104 104 }
105 105
106 106 newline = memchr(zero + 1, '\n', end - (zero + 1));
107 107 if (!newline) {
108 108 PyErr_SetString(PyExc_ValueError,
109 109 "manifest contains trailing garbage");
110 110 goto quit;
111 111 }
112 112
113 113 file = PyBytes_FromStringAndSize(start, zero - start);
114 114
115 115 if (!file)
116 116 goto bail;
117 117
118 118 nlen = newline - zero - 1;
119 119
120 120 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
121 121 if (!node)
122 122 goto bail;
123 123
124 124 if (nlen > 40) {
125 125 flags = PyBytes_FromStringAndSize(zero + 41,
126 126 nlen - 40);
127 127 if (!flags)
128 128 goto bail;
129 129
130 130 if (PyDict_SetItem(fdict, file, flags) == -1)
131 131 goto bail;
132 132 }
133 133
134 134 if (PyDict_SetItem(mfdict, file, node) == -1)
135 135 goto bail;
136 136
137 137 start = newline + 1;
138 138
139 139 Py_XDECREF(flags);
140 140 Py_XDECREF(node);
141 141 Py_XDECREF(file);
142 142 continue;
143 143 bail:
144 144 Py_XDECREF(flags);
145 145 Py_XDECREF(node);
146 146 Py_XDECREF(file);
147 147 goto quit;
148 148 }
149 149
150 150 Py_INCREF(Py_None);
151 151 return Py_None;
152 152 quit:
153 153 return NULL;
154 154 }
155 155
156 156 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
157 157 int size, int mtime)
158 158 {
159 159 dirstateTupleObject *t = PyObject_New(dirstateTupleObject,
160 160 &dirstateTupleType);
161 161 if (!t)
162 162 return NULL;
163 163 t->state = state;
164 164 t->mode = mode;
165 165 t->size = size;
166 166 t->mtime = mtime;
167 167 return t;
168 168 }
169 169
170 170 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
171 171 PyObject *kwds)
172 172 {
173 173 /* We do all the initialization here and not a tp_init function because
174 174 * dirstate_tuple is immutable. */
175 175 dirstateTupleObject *t;
176 176 char state;
177 177 int size, mode, mtime;
178 178 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
179 179 return NULL;
180 180
181 181 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
182 182 if (!t)
183 183 return NULL;
184 184 t->state = state;
185 185 t->mode = mode;
186 186 t->size = size;
187 187 t->mtime = mtime;
188 188
189 189 return (PyObject *)t;
190 190 }
191 191
192 192 static void dirstate_tuple_dealloc(PyObject *o)
193 193 {
194 194 PyObject_Del(o);
195 195 }
196 196
197 197 static Py_ssize_t dirstate_tuple_length(PyObject *o)
198 198 {
199 199 return 4;
200 200 }
201 201
202 202 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
203 203 {
204 204 dirstateTupleObject *t = (dirstateTupleObject *)o;
205 205 switch (i) {
206 206 case 0:
207 207 return PyBytes_FromStringAndSize(&t->state, 1);
208 208 case 1:
209 209 return PyInt_FromLong(t->mode);
210 210 case 2:
211 211 return PyInt_FromLong(t->size);
212 212 case 3:
213 213 return PyInt_FromLong(t->mtime);
214 214 default:
215 215 PyErr_SetString(PyExc_IndexError, "index out of range");
216 216 return NULL;
217 217 }
218 218 }
219 219
220 220 static PySequenceMethods dirstate_tuple_sq = {
221 221 dirstate_tuple_length, /* sq_length */
222 222 0, /* sq_concat */
223 223 0, /* sq_repeat */
224 224 dirstate_tuple_item, /* sq_item */
225 225 0, /* sq_ass_item */
226 226 0, /* sq_contains */
227 227 0, /* sq_inplace_concat */
228 228 0 /* sq_inplace_repeat */
229 229 };
230 230
231 231 PyTypeObject dirstateTupleType = {
232 232 PyVarObject_HEAD_INIT(NULL, 0)
233 233 "dirstate_tuple", /* tp_name */
234 234 sizeof(dirstateTupleObject),/* tp_basicsize */
235 235 0, /* tp_itemsize */
236 236 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
237 237 0, /* tp_print */
238 238 0, /* tp_getattr */
239 239 0, /* tp_setattr */
240 240 0, /* tp_compare */
241 241 0, /* tp_repr */
242 242 0, /* tp_as_number */
243 243 &dirstate_tuple_sq, /* tp_as_sequence */
244 244 0, /* tp_as_mapping */
245 245 0, /* tp_hash */
246 246 0, /* tp_call */
247 247 0, /* tp_str */
248 248 0, /* tp_getattro */
249 249 0, /* tp_setattro */
250 250 0, /* tp_as_buffer */
251 251 Py_TPFLAGS_DEFAULT, /* tp_flags */
252 252 "dirstate tuple", /* tp_doc */
253 253 0, /* tp_traverse */
254 254 0, /* tp_clear */
255 255 0, /* tp_richcompare */
256 256 0, /* tp_weaklistoffset */
257 257 0, /* tp_iter */
258 258 0, /* tp_iternext */
259 259 0, /* tp_methods */
260 260 0, /* tp_members */
261 261 0, /* tp_getset */
262 262 0, /* tp_base */
263 263 0, /* tp_dict */
264 264 0, /* tp_descr_get */
265 265 0, /* tp_descr_set */
266 266 0, /* tp_dictoffset */
267 267 0, /* tp_init */
268 268 0, /* tp_alloc */
269 269 dirstate_tuple_new, /* tp_new */
270 270 };
271 271
272 272 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
273 273 {
274 274 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
275 275 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
276 276 char state, *cur, *str, *cpos;
277 277 int mode, size, mtime;
278 278 unsigned int flen, len, pos = 40;
279 279 int readlen;
280 280
281 281 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
282 282 &PyDict_Type, &dmap,
283 283 &PyDict_Type, &cmap,
284 284 &str, &readlen))
285 285 goto quit;
286 286
287 287 if (readlen < 0)
288 288 goto quit;
289 289
290 290 len = readlen;
291 291
292 292 /* read parents */
293 293 if (len < 40)
294 294 goto quit;
295 295
296 296 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
297 297 if (!parents)
298 298 goto quit;
299 299
300 300 /* read filenames */
301 301 while (pos >= 40 && pos < len) {
302 302 cur = str + pos;
303 303 /* unpack header */
304 304 state = *cur;
305 305 mode = getbe32(cur + 1);
306 306 size = getbe32(cur + 5);
307 307 mtime = getbe32(cur + 9);
308 308 flen = getbe32(cur + 13);
309 309 pos += 17;
310 310 cur += 17;
311 311 if (flen > len - pos) {
312 312 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
313 313 goto quit;
314 314 }
315 315
316 316 entry = (PyObject *)make_dirstate_tuple(state, mode, size,
317 317 mtime);
318 318 cpos = memchr(cur, 0, flen);
319 319 if (cpos) {
320 320 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
321 321 cname = PyBytes_FromStringAndSize(cpos + 1,
322 322 flen - (cpos - cur) - 1);
323 323 if (!fname || !cname ||
324 324 PyDict_SetItem(cmap, fname, cname) == -1 ||
325 325 PyDict_SetItem(dmap, fname, entry) == -1)
326 326 goto quit;
327 327 Py_DECREF(cname);
328 328 } else {
329 329 fname = PyBytes_FromStringAndSize(cur, flen);
330 330 if (!fname ||
331 331 PyDict_SetItem(dmap, fname, entry) == -1)
332 332 goto quit;
333 333 }
334 334 Py_DECREF(fname);
335 335 Py_DECREF(entry);
336 336 fname = cname = entry = NULL;
337 337 pos += flen;
338 338 }
339 339
340 340 ret = parents;
341 341 Py_INCREF(ret);
342 342 quit:
343 343 Py_XDECREF(fname);
344 344 Py_XDECREF(cname);
345 345 Py_XDECREF(entry);
346 346 Py_XDECREF(parents);
347 347 return ret;
348 348 }
349 349
350 350 /*
351 351 * Efficiently pack a dirstate object into its on-disk format.
352 352 */
353 353 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
354 354 {
355 355 PyObject *packobj = NULL;
356 356 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
357 357 Py_ssize_t nbytes, pos, l;
358 358 PyObject *k, *v, *pn;
359 359 char *p, *s;
360 360 double now;
361 361
362 362 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
363 363 &PyDict_Type, &map, &PyDict_Type, &copymap,
364 364 &pl, &now))
365 365 return NULL;
366 366
367 367 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
368 368 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
369 369 return NULL;
370 370 }
371 371
372 372 /* Figure out how much we need to allocate. */
373 373 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
374 374 PyObject *c;
375 375 if (!PyString_Check(k)) {
376 376 PyErr_SetString(PyExc_TypeError, "expected string key");
377 377 goto bail;
378 378 }
379 379 nbytes += PyString_GET_SIZE(k) + 17;
380 380 c = PyDict_GetItem(copymap, k);
381 381 if (c) {
382 382 if (!PyString_Check(c)) {
383 383 PyErr_SetString(PyExc_TypeError,
384 384 "expected string key");
385 385 goto bail;
386 386 }
387 387 nbytes += PyString_GET_SIZE(c) + 1;
388 388 }
389 389 }
390 390
391 391 packobj = PyString_FromStringAndSize(NULL, nbytes);
392 392 if (packobj == NULL)
393 393 goto bail;
394 394
395 395 p = PyString_AS_STRING(packobj);
396 396
397 397 pn = PySequence_ITEM(pl, 0);
398 398 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
399 399 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
400 400 goto bail;
401 401 }
402 402 memcpy(p, s, l);
403 403 p += 20;
404 404 pn = PySequence_ITEM(pl, 1);
405 405 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
406 406 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
407 407 goto bail;
408 408 }
409 409 memcpy(p, s, l);
410 410 p += 20;
411 411
412 412 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
413 413 dirstateTupleObject *tuple;
414 414 char state;
415 415 uint32_t mode, size, mtime;
416 416 Py_ssize_t len, l;
417 417 PyObject *o;
418 418 char *t;
419 419
420 420 if (!dirstate_tuple_check(v)) {
421 421 PyErr_SetString(PyExc_TypeError,
422 422 "expected a dirstate tuple");
423 423 goto bail;
424 424 }
425 425 tuple = (dirstateTupleObject *)v;
426 426
427 427 state = tuple->state;
428 428 mode = tuple->mode;
429 429 size = tuple->size;
430 430 mtime = tuple->mtime;
431 431 if (state == 'n' && mtime == (uint32_t)now) {
432 432 /* See pure/parsers.py:pack_dirstate for why we do
433 433 * this. */
434 434 mtime = -1;
435 435 mtime_unset = (PyObject *)make_dirstate_tuple(
436 436 state, mode, size, mtime);
437 437 if (!mtime_unset)
438 438 goto bail;
439 439 if (PyDict_SetItem(map, k, mtime_unset) == -1)
440 440 goto bail;
441 441 Py_DECREF(mtime_unset);
442 442 mtime_unset = NULL;
443 443 }
444 444 *p++ = state;
445 445 putbe32(mode, p);
446 446 putbe32(size, p + 4);
447 447 putbe32(mtime, p + 8);
448 448 t = p + 12;
449 449 p += 16;
450 450 len = PyString_GET_SIZE(k);
451 451 memcpy(p, PyString_AS_STRING(k), len);
452 452 p += len;
453 453 o = PyDict_GetItem(copymap, k);
454 454 if (o) {
455 455 *p++ = '\0';
456 456 l = PyString_GET_SIZE(o);
457 457 memcpy(p, PyString_AS_STRING(o), l);
458 458 p += l;
459 459 len += l + 1;
460 460 }
461 461 putbe32((uint32_t)len, t);
462 462 }
463 463
464 464 pos = p - PyString_AS_STRING(packobj);
465 465 if (pos != nbytes) {
466 466 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
467 467 (long)pos, (long)nbytes);
468 468 goto bail;
469 469 }
470 470
471 471 return packobj;
472 472 bail:
473 473 Py_XDECREF(mtime_unset);
474 474 Py_XDECREF(packobj);
475 475 return NULL;
476 476 }
477 477
478 478 /*
479 479 * A base-16 trie for fast node->rev mapping.
480 480 *
481 481 * Positive value is index of the next node in the trie
482 482 * Negative value is a leaf: -(rev + 1)
483 483 * Zero is empty
484 484 */
485 485 typedef struct {
486 486 int children[16];
487 487 } nodetree;
488 488
489 489 /*
490 490 * This class has two behaviours.
491 491 *
492 492 * When used in a list-like way (with integer keys), we decode an
493 493 * entry in a RevlogNG index file on demand. Our last entry is a
494 494 * sentinel, always a nullid. We have limited support for
495 495 * integer-keyed insert and delete, only at elements right before the
496 496 * sentinel.
497 497 *
498 498 * With string keys, we lazily perform a reverse mapping from node to
499 499 * rev, using a base-16 trie.
500 500 */
501 501 typedef struct {
502 502 PyObject_HEAD
503 503 /* Type-specific fields go here. */
504 504 PyObject *data; /* raw bytes of index */
505 505 PyObject **cache; /* cached tuples */
506 506 const char **offsets; /* populated on demand */
507 507 Py_ssize_t raw_length; /* original number of elements */
508 508 Py_ssize_t length; /* current number of elements */
509 509 PyObject *added; /* populated on demand */
510 510 PyObject *headrevs; /* cache, invalidated on changes */
511 PyObject *filteredrevs;/* filtered revs set */
511 512 nodetree *nt; /* base-16 trie */
512 513 int ntlength; /* # nodes in use */
513 514 int ntcapacity; /* # nodes allocated */
514 515 int ntdepth; /* maximum depth of tree */
515 516 int ntsplits; /* # splits performed */
516 517 int ntrev; /* last rev scanned */
517 518 int ntlookups; /* # lookups */
518 519 int ntmisses; /* # lookups that miss the cache */
519 520 int inlined;
520 521 } indexObject;
521 522
522 523 static Py_ssize_t index_length(const indexObject *self)
523 524 {
524 525 if (self->added == NULL)
525 526 return self->length;
526 527 return self->length + PyList_GET_SIZE(self->added);
527 528 }
528 529
529 530 static PyObject *nullentry;
530 531 static const char nullid[20];
531 532
532 533 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
533 534
534 535 #if LONG_MAX == 0x7fffffffL
535 536 static char *tuple_format = "Kiiiiiis#";
536 537 #else
537 538 static char *tuple_format = "kiiiiiis#";
538 539 #endif
539 540
540 541 /* A RevlogNG v1 index entry is 64 bytes long. */
541 542 static const long v1_hdrsize = 64;
542 543
543 544 /*
544 545 * Return a pointer to the beginning of a RevlogNG record.
545 546 */
546 547 static const char *index_deref(indexObject *self, Py_ssize_t pos)
547 548 {
548 549 if (self->inlined && pos > 0) {
549 550 if (self->offsets == NULL) {
550 551 self->offsets = malloc(self->raw_length *
551 552 sizeof(*self->offsets));
552 553 if (self->offsets == NULL)
553 554 return (const char *)PyErr_NoMemory();
554 555 inline_scan(self, self->offsets);
555 556 }
556 557 return self->offsets[pos];
557 558 }
558 559
559 560 return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
560 561 }
561 562
562 563 /*
563 564 * RevlogNG format (all in big endian, data may be inlined):
564 565 * 6 bytes: offset
565 566 * 2 bytes: flags
566 567 * 4 bytes: compressed length
567 568 * 4 bytes: uncompressed length
568 569 * 4 bytes: base revision
569 570 * 4 bytes: link revision
570 571 * 4 bytes: parent 1 revision
571 572 * 4 bytes: parent 2 revision
572 573 * 32 bytes: nodeid (only 20 bytes used)
573 574 */
574 575 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
575 576 {
576 577 uint64_t offset_flags;
577 578 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
578 579 const char *c_node_id;
579 580 const char *data;
580 581 Py_ssize_t length = index_length(self);
581 582 PyObject *entry;
582 583
583 584 if (pos < 0)
584 585 pos += length;
585 586
586 587 if (pos < 0 || pos >= length) {
587 588 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
588 589 return NULL;
589 590 }
590 591
591 592 if (pos == length - 1) {
592 593 Py_INCREF(nullentry);
593 594 return nullentry;
594 595 }
595 596
596 597 if (pos >= self->length - 1) {
597 598 PyObject *obj;
598 599 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
599 600 Py_INCREF(obj);
600 601 return obj;
601 602 }
602 603
603 604 if (self->cache) {
604 605 if (self->cache[pos]) {
605 606 Py_INCREF(self->cache[pos]);
606 607 return self->cache[pos];
607 608 }
608 609 } else {
609 610 self->cache = calloc(self->raw_length, sizeof(PyObject *));
610 611 if (self->cache == NULL)
611 612 return PyErr_NoMemory();
612 613 }
613 614
614 615 data = index_deref(self, pos);
615 616 if (data == NULL)
616 617 return NULL;
617 618
618 619 offset_flags = getbe32(data + 4);
619 620 if (pos == 0) /* mask out version number for the first entry */
620 621 offset_flags &= 0xFFFF;
621 622 else {
622 623 uint32_t offset_high = getbe32(data);
623 624 offset_flags |= ((uint64_t)offset_high) << 32;
624 625 }
625 626
626 627 comp_len = getbe32(data + 8);
627 628 uncomp_len = getbe32(data + 12);
628 629 base_rev = getbe32(data + 16);
629 630 link_rev = getbe32(data + 20);
630 631 parent_1 = getbe32(data + 24);
631 632 parent_2 = getbe32(data + 28);
632 633 c_node_id = data + 32;
633 634
634 635 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
635 636 uncomp_len, base_rev, link_rev,
636 637 parent_1, parent_2, c_node_id, 20);
637 638
638 639 if (entry) {
639 640 PyObject_GC_UnTrack(entry);
640 641 Py_INCREF(entry);
641 642 }
642 643
643 644 self->cache[pos] = entry;
644 645
645 646 return entry;
646 647 }
647 648
648 649 /*
649 650 * Return the 20-byte SHA of the node corresponding to the given rev.
650 651 */
651 652 static const char *index_node(indexObject *self, Py_ssize_t pos)
652 653 {
653 654 Py_ssize_t length = index_length(self);
654 655 const char *data;
655 656
656 657 if (pos == length - 1 || pos == INT_MAX)
657 658 return nullid;
658 659
659 660 if (pos >= length)
660 661 return NULL;
661 662
662 663 if (pos >= self->length - 1) {
663 664 PyObject *tuple, *str;
664 665 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
665 666 str = PyTuple_GetItem(tuple, 7);
666 667 return str ? PyString_AS_STRING(str) : NULL;
667 668 }
668 669
669 670 data = index_deref(self, pos);
670 671 return data ? data + 32 : NULL;
671 672 }
672 673
673 674 static int nt_insert(indexObject *self, const char *node, int rev);
674 675
675 676 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
676 677 {
677 678 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
678 679 return -1;
679 680 if (*nodelen == 20)
680 681 return 0;
681 682 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
682 683 return -1;
683 684 }
684 685
685 686 static PyObject *index_insert(indexObject *self, PyObject *args)
686 687 {
687 688 PyObject *obj;
688 689 char *node;
689 690 Py_ssize_t offset, len, nodelen;
690 691
691 692 if (!PyArg_ParseTuple(args, "nO", &offset, &obj))
692 693 return NULL;
693 694
694 695 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
695 696 PyErr_SetString(PyExc_TypeError, "8-tuple required");
696 697 return NULL;
697 698 }
698 699
699 700 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
700 701 return NULL;
701 702
702 703 len = index_length(self);
703 704
704 705 if (offset < 0)
705 706 offset += len;
706 707
707 708 if (offset != len - 1) {
708 709 PyErr_SetString(PyExc_IndexError,
709 710 "insert only supported at index -1");
710 711 return NULL;
711 712 }
712 713
713 714 if (offset > INT_MAX) {
714 715 PyErr_SetString(PyExc_ValueError,
715 716 "currently only 2**31 revs supported");
716 717 return NULL;
717 718 }
718 719
719 720 if (self->added == NULL) {
720 721 self->added = PyList_New(0);
721 722 if (self->added == NULL)
722 723 return NULL;
723 724 }
724 725
725 726 if (PyList_Append(self->added, obj) == -1)
726 727 return NULL;
727 728
728 729 if (self->nt)
729 730 nt_insert(self, node, (int)offset);
730 731
731 732 Py_CLEAR(self->headrevs);
732 733 Py_RETURN_NONE;
733 734 }
734 735
735 736 static void _index_clearcaches(indexObject *self)
736 737 {
737 738 if (self->cache) {
738 739 Py_ssize_t i;
739 740
740 741 for (i = 0; i < self->raw_length; i++)
741 742 Py_CLEAR(self->cache[i]);
742 743 free(self->cache);
743 744 self->cache = NULL;
744 745 }
745 746 if (self->offsets) {
746 747 free(self->offsets);
747 748 self->offsets = NULL;
748 749 }
749 750 if (self->nt) {
750 751 free(self->nt);
751 752 self->nt = NULL;
752 753 }
753 754 Py_CLEAR(self->headrevs);
754 755 }
755 756
756 757 static PyObject *index_clearcaches(indexObject *self)
757 758 {
758 759 _index_clearcaches(self);
759 760 self->ntlength = self->ntcapacity = 0;
760 761 self->ntdepth = self->ntsplits = 0;
761 762 self->ntrev = -1;
762 763 self->ntlookups = self->ntmisses = 0;
763 764 Py_RETURN_NONE;
764 765 }
765 766
766 767 static PyObject *index_stats(indexObject *self)
767 768 {
768 769 PyObject *obj = PyDict_New();
769 770
770 771 if (obj == NULL)
771 772 return NULL;
772 773
773 774 #define istat(__n, __d) \
774 775 if (PyDict_SetItemString(obj, __d, PyInt_FromSsize_t(self->__n)) == -1) \
775 776 goto bail;
776 777
777 778 if (self->added) {
778 779 Py_ssize_t len = PyList_GET_SIZE(self->added);
779 780 if (PyDict_SetItemString(obj, "index entries added",
780 781 PyInt_FromSsize_t(len)) == -1)
781 782 goto bail;
782 783 }
783 784
784 785 if (self->raw_length != self->length - 1)
785 786 istat(raw_length, "revs on disk");
786 787 istat(length, "revs in memory");
787 788 istat(ntcapacity, "node trie capacity");
788 789 istat(ntdepth, "node trie depth");
789 790 istat(ntlength, "node trie count");
790 791 istat(ntlookups, "node trie lookups");
791 792 istat(ntmisses, "node trie misses");
792 793 istat(ntrev, "node trie last rev scanned");
793 794 istat(ntsplits, "node trie splits");
794 795
795 796 #undef istat
796 797
797 798 return obj;
798 799
799 800 bail:
800 801 Py_XDECREF(obj);
801 802 return NULL;
802 803 }
803 804
804 805 /*
805 806 * When we cache a list, we want to be sure the caller can't mutate
806 807 * the cached copy.
807 808 */
808 809 static PyObject *list_copy(PyObject *list)
809 810 {
810 811 Py_ssize_t len = PyList_GET_SIZE(list);
811 812 PyObject *newlist = PyList_New(len);
812 813 Py_ssize_t i;
813 814
814 815 if (newlist == NULL)
815 816 return NULL;
816 817
817 818 for (i = 0; i < len; i++) {
818 819 PyObject *obj = PyList_GET_ITEM(list, i);
819 820 Py_INCREF(obj);
820 821 PyList_SET_ITEM(newlist, i, obj);
821 822 }
822 823
823 824 return newlist;
824 825 }
825 826
826 static PyObject *index_headrevs(indexObject *self)
827 static int check_filter(PyObject *filter, Py_ssize_t arg) {
828 if (filter) {
829 PyObject *arglist, *result;
830 int isfiltered;
831
832 arglist = Py_BuildValue("(n)", arg);
833 if (!arglist) {
834 return -1;
835 }
836
837 result = PyEval_CallObject(filter, arglist);
838 Py_DECREF(arglist);
839 if (!result) {
840 return -1;
841 }
842
843 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
844 * same as this function, so we can just return it directly.*/
845 isfiltered = PyObject_IsTrue(result);
846 Py_DECREF(result);
847 return isfiltered;
848 } else {
849 return 0;
850 }
851 }
852
853 static PyObject *index_headrevs(indexObject *self, PyObject *args)
827 854 {
828 855 Py_ssize_t i, len, addlen;
829 856 char *nothead = NULL;
830 857 PyObject *heads;
858 PyObject *filter = NULL;
859 PyObject *filteredrevs = Py_None;
831 860
832 if (self->headrevs)
861 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
862 return NULL;
863 }
864
865 if (self->headrevs && filteredrevs == self->filteredrevs)
833 866 return list_copy(self->headrevs);
834 867
868 Py_DECREF(self->filteredrevs);
869 self->filteredrevs = filteredrevs;
870 Py_INCREF(filteredrevs);
871
872 if (filteredrevs != Py_None) {
873 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
874 if (!filter) {
875 PyErr_SetString(PyExc_TypeError,
876 "filteredrevs has no attribute __contains__");
877 goto bail;
878 }
879 }
880
835 881 len = index_length(self) - 1;
836 882 heads = PyList_New(0);
837 883 if (heads == NULL)
838 884 goto bail;
839 885 if (len == 0) {
840 886 PyObject *nullid = PyInt_FromLong(-1);
841 887 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
842 888 Py_XDECREF(nullid);
843 889 goto bail;
844 890 }
845 891 goto done;
846 892 }
847 893
848 894 nothead = calloc(len, 1);
849 895 if (nothead == NULL)
850 896 goto bail;
851 897
852 898 for (i = 0; i < self->raw_length; i++) {
853 const char *data = index_deref(self, i);
854 int parent_1 = getbe32(data + 24);
855 int parent_2 = getbe32(data + 28);
899 const char *data;
900 int parent_1, parent_2, isfiltered;
901
902 isfiltered = check_filter(filter, i);
903 if (isfiltered == -1) {
904 PyErr_SetString(PyExc_TypeError,
905 "unable to check filter");
906 goto bail;
907 }
908
909 if (isfiltered) {
910 nothead[i] = 1;
911 continue;
912 }
913
914 data = index_deref(self, i);
915 parent_1 = getbe32(data + 24);
916 parent_2 = getbe32(data + 28);
917
856 918 if (parent_1 >= 0)
857 919 nothead[parent_1] = 1;
858 920 if (parent_2 >= 0)
859 921 nothead[parent_2] = 1;
860 922 }
861 923
862 924 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
863 925
864 926 for (i = 0; i < addlen; i++) {
865 927 PyObject *rev = PyList_GET_ITEM(self->added, i);
866 928 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
867 929 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
868 930 long parent_1, parent_2;
931 int isfiltered;
869 932
870 933 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
871 934 PyErr_SetString(PyExc_TypeError,
872 935 "revlog parents are invalid");
873 936 goto bail;
874 937 }
938
939 isfiltered = check_filter(filter, i);
940 if (isfiltered == -1) {
941 PyErr_SetString(PyExc_TypeError,
942 "unable to check filter");
943 goto bail;
944 }
945
946 if (isfiltered) {
947 nothead[i] = 1;
948 continue;
949 }
950
875 951 parent_1 = PyInt_AS_LONG(p1);
876 952 parent_2 = PyInt_AS_LONG(p2);
877 953 if (parent_1 >= 0)
878 954 nothead[parent_1] = 1;
879 955 if (parent_2 >= 0)
880 956 nothead[parent_2] = 1;
881 957 }
882 958
883 959 for (i = 0; i < len; i++) {
884 960 PyObject *head;
885 961
886 962 if (nothead[i])
887 963 continue;
888 964 head = PyInt_FromSsize_t(i);
889 965 if (head == NULL || PyList_Append(heads, head) == -1) {
890 966 Py_XDECREF(head);
891 967 goto bail;
892 968 }
893 969 }
894 970
895 971 done:
896 972 self->headrevs = heads;
973 Py_XDECREF(filter);
897 974 free(nothead);
898 975 return list_copy(self->headrevs);
899 976 bail:
977 Py_XDECREF(filter);
900 978 Py_XDECREF(heads);
901 979 free(nothead);
902 980 return NULL;
903 981 }
904 982
905 983 static inline int nt_level(const char *node, Py_ssize_t level)
906 984 {
907 985 int v = node[level>>1];
908 986 if (!(level & 1))
909 987 v >>= 4;
910 988 return v & 0xf;
911 989 }
912 990
913 991 /*
914 992 * Return values:
915 993 *
916 994 * -4: match is ambiguous (multiple candidates)
917 995 * -2: not found
918 996 * rest: valid rev
919 997 */
920 998 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
921 999 int hex)
922 1000 {
923 1001 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
924 1002 int level, maxlevel, off;
925 1003
926 1004 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
927 1005 return -1;
928 1006
929 1007 if (self->nt == NULL)
930 1008 return -2;
931 1009
932 1010 if (hex)
933 1011 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
934 1012 else
935 1013 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
936 1014
937 1015 for (level = off = 0; level < maxlevel; level++) {
938 1016 int k = getnybble(node, level);
939 1017 nodetree *n = &self->nt[off];
940 1018 int v = n->children[k];
941 1019
942 1020 if (v < 0) {
943 1021 const char *n;
944 1022 Py_ssize_t i;
945 1023
946 1024 v = -v - 1;
947 1025 n = index_node(self, v);
948 1026 if (n == NULL)
949 1027 return -2;
950 1028 for (i = level; i < maxlevel; i++)
951 1029 if (getnybble(node, i) != nt_level(n, i))
952 1030 return -2;
953 1031 return v;
954 1032 }
955 1033 if (v == 0)
956 1034 return -2;
957 1035 off = v;
958 1036 }
959 1037 /* multiple matches against an ambiguous prefix */
960 1038 return -4;
961 1039 }
962 1040
963 1041 static int nt_new(indexObject *self)
964 1042 {
965 1043 if (self->ntlength == self->ntcapacity) {
966 1044 self->ntcapacity *= 2;
967 1045 self->nt = realloc(self->nt,
968 1046 self->ntcapacity * sizeof(nodetree));
969 1047 if (self->nt == NULL) {
970 1048 PyErr_SetString(PyExc_MemoryError, "out of memory");
971 1049 return -1;
972 1050 }
973 1051 memset(&self->nt[self->ntlength], 0,
974 1052 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
975 1053 }
976 1054 return self->ntlength++;
977 1055 }
978 1056
979 1057 static int nt_insert(indexObject *self, const char *node, int rev)
980 1058 {
981 1059 int level = 0;
982 1060 int off = 0;
983 1061
984 1062 while (level < 40) {
985 1063 int k = nt_level(node, level);
986 1064 nodetree *n;
987 1065 int v;
988 1066
989 1067 n = &self->nt[off];
990 1068 v = n->children[k];
991 1069
992 1070 if (v == 0) {
993 1071 n->children[k] = -rev - 1;
994 1072 return 0;
995 1073 }
996 1074 if (v < 0) {
997 1075 const char *oldnode = index_node(self, -v - 1);
998 1076 int noff;
999 1077
1000 1078 if (!oldnode || !memcmp(oldnode, node, 20)) {
1001 1079 n->children[k] = -rev - 1;
1002 1080 return 0;
1003 1081 }
1004 1082 noff = nt_new(self);
1005 1083 if (noff == -1)
1006 1084 return -1;
1007 1085 /* self->nt may have been changed by realloc */
1008 1086 self->nt[off].children[k] = noff;
1009 1087 off = noff;
1010 1088 n = &self->nt[off];
1011 1089 n->children[nt_level(oldnode, ++level)] = v;
1012 1090 if (level > self->ntdepth)
1013 1091 self->ntdepth = level;
1014 1092 self->ntsplits += 1;
1015 1093 } else {
1016 1094 level += 1;
1017 1095 off = v;
1018 1096 }
1019 1097 }
1020 1098
1021 1099 return -1;
1022 1100 }
1023 1101
1024 1102 static int nt_init(indexObject *self)
1025 1103 {
1026 1104 if (self->nt == NULL) {
1027 1105 if (self->raw_length > INT_MAX) {
1028 1106 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
1029 1107 return -1;
1030 1108 }
1031 1109 self->ntcapacity = self->raw_length < 4
1032 1110 ? 4 : (int)self->raw_length / 2;
1033 1111
1034 1112 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
1035 1113 if (self->nt == NULL) {
1036 1114 PyErr_NoMemory();
1037 1115 return -1;
1038 1116 }
1039 1117 self->ntlength = 1;
1040 1118 self->ntrev = (int)index_length(self) - 1;
1041 1119 self->ntlookups = 1;
1042 1120 self->ntmisses = 0;
1043 1121 if (nt_insert(self, nullid, INT_MAX) == -1)
1044 1122 return -1;
1045 1123 }
1046 1124 return 0;
1047 1125 }
1048 1126
1049 1127 /*
1050 1128 * Return values:
1051 1129 *
1052 1130 * -3: error (exception set)
1053 1131 * -2: not found (no exception set)
1054 1132 * rest: valid rev
1055 1133 */
1056 1134 static int index_find_node(indexObject *self,
1057 1135 const char *node, Py_ssize_t nodelen)
1058 1136 {
1059 1137 int rev;
1060 1138
1061 1139 self->ntlookups++;
1062 1140 rev = nt_find(self, node, nodelen, 0);
1063 1141 if (rev >= -1)
1064 1142 return rev;
1065 1143
1066 1144 if (nt_init(self) == -1)
1067 1145 return -3;
1068 1146
1069 1147 /*
1070 1148 * For the first handful of lookups, we scan the entire index,
1071 1149 * and cache only the matching nodes. This optimizes for cases
1072 1150 * like "hg tip", where only a few nodes are accessed.
1073 1151 *
1074 1152 * After that, we cache every node we visit, using a single
1075 1153 * scan amortized over multiple lookups. This gives the best
1076 1154 * bulk performance, e.g. for "hg log".
1077 1155 */
1078 1156 if (self->ntmisses++ < 4) {
1079 1157 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1080 1158 const char *n = index_node(self, rev);
1081 1159 if (n == NULL)
1082 1160 return -2;
1083 1161 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1084 1162 if (nt_insert(self, n, rev) == -1)
1085 1163 return -3;
1086 1164 break;
1087 1165 }
1088 1166 }
1089 1167 } else {
1090 1168 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1091 1169 const char *n = index_node(self, rev);
1092 1170 if (n == NULL) {
1093 1171 self->ntrev = rev + 1;
1094 1172 return -2;
1095 1173 }
1096 1174 if (nt_insert(self, n, rev) == -1) {
1097 1175 self->ntrev = rev + 1;
1098 1176 return -3;
1099 1177 }
1100 1178 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1101 1179 break;
1102 1180 }
1103 1181 }
1104 1182 self->ntrev = rev;
1105 1183 }
1106 1184
1107 1185 if (rev >= 0)
1108 1186 return rev;
1109 1187 return -2;
1110 1188 }
1111 1189
1112 1190 static PyObject *raise_revlog_error(void)
1113 1191 {
1114 1192 static PyObject *errclass;
1115 1193 PyObject *mod = NULL, *errobj;
1116 1194
1117 1195 if (errclass == NULL) {
1118 1196 PyObject *dict;
1119 1197
1120 1198 mod = PyImport_ImportModule("mercurial.error");
1121 1199 if (mod == NULL)
1122 1200 goto classfail;
1123 1201
1124 1202 dict = PyModule_GetDict(mod);
1125 1203 if (dict == NULL)
1126 1204 goto classfail;
1127 1205
1128 1206 errclass = PyDict_GetItemString(dict, "RevlogError");
1129 1207 if (errclass == NULL) {
1130 1208 PyErr_SetString(PyExc_SystemError,
1131 1209 "could not find RevlogError");
1132 1210 goto classfail;
1133 1211 }
1134 1212 Py_INCREF(errclass);
1135 1213 }
1136 1214
1137 1215 errobj = PyObject_CallFunction(errclass, NULL);
1138 1216 if (errobj == NULL)
1139 1217 return NULL;
1140 1218 PyErr_SetObject(errclass, errobj);
1141 1219 return errobj;
1142 1220
1143 1221 classfail:
1144 1222 Py_XDECREF(mod);
1145 1223 return NULL;
1146 1224 }
1147 1225
1148 1226 static PyObject *index_getitem(indexObject *self, PyObject *value)
1149 1227 {
1150 1228 char *node;
1151 1229 Py_ssize_t nodelen;
1152 1230 int rev;
1153 1231
1154 1232 if (PyInt_Check(value))
1155 1233 return index_get(self, PyInt_AS_LONG(value));
1156 1234
1157 1235 if (node_check(value, &node, &nodelen) == -1)
1158 1236 return NULL;
1159 1237 rev = index_find_node(self, node, nodelen);
1160 1238 if (rev >= -1)
1161 1239 return PyInt_FromLong(rev);
1162 1240 if (rev == -2)
1163 1241 raise_revlog_error();
1164 1242 return NULL;
1165 1243 }
1166 1244
1167 1245 static int nt_partialmatch(indexObject *self, const char *node,
1168 1246 Py_ssize_t nodelen)
1169 1247 {
1170 1248 int rev;
1171 1249
1172 1250 if (nt_init(self) == -1)
1173 1251 return -3;
1174 1252
1175 1253 if (self->ntrev > 0) {
1176 1254 /* ensure that the radix tree is fully populated */
1177 1255 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1178 1256 const char *n = index_node(self, rev);
1179 1257 if (n == NULL)
1180 1258 return -2;
1181 1259 if (nt_insert(self, n, rev) == -1)
1182 1260 return -3;
1183 1261 }
1184 1262 self->ntrev = rev;
1185 1263 }
1186 1264
1187 1265 return nt_find(self, node, nodelen, 1);
1188 1266 }
1189 1267
1190 1268 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1191 1269 {
1192 1270 const char *fullnode;
1193 1271 int nodelen;
1194 1272 char *node;
1195 1273 int rev, i;
1196 1274
1197 1275 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1198 1276 return NULL;
1199 1277
1200 1278 if (nodelen < 4) {
1201 1279 PyErr_SetString(PyExc_ValueError, "key too short");
1202 1280 return NULL;
1203 1281 }
1204 1282
1205 1283 if (nodelen > 40) {
1206 1284 PyErr_SetString(PyExc_ValueError, "key too long");
1207 1285 return NULL;
1208 1286 }
1209 1287
1210 1288 for (i = 0; i < nodelen; i++)
1211 1289 hexdigit(node, i);
1212 1290 if (PyErr_Occurred()) {
1213 1291 /* input contains non-hex characters */
1214 1292 PyErr_Clear();
1215 1293 Py_RETURN_NONE;
1216 1294 }
1217 1295
1218 1296 rev = nt_partialmatch(self, node, nodelen);
1219 1297
1220 1298 switch (rev) {
1221 1299 case -4:
1222 1300 raise_revlog_error();
1223 1301 case -3:
1224 1302 return NULL;
1225 1303 case -2:
1226 1304 Py_RETURN_NONE;
1227 1305 case -1:
1228 1306 return PyString_FromStringAndSize(nullid, 20);
1229 1307 }
1230 1308
1231 1309 fullnode = index_node(self, rev);
1232 1310 if (fullnode == NULL) {
1233 1311 PyErr_Format(PyExc_IndexError,
1234 1312 "could not access rev %d", rev);
1235 1313 return NULL;
1236 1314 }
1237 1315 return PyString_FromStringAndSize(fullnode, 20);
1238 1316 }
1239 1317
1240 1318 static PyObject *index_m_get(indexObject *self, PyObject *args)
1241 1319 {
1242 1320 Py_ssize_t nodelen;
1243 1321 PyObject *val;
1244 1322 char *node;
1245 1323 int rev;
1246 1324
1247 1325 if (!PyArg_ParseTuple(args, "O", &val))
1248 1326 return NULL;
1249 1327 if (node_check(val, &node, &nodelen) == -1)
1250 1328 return NULL;
1251 1329 rev = index_find_node(self, node, nodelen);
1252 1330 if (rev == -3)
1253 1331 return NULL;
1254 1332 if (rev == -2)
1255 1333 Py_RETURN_NONE;
1256 1334 return PyInt_FromLong(rev);
1257 1335 }
1258 1336
1259 1337 static int index_contains(indexObject *self, PyObject *value)
1260 1338 {
1261 1339 char *node;
1262 1340 Py_ssize_t nodelen;
1263 1341
1264 1342 if (PyInt_Check(value)) {
1265 1343 long rev = PyInt_AS_LONG(value);
1266 1344 return rev >= -1 && rev < index_length(self);
1267 1345 }
1268 1346
1269 1347 if (node_check(value, &node, &nodelen) == -1)
1270 1348 return -1;
1271 1349
1272 1350 switch (index_find_node(self, node, nodelen)) {
1273 1351 case -3:
1274 1352 return -1;
1275 1353 case -2:
1276 1354 return 0;
1277 1355 default:
1278 1356 return 1;
1279 1357 }
1280 1358 }
1281 1359
1282 1360 static inline void index_get_parents(indexObject *self, int rev, int *ps)
1283 1361 {
1284 1362 if (rev >= self->length - 1) {
1285 1363 PyObject *tuple = PyList_GET_ITEM(self->added,
1286 1364 rev - self->length + 1);
1287 1365 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
1288 1366 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
1289 1367 } else {
1290 1368 const char *data = index_deref(self, rev);
1291 1369 ps[0] = getbe32(data + 24);
1292 1370 ps[1] = getbe32(data + 28);
1293 1371 }
1294 1372 }
1295 1373
1296 1374 typedef uint64_t bitmask;
1297 1375
1298 1376 /*
1299 1377 * Given a disjoint set of revs, return all candidates for the
1300 1378 * greatest common ancestor. In revset notation, this is the set
1301 1379 * "heads(::a and ::b and ...)"
1302 1380 */
1303 1381 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1304 1382 int revcount)
1305 1383 {
1306 1384 const bitmask allseen = (1ull << revcount) - 1;
1307 1385 const bitmask poison = 1ull << revcount;
1308 1386 PyObject *gca = PyList_New(0);
1309 1387 int i, v, interesting;
1310 1388 int maxrev = -1;
1311 1389 bitmask sp;
1312 1390 bitmask *seen;
1313 1391
1314 1392 if (gca == NULL)
1315 1393 return PyErr_NoMemory();
1316 1394
1317 1395 for (i = 0; i < revcount; i++) {
1318 1396 if (revs[i] > maxrev)
1319 1397 maxrev = revs[i];
1320 1398 }
1321 1399
1322 1400 seen = calloc(sizeof(*seen), maxrev + 1);
1323 1401 if (seen == NULL) {
1324 1402 Py_DECREF(gca);
1325 1403 return PyErr_NoMemory();
1326 1404 }
1327 1405
1328 1406 for (i = 0; i < revcount; i++)
1329 1407 seen[revs[i]] = 1ull << i;
1330 1408
1331 1409 interesting = revcount;
1332 1410
1333 1411 for (v = maxrev; v >= 0 && interesting; v--) {
1334 1412 bitmask sv = seen[v];
1335 1413 int parents[2];
1336 1414
1337 1415 if (!sv)
1338 1416 continue;
1339 1417
1340 1418 if (sv < poison) {
1341 1419 interesting -= 1;
1342 1420 if (sv == allseen) {
1343 1421 PyObject *obj = PyInt_FromLong(v);
1344 1422 if (obj == NULL)
1345 1423 goto bail;
1346 1424 if (PyList_Append(gca, obj) == -1) {
1347 1425 Py_DECREF(obj);
1348 1426 goto bail;
1349 1427 }
1350 1428 sv |= poison;
1351 1429 for (i = 0; i < revcount; i++) {
1352 1430 if (revs[i] == v)
1353 1431 goto done;
1354 1432 }
1355 1433 }
1356 1434 }
1357 1435 index_get_parents(self, v, parents);
1358 1436
1359 1437 for (i = 0; i < 2; i++) {
1360 1438 int p = parents[i];
1361 1439 if (p == -1)
1362 1440 continue;
1363 1441 sp = seen[p];
1364 1442 if (sv < poison) {
1365 1443 if (sp == 0) {
1366 1444 seen[p] = sv;
1367 1445 interesting++;
1368 1446 }
1369 1447 else if (sp != sv)
1370 1448 seen[p] |= sv;
1371 1449 } else {
1372 1450 if (sp && sp < poison)
1373 1451 interesting--;
1374 1452 seen[p] = sv;
1375 1453 }
1376 1454 }
1377 1455 }
1378 1456
1379 1457 done:
1380 1458 free(seen);
1381 1459 return gca;
1382 1460 bail:
1383 1461 free(seen);
1384 1462 Py_XDECREF(gca);
1385 1463 return NULL;
1386 1464 }
1387 1465
1388 1466 /*
1389 1467 * Given a disjoint set of revs, return the subset with the longest
1390 1468 * path to the root.
1391 1469 */
1392 1470 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1393 1471 {
1394 1472 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1395 1473 static const Py_ssize_t capacity = 24;
1396 1474 int *depth, *interesting = NULL;
1397 1475 int i, j, v, ninteresting;
1398 1476 PyObject *dict = NULL, *keys = NULL;
1399 1477 long *seen = NULL;
1400 1478 int maxrev = -1;
1401 1479 long final;
1402 1480
1403 1481 if (revcount > capacity) {
1404 1482 PyErr_Format(PyExc_OverflowError,
1405 1483 "bitset size (%ld) > capacity (%ld)",
1406 1484 (long)revcount, (long)capacity);
1407 1485 return NULL;
1408 1486 }
1409 1487
1410 1488 for (i = 0; i < revcount; i++) {
1411 1489 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1412 1490 if (n > maxrev)
1413 1491 maxrev = n;
1414 1492 }
1415 1493
1416 1494 depth = calloc(sizeof(*depth), maxrev + 1);
1417 1495 if (depth == NULL)
1418 1496 return PyErr_NoMemory();
1419 1497
1420 1498 seen = calloc(sizeof(*seen), maxrev + 1);
1421 1499 if (seen == NULL) {
1422 1500 PyErr_NoMemory();
1423 1501 goto bail;
1424 1502 }
1425 1503
1426 1504 interesting = calloc(sizeof(*interesting), 2 << revcount);
1427 1505 if (interesting == NULL) {
1428 1506 PyErr_NoMemory();
1429 1507 goto bail;
1430 1508 }
1431 1509
1432 1510 if (PyList_Sort(revs) == -1)
1433 1511 goto bail;
1434 1512
1435 1513 for (i = 0; i < revcount; i++) {
1436 1514 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1437 1515 long b = 1l << i;
1438 1516 depth[n] = 1;
1439 1517 seen[n] = b;
1440 1518 interesting[b] = 1;
1441 1519 }
1442 1520
1443 1521 ninteresting = (int)revcount;
1444 1522
1445 1523 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1446 1524 int dv = depth[v];
1447 1525 int parents[2];
1448 1526 long sv;
1449 1527
1450 1528 if (dv == 0)
1451 1529 continue;
1452 1530
1453 1531 sv = seen[v];
1454 1532 index_get_parents(self, v, parents);
1455 1533
1456 1534 for (i = 0; i < 2; i++) {
1457 1535 int p = parents[i];
1458 1536 long nsp, sp;
1459 1537 int dp;
1460 1538
1461 1539 if (p == -1)
1462 1540 continue;
1463 1541
1464 1542 dp = depth[p];
1465 1543 nsp = sp = seen[p];
1466 1544 if (dp <= dv) {
1467 1545 depth[p] = dv + 1;
1468 1546 if (sp != sv) {
1469 1547 interesting[sv] += 1;
1470 1548 nsp = seen[p] = sv;
1471 1549 if (sp) {
1472 1550 interesting[sp] -= 1;
1473 1551 if (interesting[sp] == 0)
1474 1552 ninteresting -= 1;
1475 1553 }
1476 1554 }
1477 1555 }
1478 1556 else if (dv == dp - 1) {
1479 1557 nsp = sp | sv;
1480 1558 if (nsp == sp)
1481 1559 continue;
1482 1560 seen[p] = nsp;
1483 1561 interesting[sp] -= 1;
1484 1562 if (interesting[sp] == 0 && interesting[nsp] > 0)
1485 1563 ninteresting -= 1;
1486 1564 interesting[nsp] += 1;
1487 1565 }
1488 1566 }
1489 1567 interesting[sv] -= 1;
1490 1568 if (interesting[sv] == 0)
1491 1569 ninteresting -= 1;
1492 1570 }
1493 1571
1494 1572 final = 0;
1495 1573 j = ninteresting;
1496 1574 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1497 1575 if (interesting[i] == 0)
1498 1576 continue;
1499 1577 final |= i;
1500 1578 j -= 1;
1501 1579 }
1502 1580 if (final == 0) {
1503 1581 keys = PyList_New(0);
1504 1582 goto bail;
1505 1583 }
1506 1584
1507 1585 dict = PyDict_New();
1508 1586 if (dict == NULL)
1509 1587 goto bail;
1510 1588
1511 1589 for (i = 0; i < revcount; i++) {
1512 1590 PyObject *key;
1513 1591
1514 1592 if ((final & (1 << i)) == 0)
1515 1593 continue;
1516 1594
1517 1595 key = PyList_GET_ITEM(revs, i);
1518 1596 Py_INCREF(key);
1519 1597 Py_INCREF(Py_None);
1520 1598 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1521 1599 Py_DECREF(key);
1522 1600 Py_DECREF(Py_None);
1523 1601 goto bail;
1524 1602 }
1525 1603 }
1526 1604
1527 1605 keys = PyDict_Keys(dict);
1528 1606
1529 1607 bail:
1530 1608 free(depth);
1531 1609 free(seen);
1532 1610 free(interesting);
1533 1611 Py_XDECREF(dict);
1534 1612
1535 1613 return keys;
1536 1614 }
1537 1615
1538 1616 /*
1539 1617 * Given a (possibly overlapping) set of revs, return the greatest
1540 1618 * common ancestors: those with the longest path to the root.
1541 1619 */
1542 1620 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1543 1621 {
1544 1622 PyObject *ret = NULL, *gca = NULL;
1545 1623 Py_ssize_t argcount, i, len;
1546 1624 bitmask repeat = 0;
1547 1625 int revcount = 0;
1548 1626 int *revs;
1549 1627
1550 1628 argcount = PySequence_Length(args);
1551 1629 revs = malloc(argcount * sizeof(*revs));
1552 1630 if (argcount > 0 && revs == NULL)
1553 1631 return PyErr_NoMemory();
1554 1632 len = index_length(self) - 1;
1555 1633
1556 1634 for (i = 0; i < argcount; i++) {
1557 1635 static const int capacity = 24;
1558 1636 PyObject *obj = PySequence_GetItem(args, i);
1559 1637 bitmask x;
1560 1638 long val;
1561 1639
1562 1640 if (!PyInt_Check(obj)) {
1563 1641 PyErr_SetString(PyExc_TypeError,
1564 1642 "arguments must all be ints");
1565 1643 goto bail;
1566 1644 }
1567 1645 val = PyInt_AsLong(obj);
1568 1646 if (val == -1) {
1569 1647 ret = PyList_New(0);
1570 1648 goto done;
1571 1649 }
1572 1650 if (val < 0 || val >= len) {
1573 1651 PyErr_SetString(PyExc_IndexError,
1574 1652 "index out of range");
1575 1653 goto bail;
1576 1654 }
1577 1655 /* this cheesy bloom filter lets us avoid some more
1578 1656 * expensive duplicate checks in the common set-is-disjoint
1579 1657 * case */
1580 1658 x = 1ull << (val & 0x3f);
1581 1659 if (repeat & x) {
1582 1660 int k;
1583 1661 for (k = 0; k < revcount; k++) {
1584 1662 if (val == revs[k])
1585 1663 goto duplicate;
1586 1664 }
1587 1665 }
1588 1666 else repeat |= x;
1589 1667 if (revcount >= capacity) {
1590 1668 PyErr_Format(PyExc_OverflowError,
1591 1669 "bitset size (%d) > capacity (%d)",
1592 1670 revcount, capacity);
1593 1671 goto bail;
1594 1672 }
1595 1673 revs[revcount++] = (int)val;
1596 1674 duplicate:;
1597 1675 }
1598 1676
1599 1677 if (revcount == 0) {
1600 1678 ret = PyList_New(0);
1601 1679 goto done;
1602 1680 }
1603 1681 if (revcount == 1) {
1604 1682 PyObject *obj;
1605 1683 ret = PyList_New(1);
1606 1684 if (ret == NULL)
1607 1685 goto bail;
1608 1686 obj = PyInt_FromLong(revs[0]);
1609 1687 if (obj == NULL)
1610 1688 goto bail;
1611 1689 PyList_SET_ITEM(ret, 0, obj);
1612 1690 goto done;
1613 1691 }
1614 1692
1615 1693 gca = find_gca_candidates(self, revs, revcount);
1616 1694 if (gca == NULL)
1617 1695 goto bail;
1618 1696
1619 1697 if (PyList_GET_SIZE(gca) <= 1) {
1620 1698 ret = gca;
1621 1699 Py_INCREF(gca);
1622 1700 }
1623 1701 else ret = find_deepest(self, gca);
1624 1702
1625 1703 done:
1626 1704 free(revs);
1627 1705 Py_XDECREF(gca);
1628 1706
1629 1707 return ret;
1630 1708
1631 1709 bail:
1632 1710 free(revs);
1633 1711 Py_XDECREF(gca);
1634 1712 Py_XDECREF(ret);
1635 1713 return NULL;
1636 1714 }
1637 1715
1638 1716 /*
1639 1717 * Given a (possibly overlapping) set of revs, return all the
1640 1718 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1641 1719 */
1642 1720 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1643 1721 {
1644 1722 PyObject *ret = NULL;
1645 1723 Py_ssize_t argcount, i, len;
1646 1724 bitmask repeat = 0;
1647 1725 int revcount = 0;
1648 1726 int *revs;
1649 1727
1650 1728 argcount = PySequence_Length(args);
1651 1729 revs = malloc(argcount * sizeof(*revs));
1652 1730 if (argcount > 0 && revs == NULL)
1653 1731 return PyErr_NoMemory();
1654 1732 len = index_length(self) - 1;
1655 1733
1656 1734 for (i = 0; i < argcount; i++) {
1657 1735 static const int capacity = 24;
1658 1736 PyObject *obj = PySequence_GetItem(args, i);
1659 1737 bitmask x;
1660 1738 long val;
1661 1739
1662 1740 if (!PyInt_Check(obj)) {
1663 1741 PyErr_SetString(PyExc_TypeError,
1664 1742 "arguments must all be ints");
1665 1743 goto bail;
1666 1744 }
1667 1745 val = PyInt_AsLong(obj);
1668 1746 if (val == -1) {
1669 1747 ret = PyList_New(0);
1670 1748 goto done;
1671 1749 }
1672 1750 if (val < 0 || val >= len) {
1673 1751 PyErr_SetString(PyExc_IndexError,
1674 1752 "index out of range");
1675 1753 goto bail;
1676 1754 }
1677 1755 /* this cheesy bloom filter lets us avoid some more
1678 1756 * expensive duplicate checks in the common set-is-disjoint
1679 1757 * case */
1680 1758 x = 1ull << (val & 0x3f);
1681 1759 if (repeat & x) {
1682 1760 int k;
1683 1761 for (k = 0; k < revcount; k++) {
1684 1762 if (val == revs[k])
1685 1763 goto duplicate;
1686 1764 }
1687 1765 }
1688 1766 else repeat |= x;
1689 1767 if (revcount >= capacity) {
1690 1768 PyErr_Format(PyExc_OverflowError,
1691 1769 "bitset size (%d) > capacity (%d)",
1692 1770 revcount, capacity);
1693 1771 goto bail;
1694 1772 }
1695 1773 revs[revcount++] = (int)val;
1696 1774 duplicate:;
1697 1775 }
1698 1776
1699 1777 if (revcount == 0) {
1700 1778 ret = PyList_New(0);
1701 1779 goto done;
1702 1780 }
1703 1781 if (revcount == 1) {
1704 1782 PyObject *obj;
1705 1783 ret = PyList_New(1);
1706 1784 if (ret == NULL)
1707 1785 goto bail;
1708 1786 obj = PyInt_FromLong(revs[0]);
1709 1787 if (obj == NULL)
1710 1788 goto bail;
1711 1789 PyList_SET_ITEM(ret, 0, obj);
1712 1790 goto done;
1713 1791 }
1714 1792
1715 1793 ret = find_gca_candidates(self, revs, revcount);
1716 1794 if (ret == NULL)
1717 1795 goto bail;
1718 1796
1719 1797 done:
1720 1798 free(revs);
1721 1799 return ret;
1722 1800
1723 1801 bail:
1724 1802 free(revs);
1725 1803 Py_XDECREF(ret);
1726 1804 return NULL;
1727 1805 }
1728 1806
1729 1807 /*
1730 1808 * Invalidate any trie entries introduced by added revs.
1731 1809 */
1732 1810 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1733 1811 {
1734 1812 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1735 1813
1736 1814 for (i = start; i < len; i++) {
1737 1815 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1738 1816 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1739 1817
1740 1818 nt_insert(self, PyString_AS_STRING(node), -1);
1741 1819 }
1742 1820
1743 1821 if (start == 0)
1744 1822 Py_CLEAR(self->added);
1745 1823 }
1746 1824
1747 1825 /*
1748 1826 * Delete a numeric range of revs, which must be at the end of the
1749 1827 * range, but exclude the sentinel nullid entry.
1750 1828 */
1751 1829 static int index_slice_del(indexObject *self, PyObject *item)
1752 1830 {
1753 1831 Py_ssize_t start, stop, step, slicelength;
1754 1832 Py_ssize_t length = index_length(self);
1755 1833 int ret = 0;
1756 1834
1757 1835 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1758 1836 &start, &stop, &step, &slicelength) < 0)
1759 1837 return -1;
1760 1838
1761 1839 if (slicelength <= 0)
1762 1840 return 0;
1763 1841
1764 1842 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1765 1843 stop = start;
1766 1844
1767 1845 if (step < 0) {
1768 1846 stop = start + 1;
1769 1847 start = stop + step*(slicelength - 1) - 1;
1770 1848 step = -step;
1771 1849 }
1772 1850
1773 1851 if (step != 1) {
1774 1852 PyErr_SetString(PyExc_ValueError,
1775 1853 "revlog index delete requires step size of 1");
1776 1854 return -1;
1777 1855 }
1778 1856
1779 1857 if (stop != length - 1) {
1780 1858 PyErr_SetString(PyExc_IndexError,
1781 1859 "revlog index deletion indices are invalid");
1782 1860 return -1;
1783 1861 }
1784 1862
1785 1863 if (start < self->length - 1) {
1786 1864 if (self->nt) {
1787 1865 Py_ssize_t i;
1788 1866
1789 1867 for (i = start + 1; i < self->length - 1; i++) {
1790 1868 const char *node = index_node(self, i);
1791 1869
1792 1870 if (node)
1793 1871 nt_insert(self, node, -1);
1794 1872 }
1795 1873 if (self->added)
1796 1874 nt_invalidate_added(self, 0);
1797 1875 if (self->ntrev > start)
1798 1876 self->ntrev = (int)start;
1799 1877 }
1800 1878 self->length = start + 1;
1801 1879 if (start < self->raw_length) {
1802 1880 if (self->cache) {
1803 1881 Py_ssize_t i;
1804 1882 for (i = start; i < self->raw_length; i++)
1805 1883 Py_CLEAR(self->cache[i]);
1806 1884 }
1807 1885 self->raw_length = start;
1808 1886 }
1809 1887 goto done;
1810 1888 }
1811 1889
1812 1890 if (self->nt) {
1813 1891 nt_invalidate_added(self, start - self->length + 1);
1814 1892 if (self->ntrev > start)
1815 1893 self->ntrev = (int)start;
1816 1894 }
1817 1895 if (self->added)
1818 1896 ret = PyList_SetSlice(self->added, start - self->length + 1,
1819 1897 PyList_GET_SIZE(self->added), NULL);
1820 1898 done:
1821 1899 Py_CLEAR(self->headrevs);
1822 1900 return ret;
1823 1901 }
1824 1902
1825 1903 /*
1826 1904 * Supported ops:
1827 1905 *
1828 1906 * slice deletion
1829 1907 * string assignment (extend node->rev mapping)
1830 1908 * string deletion (shrink node->rev mapping)
1831 1909 */
1832 1910 static int index_assign_subscript(indexObject *self, PyObject *item,
1833 1911 PyObject *value)
1834 1912 {
1835 1913 char *node;
1836 1914 Py_ssize_t nodelen;
1837 1915 long rev;
1838 1916
1839 1917 if (PySlice_Check(item) && value == NULL)
1840 1918 return index_slice_del(self, item);
1841 1919
1842 1920 if (node_check(item, &node, &nodelen) == -1)
1843 1921 return -1;
1844 1922
1845 1923 if (value == NULL)
1846 1924 return self->nt ? nt_insert(self, node, -1) : 0;
1847 1925 rev = PyInt_AsLong(value);
1848 1926 if (rev > INT_MAX || rev < 0) {
1849 1927 if (!PyErr_Occurred())
1850 1928 PyErr_SetString(PyExc_ValueError, "rev out of range");
1851 1929 return -1;
1852 1930 }
1853 1931 return nt_insert(self, node, (int)rev);
1854 1932 }
1855 1933
1856 1934 /*
1857 1935 * Find all RevlogNG entries in an index that has inline data. Update
1858 1936 * the optional "offsets" table with those entries.
1859 1937 */
1860 1938 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
1861 1939 {
1862 1940 const char *data = PyString_AS_STRING(self->data);
1863 1941 Py_ssize_t pos = 0;
1864 1942 Py_ssize_t end = PyString_GET_SIZE(self->data);
1865 1943 long incr = v1_hdrsize;
1866 1944 Py_ssize_t len = 0;
1867 1945
1868 1946 while (pos + v1_hdrsize <= end && pos >= 0) {
1869 1947 uint32_t comp_len;
1870 1948 /* 3rd element of header is length of compressed inline data */
1871 1949 comp_len = getbe32(data + pos + 8);
1872 1950 incr = v1_hdrsize + comp_len;
1873 1951 if (offsets)
1874 1952 offsets[len] = data + pos;
1875 1953 len++;
1876 1954 pos += incr;
1877 1955 }
1878 1956
1879 1957 if (pos != end) {
1880 1958 if (!PyErr_Occurred())
1881 1959 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1882 1960 return -1;
1883 1961 }
1884 1962
1885 1963 return len;
1886 1964 }
1887 1965
1888 1966 static int index_init(indexObject *self, PyObject *args)
1889 1967 {
1890 1968 PyObject *data_obj, *inlined_obj;
1891 1969 Py_ssize_t size;
1892 1970
1893 1971 /* Initialize before argument-checking to avoid index_dealloc() crash. */
1894 1972 self->raw_length = 0;
1895 1973 self->added = NULL;
1896 1974 self->cache = NULL;
1897 1975 self->data = NULL;
1898 1976 self->headrevs = NULL;
1977 self->filteredrevs = Py_None;
1978 Py_INCREF(Py_None);
1899 1979 self->nt = NULL;
1900 1980 self->offsets = NULL;
1901 1981
1902 1982 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
1903 1983 return -1;
1904 1984 if (!PyString_Check(data_obj)) {
1905 1985 PyErr_SetString(PyExc_TypeError, "data is not a string");
1906 1986 return -1;
1907 1987 }
1908 1988 size = PyString_GET_SIZE(data_obj);
1909 1989
1910 1990 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
1911 1991 self->data = data_obj;
1912 1992
1913 1993 self->ntlength = self->ntcapacity = 0;
1914 1994 self->ntdepth = self->ntsplits = 0;
1915 1995 self->ntlookups = self->ntmisses = 0;
1916 1996 self->ntrev = -1;
1917 1997 Py_INCREF(self->data);
1918 1998
1919 1999 if (self->inlined) {
1920 2000 Py_ssize_t len = inline_scan(self, NULL);
1921 2001 if (len == -1)
1922 2002 goto bail;
1923 2003 self->raw_length = len;
1924 2004 self->length = len + 1;
1925 2005 } else {
1926 2006 if (size % v1_hdrsize) {
1927 2007 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1928 2008 goto bail;
1929 2009 }
1930 2010 self->raw_length = size / v1_hdrsize;
1931 2011 self->length = self->raw_length + 1;
1932 2012 }
1933 2013
1934 2014 return 0;
1935 2015 bail:
1936 2016 return -1;
1937 2017 }
1938 2018
1939 2019 static PyObject *index_nodemap(indexObject *self)
1940 2020 {
1941 2021 Py_INCREF(self);
1942 2022 return (PyObject *)self;
1943 2023 }
1944 2024
1945 2025 static void index_dealloc(indexObject *self)
1946 2026 {
1947 2027 _index_clearcaches(self);
2028 Py_XDECREF(self->filteredrevs);
1948 2029 Py_XDECREF(self->data);
1949 2030 Py_XDECREF(self->added);
1950 2031 PyObject_Del(self);
1951 2032 }
1952 2033
1953 2034 static PySequenceMethods index_sequence_methods = {
1954 2035 (lenfunc)index_length, /* sq_length */
1955 2036 0, /* sq_concat */
1956 2037 0, /* sq_repeat */
1957 2038 (ssizeargfunc)index_get, /* sq_item */
1958 2039 0, /* sq_slice */
1959 2040 0, /* sq_ass_item */
1960 2041 0, /* sq_ass_slice */
1961 2042 (objobjproc)index_contains, /* sq_contains */
1962 2043 };
1963 2044
1964 2045 static PyMappingMethods index_mapping_methods = {
1965 2046 (lenfunc)index_length, /* mp_length */
1966 2047 (binaryfunc)index_getitem, /* mp_subscript */
1967 2048 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
1968 2049 };
1969 2050
1970 2051 static PyMethodDef index_methods[] = {
1971 2052 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
1972 2053 "return the gca set of the given revs"},
1973 2054 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
1974 2055 METH_VARARGS,
1975 2056 "return the heads of the common ancestors of the given revs"},
1976 2057 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
1977 2058 "clear the index caches"},
1978 2059 {"get", (PyCFunction)index_m_get, METH_VARARGS,
1979 2060 "get an index entry"},
1980 {"headrevs", (PyCFunction)index_headrevs, METH_NOARGS,
2061 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
1981 2062 "get head revisions"},
1982 2063 {"insert", (PyCFunction)index_insert, METH_VARARGS,
1983 2064 "insert an index entry"},
1984 2065 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
1985 2066 "match a potentially ambiguous node ID"},
1986 2067 {"stats", (PyCFunction)index_stats, METH_NOARGS,
1987 2068 "stats for the index"},
1988 2069 {NULL} /* Sentinel */
1989 2070 };
1990 2071
1991 2072 static PyGetSetDef index_getset[] = {
1992 2073 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
1993 2074 {NULL} /* Sentinel */
1994 2075 };
1995 2076
1996 2077 static PyTypeObject indexType = {
1997 2078 PyObject_HEAD_INIT(NULL)
1998 2079 0, /* ob_size */
1999 2080 "parsers.index", /* tp_name */
2000 2081 sizeof(indexObject), /* tp_basicsize */
2001 2082 0, /* tp_itemsize */
2002 2083 (destructor)index_dealloc, /* tp_dealloc */
2003 2084 0, /* tp_print */
2004 2085 0, /* tp_getattr */
2005 2086 0, /* tp_setattr */
2006 2087 0, /* tp_compare */
2007 2088 0, /* tp_repr */
2008 2089 0, /* tp_as_number */
2009 2090 &index_sequence_methods, /* tp_as_sequence */
2010 2091 &index_mapping_methods, /* tp_as_mapping */
2011 2092 0, /* tp_hash */
2012 2093 0, /* tp_call */
2013 2094 0, /* tp_str */
2014 2095 0, /* tp_getattro */
2015 2096 0, /* tp_setattro */
2016 2097 0, /* tp_as_buffer */
2017 2098 Py_TPFLAGS_DEFAULT, /* tp_flags */
2018 2099 "revlog index", /* tp_doc */
2019 2100 0, /* tp_traverse */
2020 2101 0, /* tp_clear */
2021 2102 0, /* tp_richcompare */
2022 2103 0, /* tp_weaklistoffset */
2023 2104 0, /* tp_iter */
2024 2105 0, /* tp_iternext */
2025 2106 index_methods, /* tp_methods */
2026 2107 0, /* tp_members */
2027 2108 index_getset, /* tp_getset */
2028 2109 0, /* tp_base */
2029 2110 0, /* tp_dict */
2030 2111 0, /* tp_descr_get */
2031 2112 0, /* tp_descr_set */
2032 2113 0, /* tp_dictoffset */
2033 2114 (initproc)index_init, /* tp_init */
2034 2115 0, /* tp_alloc */
2035 2116 };
2036 2117
2037 2118 /*
2038 2119 * returns a tuple of the form (index, index, cache) with elements as
2039 2120 * follows:
2040 2121 *
2041 2122 * index: an index object that lazily parses RevlogNG records
2042 2123 * cache: if data is inlined, a tuple (index_file_content, 0), else None
2043 2124 *
2044 2125 * added complications are for backwards compatibility
2045 2126 */
2046 2127 static PyObject *parse_index2(PyObject *self, PyObject *args)
2047 2128 {
2048 2129 PyObject *tuple = NULL, *cache = NULL;
2049 2130 indexObject *idx;
2050 2131 int ret;
2051 2132
2052 2133 idx = PyObject_New(indexObject, &indexType);
2053 2134 if (idx == NULL)
2054 2135 goto bail;
2055 2136
2056 2137 ret = index_init(idx, args);
2057 2138 if (ret == -1)
2058 2139 goto bail;
2059 2140
2060 2141 if (idx->inlined) {
2061 2142 cache = Py_BuildValue("iO", 0, idx->data);
2062 2143 if (cache == NULL)
2063 2144 goto bail;
2064 2145 } else {
2065 2146 cache = Py_None;
2066 2147 Py_INCREF(cache);
2067 2148 }
2068 2149
2069 2150 tuple = Py_BuildValue("NN", idx, cache);
2070 2151 if (!tuple)
2071 2152 goto bail;
2072 2153 return tuple;
2073 2154
2074 2155 bail:
2075 2156 Py_XDECREF(idx);
2076 2157 Py_XDECREF(cache);
2077 2158 Py_XDECREF(tuple);
2078 2159 return NULL;
2079 2160 }
2080 2161
2081 2162 static char parsers_doc[] = "Efficient content parsing.";
2082 2163
2083 2164 PyObject *encodedir(PyObject *self, PyObject *args);
2084 2165 PyObject *pathencode(PyObject *self, PyObject *args);
2085 2166 PyObject *lowerencode(PyObject *self, PyObject *args);
2086 2167
2087 2168 static PyMethodDef methods[] = {
2088 2169 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
2089 2170 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
2090 2171 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
2091 2172 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
2092 2173 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
2093 2174 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
2094 2175 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
2095 2176 {NULL, NULL}
2096 2177 };
2097 2178
2098 2179 void dirs_module_init(PyObject *mod);
2099 2180
2100 2181 static void module_init(PyObject *mod)
2101 2182 {
2102 2183 /* This module constant has two purposes. First, it lets us unit test
2103 2184 * the ImportError raised without hard-coding any error text. This
2104 2185 * means we can change the text in the future without breaking tests,
2105 2186 * even across changesets without a recompile. Second, its presence
2106 2187 * can be used to determine whether the version-checking logic is
2107 2188 * present, which also helps in testing across changesets without a
2108 2189 * recompile. Note that this means the pure-Python version of parsers
2109 2190 * should not have this module constant. */
2110 2191 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
2111 2192
2112 2193 dirs_module_init(mod);
2113 2194
2114 2195 indexType.tp_new = PyType_GenericNew;
2115 2196 if (PyType_Ready(&indexType) < 0 ||
2116 2197 PyType_Ready(&dirstateTupleType) < 0)
2117 2198 return;
2118 2199 Py_INCREF(&indexType);
2119 2200 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2120 2201 Py_INCREF(&dirstateTupleType);
2121 2202 PyModule_AddObject(mod, "dirstatetuple",
2122 2203 (PyObject *)&dirstateTupleType);
2123 2204
2124 2205 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
2125 2206 -1, -1, -1, -1, nullid, 20);
2126 2207 if (nullentry)
2127 2208 PyObject_GC_UnTrack(nullentry);
2128 2209 }
2129 2210
2130 2211 static int check_python_version(void)
2131 2212 {
2132 2213 PyObject *sys = PyImport_ImportModule("sys");
2133 2214 long hexversion = PyInt_AsLong(PyObject_GetAttrString(sys, "hexversion"));
2134 2215 /* sys.hexversion is a 32-bit number by default, so the -1 case
2135 2216 * should only occur in unusual circumstances (e.g. if sys.hexversion
2136 2217 * is manually set to an invalid value). */
2137 2218 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
2138 2219 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
2139 2220 "modules were compiled with Python " PY_VERSION ", but "
2140 2221 "Mercurial is currently using Python with sys.hexversion=%ld: "
2141 2222 "Python %s\n at: %s", versionerrortext, hexversion,
2142 2223 Py_GetVersion(), Py_GetProgramFullPath());
2143 2224 return -1;
2144 2225 }
2145 2226 return 0;
2146 2227 }
2147 2228
2148 2229 #ifdef IS_PY3K
2149 2230 static struct PyModuleDef parsers_module = {
2150 2231 PyModuleDef_HEAD_INIT,
2151 2232 "parsers",
2152 2233 parsers_doc,
2153 2234 -1,
2154 2235 methods
2155 2236 };
2156 2237
2157 2238 PyMODINIT_FUNC PyInit_parsers(void)
2158 2239 {
2159 2240 PyObject *mod;
2160 2241
2161 2242 if (check_python_version() == -1)
2162 2243 return;
2163 2244 mod = PyModule_Create(&parsers_module);
2164 2245 module_init(mod);
2165 2246 return mod;
2166 2247 }
2167 2248 #else
2168 2249 PyMODINIT_FUNC initparsers(void)
2169 2250 {
2170 2251 PyObject *mod;
2171 2252
2172 2253 if (check_python_version() == -1)
2173 2254 return;
2174 2255 mod = Py_InitModule3("parsers", methods, parsers_doc);
2175 2256 module_init(mod);
2176 2257 }
2177 2258 #endif
General Comments 0
You need to be logged in to leave comments. Login now