Show More
@@ -0,0 +1,227 b'' | |||
|
1 | // dirstate.rs | |
|
2 | // | |
|
3 | // Copyright 2019 Raphaël Gomès <rgomes@octobus.net> | |
|
4 | // | |
|
5 | // This software may be used and distributed according to the terms of the | |
|
6 | // GNU General Public License version 2 or any later version. | |
|
7 | ||
|
8 | //! Bindings for the `hg::dirstate` module provided by the | |
|
9 | //! `hg-core` package. | |
|
10 | //! | |
|
11 | //! From Python, this will be seen as `mercurial.rustext.dirstate` | |
|
12 | ||
|
13 | use cpython::{ | |
|
14 | exc, PyBytes, PyDict, PyErr, PyInt, PyModule, PyObject, PyResult, | |
|
15 | PySequence, PyTuple, Python, ToPyObject, | |
|
16 | }; | |
|
17 | use hg::{ | |
|
18 | pack_dirstate, parse_dirstate, CopyVecEntry, DirstateEntry, | |
|
19 | DirstatePackError, DirstateParents, DirstateParseError, DirstateVec, | |
|
20 | }; | |
|
21 | use std::collections::HashMap; | |
|
22 | use std::ffi::CStr; | |
|
23 | #[cfg(feature = "python27")] | |
|
24 | extern crate python27_sys as python_sys; | |
|
25 | #[cfg(feature = "python3")] | |
|
26 | extern crate python3_sys as python_sys; | |
|
27 | use self::python_sys::PyCapsule_Import; | |
|
28 | use libc::{c_char, c_int}; | |
|
29 | use std::mem::transmute; | |
|
30 | ||
|
31 | /// C code uses a custom `dirstate_tuple` type, checks in multiple instances | |
|
32 | /// for this type, and raises a Python `Exception` if the check does not pass. | |
|
33 | /// Because this type differs only in name from the regular Python tuple, it | |
|
34 | /// would be a good idea in the near future to remove it entirely to allow | |
|
35 | /// for a pure Python tuple of the same effective structure to be used, | |
|
36 | /// rendering this type and the capsule below useless. | |
|
37 | type MakeDirstateTupleFn = extern "C" fn( | |
|
38 | state: c_char, | |
|
39 | mode: c_int, | |
|
40 | size: c_int, | |
|
41 | mtime: c_int, | |
|
42 | ) -> PyObject; | |
|
43 | ||
|
44 | /// This is largely a copy/paste from cindex.rs, pending the merge of a | |
|
45 | /// `py_capsule_fn!` macro in the rust-cpython project: | |
|
46 | /// https://github.com/dgrunwald/rust-cpython/pull/169 | |
|
47 | fn decapsule_make_dirstate_tuple(py: Python) -> PyResult<MakeDirstateTupleFn> { | |
|
48 | unsafe { | |
|
49 | let caps_name = CStr::from_bytes_with_nul_unchecked( | |
|
50 | b"mercurial.cext.parsers.make_dirstate_tuple_CAPI\0", | |
|
51 | ); | |
|
52 | let from_caps = PyCapsule_Import(caps_name.as_ptr(), 0); | |
|
53 | if from_caps.is_null() { | |
|
54 | return Err(PyErr::fetch(py)); | |
|
55 | } | |
|
56 | Ok(transmute(from_caps)) | |
|
57 | } | |
|
58 | } | |
|
59 | ||
|
60 | fn parse_dirstate_wrapper( | |
|
61 | py: Python, | |
|
62 | dmap: PyDict, | |
|
63 | copymap: PyDict, | |
|
64 | st: PyBytes, | |
|
65 | ) -> PyResult<PyTuple> { | |
|
66 | match parse_dirstate(st.data(py)) { | |
|
67 | Ok((parents, dirstate_vec, copies)) => { | |
|
68 | for (filename, entry) in dirstate_vec { | |
|
69 | dmap.set_item( | |
|
70 | py, | |
|
71 | PyBytes::new(py, &filename[..]), | |
|
72 | decapsule_make_dirstate_tuple(py)?( | |
|
73 | entry.state, | |
|
74 | entry.mode, | |
|
75 | entry.size, | |
|
76 | entry.mtime, | |
|
77 | ), | |
|
78 | )?; | |
|
79 | } | |
|
80 | for CopyVecEntry { path, copy_path } in copies { | |
|
81 | copymap.set_item( | |
|
82 | py, | |
|
83 | PyBytes::new(py, path), | |
|
84 | PyBytes::new(py, copy_path), | |
|
85 | )?; | |
|
86 | } | |
|
87 | Ok((PyBytes::new(py, parents.p1), PyBytes::new(py, parents.p2)) | |
|
88 | .to_py_object(py)) | |
|
89 | } | |
|
90 | Err(e) => Err(PyErr::new::<exc::ValueError, _>( | |
|
91 | py, | |
|
92 | match e { | |
|
93 | DirstateParseError::TooLittleData => { | |
|
94 | "too little data for parents".to_string() | |
|
95 | } | |
|
96 | DirstateParseError::Overflow => { | |
|
97 | "overflow in dirstate".to_string() | |
|
98 | } | |
|
99 | DirstateParseError::CorruptedEntry(e) => e, | |
|
100 | }, | |
|
101 | )), | |
|
102 | } | |
|
103 | } | |
|
104 | ||
|
105 | fn pack_dirstate_wrapper( | |
|
106 | py: Python, | |
|
107 | dmap: PyDict, | |
|
108 | copymap: PyDict, | |
|
109 | pl: PyTuple, | |
|
110 | now: PyInt, | |
|
111 | ) -> PyResult<PyBytes> { | |
|
112 | let p1 = pl.get_item(py, 0).extract::<PyBytes>(py)?; | |
|
113 | let p1: &[u8] = p1.data(py); | |
|
114 | let p2 = pl.get_item(py, 1).extract::<PyBytes>(py)?; | |
|
115 | let p2: &[u8] = p2.data(py); | |
|
116 | ||
|
117 | let dirstate_vec: Result<DirstateVec, PyErr> = dmap | |
|
118 | .items(py) | |
|
119 | .iter() | |
|
120 | .map(|(filename, stats)| { | |
|
121 | let stats = stats.extract::<PySequence>(py)?; | |
|
122 | let state = stats.get_item(py, 0)?.extract::<PyBytes>(py)?; | |
|
123 | let state = state.data(py)[0] as i8; | |
|
124 | let mode = stats.get_item(py, 1)?.extract(py)?; | |
|
125 | let size = stats.get_item(py, 2)?.extract(py)?; | |
|
126 | let mtime = stats.get_item(py, 3)?.extract(py)?; | |
|
127 | let filename = filename.extract::<PyBytes>(py)?; | |
|
128 | let filename = filename.data(py); | |
|
129 | Ok(( | |
|
130 | filename.to_owned(), | |
|
131 | DirstateEntry { | |
|
132 | state, | |
|
133 | mode, | |
|
134 | size, | |
|
135 | mtime, | |
|
136 | }, | |
|
137 | )) | |
|
138 | }) | |
|
139 | .collect(); | |
|
140 | ||
|
141 | let copies: Result<HashMap<Vec<u8>, Vec<u8>>, PyErr> = copymap | |
|
142 | .items(py) | |
|
143 | .iter() | |
|
144 | .map(|(key, value)| { | |
|
145 | Ok(( | |
|
146 | key.extract::<PyBytes>(py)?.data(py).to_owned(), | |
|
147 | value.extract::<PyBytes>(py)?.data(py).to_owned(), | |
|
148 | )) | |
|
149 | }) | |
|
150 | .collect(); | |
|
151 | ||
|
152 | match pack_dirstate( | |
|
153 | &dirstate_vec?, | |
|
154 | &copies?, | |
|
155 | DirstateParents { p1, p2 }, | |
|
156 | now.value(py) as i32, | |
|
157 | ) { | |
|
158 | Ok((packed, new_dirstate_vec)) => { | |
|
159 | for ( | |
|
160 | filename, | |
|
161 | DirstateEntry { | |
|
162 | state, | |
|
163 | mode, | |
|
164 | size, | |
|
165 | mtime, | |
|
166 | }, | |
|
167 | ) in new_dirstate_vec | |
|
168 | { | |
|
169 | dmap.set_item( | |
|
170 | py, | |
|
171 | PyBytes::new(py, &filename[..]), | |
|
172 | decapsule_make_dirstate_tuple(py)?( | |
|
173 | state, mode, size, mtime, | |
|
174 | ), | |
|
175 | )?; | |
|
176 | } | |
|
177 | Ok(PyBytes::new(py, &packed)) | |
|
178 | } | |
|
179 | Err(error) => Err(PyErr::new::<exc::ValueError, _>( | |
|
180 | py, | |
|
181 | match error { | |
|
182 | DirstatePackError::CorruptedParent => { | |
|
183 | "expected a 20-byte hash".to_string() | |
|
184 | } | |
|
185 | DirstatePackError::CorruptedEntry(e) => e, | |
|
186 | DirstatePackError::BadSize(expected, actual) => { | |
|
187 | format!("bad dirstate size: {} != {}", actual, expected) | |
|
188 | } | |
|
189 | }, | |
|
190 | )), | |
|
191 | } | |
|
192 | } | |
|
193 | ||
|
194 | /// Create the module, with `__package__` given from parent | |
|
195 | pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> { | |
|
196 | let dotted_name = &format!("{}.dirstate", package); | |
|
197 | let m = PyModule::new(py, dotted_name)?; | |
|
198 | m.add(py, "__package__", package)?; | |
|
199 | m.add(py, "__doc__", "Dirstate - Rust implementation")?; | |
|
200 | m.add( | |
|
201 | py, | |
|
202 | "parse_dirstate", | |
|
203 | py_fn!( | |
|
204 | py, | |
|
205 | parse_dirstate_wrapper(dmap: PyDict, copymap: PyDict, st: PyBytes) | |
|
206 | ), | |
|
207 | )?; | |
|
208 | m.add( | |
|
209 | py, | |
|
210 | "pack_dirstate", | |
|
211 | py_fn!( | |
|
212 | py, | |
|
213 | pack_dirstate_wrapper( | |
|
214 | dmap: PyDict, | |
|
215 | copymap: PyDict, | |
|
216 | pl: PyTuple, | |
|
217 | now: PyInt | |
|
218 | ) | |
|
219 | ), | |
|
220 | )?; | |
|
221 | ||
|
222 | let sys = PyModule::import(py, "sys")?; | |
|
223 | let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?; | |
|
224 | sys_modules.set_item(py, dotted_name, &m)?; | |
|
225 | ||
|
226 | Ok(m) | |
|
227 | } |
@@ -1,755 +1,762 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 | #define PY_SSIZE_T_CLEAN |
|
11 | 11 | #include <Python.h> |
|
12 | 12 | #include <ctype.h> |
|
13 | 13 | #include <stddef.h> |
|
14 | 14 | #include <string.h> |
|
15 | 15 | |
|
16 | 16 | #include "bitmanipulation.h" |
|
17 | 17 | #include "charencode.h" |
|
18 | 18 | #include "util.h" |
|
19 | 19 | |
|
20 | 20 | #ifdef IS_PY3K |
|
21 | 21 | /* The mapping of Python types is meant to be temporary to get Python |
|
22 | 22 | * 3 to compile. We should remove this once Python 3 support is fully |
|
23 | 23 | * supported and proper types are used in the extensions themselves. */ |
|
24 | 24 | #define PyInt_Check PyLong_Check |
|
25 | 25 | #define PyInt_FromLong PyLong_FromLong |
|
26 | 26 | #define PyInt_FromSsize_t PyLong_FromSsize_t |
|
27 | 27 | #define PyInt_AsLong PyLong_AsLong |
|
28 | 28 | #endif |
|
29 | 29 | |
|
30 | 30 | static const char *const versionerrortext = "Python minor version mismatch"; |
|
31 | 31 | |
|
32 | 32 | static PyObject *dict_new_presized(PyObject *self, PyObject *args) |
|
33 | 33 | { |
|
34 | 34 | Py_ssize_t expected_size; |
|
35 | 35 | |
|
36 | 36 | if (!PyArg_ParseTuple(args, "n:make_presized_dict", &expected_size)) { |
|
37 | 37 | return NULL; |
|
38 | 38 | } |
|
39 | 39 | |
|
40 | 40 | return _dict_new_presized(expected_size); |
|
41 | 41 | } |
|
42 | 42 | |
|
43 | 43 | static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode, |
|
44 | 44 | int size, int mtime) |
|
45 | 45 | { |
|
46 | 46 | dirstateTupleObject *t = |
|
47 | 47 | PyObject_New(dirstateTupleObject, &dirstateTupleType); |
|
48 | 48 | if (!t) { |
|
49 | 49 | return NULL; |
|
50 | 50 | } |
|
51 | 51 | t->state = state; |
|
52 | 52 | t->mode = mode; |
|
53 | 53 | t->size = size; |
|
54 | 54 | t->mtime = mtime; |
|
55 | 55 | return t; |
|
56 | 56 | } |
|
57 | 57 | |
|
58 | 58 | static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args, |
|
59 | 59 | PyObject *kwds) |
|
60 | 60 | { |
|
61 | 61 | /* We do all the initialization here and not a tp_init function because |
|
62 | 62 | * dirstate_tuple is immutable. */ |
|
63 | 63 | dirstateTupleObject *t; |
|
64 | 64 | char state; |
|
65 | 65 | int size, mode, mtime; |
|
66 | 66 | if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) { |
|
67 | 67 | return NULL; |
|
68 | 68 | } |
|
69 | 69 | |
|
70 | 70 | t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1); |
|
71 | 71 | if (!t) { |
|
72 | 72 | return NULL; |
|
73 | 73 | } |
|
74 | 74 | t->state = state; |
|
75 | 75 | t->mode = mode; |
|
76 | 76 | t->size = size; |
|
77 | 77 | t->mtime = mtime; |
|
78 | 78 | |
|
79 | 79 | return (PyObject *)t; |
|
80 | 80 | } |
|
81 | 81 | |
|
82 | 82 | static void dirstate_tuple_dealloc(PyObject *o) |
|
83 | 83 | { |
|
84 | 84 | PyObject_Del(o); |
|
85 | 85 | } |
|
86 | 86 | |
|
87 | 87 | static Py_ssize_t dirstate_tuple_length(PyObject *o) |
|
88 | 88 | { |
|
89 | 89 | return 4; |
|
90 | 90 | } |
|
91 | 91 | |
|
92 | 92 | static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i) |
|
93 | 93 | { |
|
94 | 94 | dirstateTupleObject *t = (dirstateTupleObject *)o; |
|
95 | 95 | switch (i) { |
|
96 | 96 | case 0: |
|
97 | 97 | return PyBytes_FromStringAndSize(&t->state, 1); |
|
98 | 98 | case 1: |
|
99 | 99 | return PyInt_FromLong(t->mode); |
|
100 | 100 | case 2: |
|
101 | 101 | return PyInt_FromLong(t->size); |
|
102 | 102 | case 3: |
|
103 | 103 | return PyInt_FromLong(t->mtime); |
|
104 | 104 | default: |
|
105 | 105 | PyErr_SetString(PyExc_IndexError, "index out of range"); |
|
106 | 106 | return NULL; |
|
107 | 107 | } |
|
108 | 108 | } |
|
109 | 109 | |
|
110 | 110 | static PySequenceMethods dirstate_tuple_sq = { |
|
111 | 111 | dirstate_tuple_length, /* sq_length */ |
|
112 | 112 | 0, /* sq_concat */ |
|
113 | 113 | 0, /* sq_repeat */ |
|
114 | 114 | dirstate_tuple_item, /* sq_item */ |
|
115 | 115 | 0, /* sq_ass_item */ |
|
116 | 116 | 0, /* sq_contains */ |
|
117 | 117 | 0, /* sq_inplace_concat */ |
|
118 | 118 | 0 /* sq_inplace_repeat */ |
|
119 | 119 | }; |
|
120 | 120 | |
|
121 | 121 | PyTypeObject dirstateTupleType = { |
|
122 | 122 | PyVarObject_HEAD_INIT(NULL, 0) /* header */ |
|
123 | 123 | "dirstate_tuple", /* tp_name */ |
|
124 | 124 | sizeof(dirstateTupleObject), /* tp_basicsize */ |
|
125 | 125 | 0, /* tp_itemsize */ |
|
126 | 126 | (destructor)dirstate_tuple_dealloc, /* tp_dealloc */ |
|
127 | 127 | 0, /* tp_print */ |
|
128 | 128 | 0, /* tp_getattr */ |
|
129 | 129 | 0, /* tp_setattr */ |
|
130 | 130 | 0, /* tp_compare */ |
|
131 | 131 | 0, /* tp_repr */ |
|
132 | 132 | 0, /* tp_as_number */ |
|
133 | 133 | &dirstate_tuple_sq, /* tp_as_sequence */ |
|
134 | 134 | 0, /* tp_as_mapping */ |
|
135 | 135 | 0, /* tp_hash */ |
|
136 | 136 | 0, /* tp_call */ |
|
137 | 137 | 0, /* tp_str */ |
|
138 | 138 | 0, /* tp_getattro */ |
|
139 | 139 | 0, /* tp_setattro */ |
|
140 | 140 | 0, /* tp_as_buffer */ |
|
141 | 141 | Py_TPFLAGS_DEFAULT, /* tp_flags */ |
|
142 | 142 | "dirstate tuple", /* tp_doc */ |
|
143 | 143 | 0, /* tp_traverse */ |
|
144 | 144 | 0, /* tp_clear */ |
|
145 | 145 | 0, /* tp_richcompare */ |
|
146 | 146 | 0, /* tp_weaklistoffset */ |
|
147 | 147 | 0, /* tp_iter */ |
|
148 | 148 | 0, /* tp_iternext */ |
|
149 | 149 | 0, /* tp_methods */ |
|
150 | 150 | 0, /* tp_members */ |
|
151 | 151 | 0, /* tp_getset */ |
|
152 | 152 | 0, /* tp_base */ |
|
153 | 153 | 0, /* tp_dict */ |
|
154 | 154 | 0, /* tp_descr_get */ |
|
155 | 155 | 0, /* tp_descr_set */ |
|
156 | 156 | 0, /* tp_dictoffset */ |
|
157 | 157 | 0, /* tp_init */ |
|
158 | 158 | 0, /* tp_alloc */ |
|
159 | 159 | dirstate_tuple_new, /* tp_new */ |
|
160 | 160 | }; |
|
161 | 161 | |
|
162 | 162 | static PyObject *parse_dirstate(PyObject *self, PyObject *args) |
|
163 | 163 | { |
|
164 | 164 | PyObject *dmap, *cmap, *parents = NULL, *ret = NULL; |
|
165 | 165 | PyObject *fname = NULL, *cname = NULL, *entry = NULL; |
|
166 | 166 | char state, *cur, *str, *cpos; |
|
167 | 167 | int mode, size, mtime; |
|
168 | 168 | unsigned int flen, pos = 40; |
|
169 | 169 | Py_ssize_t len = 40; |
|
170 | 170 | Py_ssize_t readlen; |
|
171 | 171 | |
|
172 | 172 | if (!PyArg_ParseTuple( |
|
173 | 173 | args, PY23("O!O!s#:parse_dirstate", "O!O!y#:parse_dirstate"), |
|
174 | 174 | &PyDict_Type, &dmap, &PyDict_Type, &cmap, &str, &readlen)) { |
|
175 | 175 | goto quit; |
|
176 | 176 | } |
|
177 | 177 | |
|
178 | 178 | len = readlen; |
|
179 | 179 | |
|
180 | 180 | /* read parents */ |
|
181 | 181 | if (len < 40) { |
|
182 | 182 | PyErr_SetString(PyExc_ValueError, |
|
183 | 183 | "too little data for parents"); |
|
184 | 184 | goto quit; |
|
185 | 185 | } |
|
186 | 186 | |
|
187 | 187 | parents = Py_BuildValue(PY23("s#s#", "y#y#"), str, (Py_ssize_t)20, |
|
188 | 188 | str + 20, (Py_ssize_t)20); |
|
189 | 189 | if (!parents) { |
|
190 | 190 | goto quit; |
|
191 | 191 | } |
|
192 | 192 | |
|
193 | 193 | /* read filenames */ |
|
194 | 194 | while (pos >= 40 && pos < len) { |
|
195 | 195 | if (pos + 17 > len) { |
|
196 | 196 | PyErr_SetString(PyExc_ValueError, |
|
197 | 197 | "overflow in dirstate"); |
|
198 | 198 | goto quit; |
|
199 | 199 | } |
|
200 | 200 | cur = str + pos; |
|
201 | 201 | /* unpack header */ |
|
202 | 202 | state = *cur; |
|
203 | 203 | mode = getbe32(cur + 1); |
|
204 | 204 | size = getbe32(cur + 5); |
|
205 | 205 | mtime = getbe32(cur + 9); |
|
206 | 206 | flen = getbe32(cur + 13); |
|
207 | 207 | pos += 17; |
|
208 | 208 | cur += 17; |
|
209 | 209 | if (flen > len - pos) { |
|
210 | 210 | PyErr_SetString(PyExc_ValueError, |
|
211 | 211 | "overflow in dirstate"); |
|
212 | 212 | goto quit; |
|
213 | 213 | } |
|
214 | 214 | |
|
215 | 215 | entry = |
|
216 | 216 | (PyObject *)make_dirstate_tuple(state, mode, size, mtime); |
|
217 | 217 | cpos = memchr(cur, 0, flen); |
|
218 | 218 | if (cpos) { |
|
219 | 219 | fname = PyBytes_FromStringAndSize(cur, cpos - cur); |
|
220 | 220 | cname = PyBytes_FromStringAndSize( |
|
221 | 221 | cpos + 1, flen - (cpos - cur) - 1); |
|
222 | 222 | if (!fname || !cname || |
|
223 | 223 | PyDict_SetItem(cmap, fname, cname) == -1 || |
|
224 | 224 | PyDict_SetItem(dmap, fname, entry) == -1) { |
|
225 | 225 | goto quit; |
|
226 | 226 | } |
|
227 | 227 | Py_DECREF(cname); |
|
228 | 228 | } else { |
|
229 | 229 | fname = PyBytes_FromStringAndSize(cur, flen); |
|
230 | 230 | if (!fname || |
|
231 | 231 | PyDict_SetItem(dmap, fname, entry) == -1) { |
|
232 | 232 | goto quit; |
|
233 | 233 | } |
|
234 | 234 | } |
|
235 | 235 | Py_DECREF(fname); |
|
236 | 236 | Py_DECREF(entry); |
|
237 | 237 | fname = cname = entry = NULL; |
|
238 | 238 | pos += flen; |
|
239 | 239 | } |
|
240 | 240 | |
|
241 | 241 | ret = parents; |
|
242 | 242 | Py_INCREF(ret); |
|
243 | 243 | quit: |
|
244 | 244 | Py_XDECREF(fname); |
|
245 | 245 | Py_XDECREF(cname); |
|
246 | 246 | Py_XDECREF(entry); |
|
247 | 247 | Py_XDECREF(parents); |
|
248 | 248 | return ret; |
|
249 | 249 | } |
|
250 | 250 | |
|
251 | 251 | /* |
|
252 | 252 | * Build a set of non-normal and other parent entries from the dirstate dmap |
|
253 | 253 | */ |
|
254 | 254 | static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args) |
|
255 | 255 | { |
|
256 | 256 | PyObject *dmap, *fname, *v; |
|
257 | 257 | PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL; |
|
258 | 258 | Py_ssize_t pos; |
|
259 | 259 | |
|
260 | 260 | if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type, |
|
261 | 261 | &dmap)) { |
|
262 | 262 | goto bail; |
|
263 | 263 | } |
|
264 | 264 | |
|
265 | 265 | nonnset = PySet_New(NULL); |
|
266 | 266 | if (nonnset == NULL) { |
|
267 | 267 | goto bail; |
|
268 | 268 | } |
|
269 | 269 | |
|
270 | 270 | otherpset = PySet_New(NULL); |
|
271 | 271 | if (otherpset == NULL) { |
|
272 | 272 | goto bail; |
|
273 | 273 | } |
|
274 | 274 | |
|
275 | 275 | pos = 0; |
|
276 | 276 | while (PyDict_Next(dmap, &pos, &fname, &v)) { |
|
277 | 277 | dirstateTupleObject *t; |
|
278 | 278 | if (!dirstate_tuple_check(v)) { |
|
279 | 279 | PyErr_SetString(PyExc_TypeError, |
|
280 | 280 | "expected a dirstate tuple"); |
|
281 | 281 | goto bail; |
|
282 | 282 | } |
|
283 | 283 | t = (dirstateTupleObject *)v; |
|
284 | 284 | |
|
285 | 285 | if (t->state == 'n' && t->size == -2) { |
|
286 | 286 | if (PySet_Add(otherpset, fname) == -1) { |
|
287 | 287 | goto bail; |
|
288 | 288 | } |
|
289 | 289 | } |
|
290 | 290 | |
|
291 | 291 | if (t->state == 'n' && t->mtime != -1) { |
|
292 | 292 | continue; |
|
293 | 293 | } |
|
294 | 294 | if (PySet_Add(nonnset, fname) == -1) { |
|
295 | 295 | goto bail; |
|
296 | 296 | } |
|
297 | 297 | } |
|
298 | 298 | |
|
299 | 299 | result = Py_BuildValue("(OO)", nonnset, otherpset); |
|
300 | 300 | if (result == NULL) { |
|
301 | 301 | goto bail; |
|
302 | 302 | } |
|
303 | 303 | Py_DECREF(nonnset); |
|
304 | 304 | Py_DECREF(otherpset); |
|
305 | 305 | return result; |
|
306 | 306 | bail: |
|
307 | 307 | Py_XDECREF(nonnset); |
|
308 | 308 | Py_XDECREF(otherpset); |
|
309 | 309 | Py_XDECREF(result); |
|
310 | 310 | return NULL; |
|
311 | 311 | } |
|
312 | 312 | |
|
313 | 313 | /* |
|
314 | 314 | * Efficiently pack a dirstate object into its on-disk format. |
|
315 | 315 | */ |
|
316 | 316 | static PyObject *pack_dirstate(PyObject *self, PyObject *args) |
|
317 | 317 | { |
|
318 | 318 | PyObject *packobj = NULL; |
|
319 | 319 | PyObject *map, *copymap, *pl, *mtime_unset = NULL; |
|
320 | 320 | Py_ssize_t nbytes, pos, l; |
|
321 | 321 | PyObject *k, *v = NULL, *pn; |
|
322 | 322 | char *p, *s; |
|
323 | 323 | int now; |
|
324 | 324 | |
|
325 | 325 | if (!PyArg_ParseTuple(args, "O!O!O!i:pack_dirstate", &PyDict_Type, &map, |
|
326 | 326 | &PyDict_Type, ©map, &PyTuple_Type, &pl, |
|
327 | 327 | &now)) { |
|
328 | 328 | return NULL; |
|
329 | 329 | } |
|
330 | 330 | |
|
331 | 331 | if (PyTuple_Size(pl) != 2) { |
|
332 | 332 | PyErr_SetString(PyExc_TypeError, "expected 2-element tuple"); |
|
333 | 333 | return NULL; |
|
334 | 334 | } |
|
335 | 335 | |
|
336 | 336 | /* Figure out how much we need to allocate. */ |
|
337 | 337 | for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) { |
|
338 | 338 | PyObject *c; |
|
339 | 339 | if (!PyBytes_Check(k)) { |
|
340 | 340 | PyErr_SetString(PyExc_TypeError, "expected string key"); |
|
341 | 341 | goto bail; |
|
342 | 342 | } |
|
343 | 343 | nbytes += PyBytes_GET_SIZE(k) + 17; |
|
344 | 344 | c = PyDict_GetItem(copymap, k); |
|
345 | 345 | if (c) { |
|
346 | 346 | if (!PyBytes_Check(c)) { |
|
347 | 347 | PyErr_SetString(PyExc_TypeError, |
|
348 | 348 | "expected string key"); |
|
349 | 349 | goto bail; |
|
350 | 350 | } |
|
351 | 351 | nbytes += PyBytes_GET_SIZE(c) + 1; |
|
352 | 352 | } |
|
353 | 353 | } |
|
354 | 354 | |
|
355 | 355 | packobj = PyBytes_FromStringAndSize(NULL, nbytes); |
|
356 | 356 | if (packobj == NULL) { |
|
357 | 357 | goto bail; |
|
358 | 358 | } |
|
359 | 359 | |
|
360 | 360 | p = PyBytes_AS_STRING(packobj); |
|
361 | 361 | |
|
362 | 362 | pn = PyTuple_GET_ITEM(pl, 0); |
|
363 | 363 | if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) { |
|
364 | 364 | PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash"); |
|
365 | 365 | goto bail; |
|
366 | 366 | } |
|
367 | 367 | memcpy(p, s, l); |
|
368 | 368 | p += 20; |
|
369 | 369 | pn = PyTuple_GET_ITEM(pl, 1); |
|
370 | 370 | if (PyBytes_AsStringAndSize(pn, &s, &l) == -1 || l != 20) { |
|
371 | 371 | PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash"); |
|
372 | 372 | goto bail; |
|
373 | 373 | } |
|
374 | 374 | memcpy(p, s, l); |
|
375 | 375 | p += 20; |
|
376 | 376 | |
|
377 | 377 | for (pos = 0; PyDict_Next(map, &pos, &k, &v);) { |
|
378 | 378 | dirstateTupleObject *tuple; |
|
379 | 379 | char state; |
|
380 | 380 | int mode, size, mtime; |
|
381 | 381 | Py_ssize_t len, l; |
|
382 | 382 | PyObject *o; |
|
383 | 383 | char *t; |
|
384 | 384 | |
|
385 | 385 | if (!dirstate_tuple_check(v)) { |
|
386 | 386 | PyErr_SetString(PyExc_TypeError, |
|
387 | 387 | "expected a dirstate tuple"); |
|
388 | 388 | goto bail; |
|
389 | 389 | } |
|
390 | 390 | tuple = (dirstateTupleObject *)v; |
|
391 | 391 | |
|
392 | 392 | state = tuple->state; |
|
393 | 393 | mode = tuple->mode; |
|
394 | 394 | size = tuple->size; |
|
395 | 395 | mtime = tuple->mtime; |
|
396 | 396 | if (state == 'n' && mtime == now) { |
|
397 | 397 | /* See pure/parsers.py:pack_dirstate for why we do |
|
398 | 398 | * this. */ |
|
399 | 399 | mtime = -1; |
|
400 | 400 | mtime_unset = (PyObject *)make_dirstate_tuple( |
|
401 | 401 | state, mode, size, mtime); |
|
402 | 402 | if (!mtime_unset) { |
|
403 | 403 | goto bail; |
|
404 | 404 | } |
|
405 | 405 | if (PyDict_SetItem(map, k, mtime_unset) == -1) { |
|
406 | 406 | goto bail; |
|
407 | 407 | } |
|
408 | 408 | Py_DECREF(mtime_unset); |
|
409 | 409 | mtime_unset = NULL; |
|
410 | 410 | } |
|
411 | 411 | *p++ = state; |
|
412 | 412 | putbe32((uint32_t)mode, p); |
|
413 | 413 | putbe32((uint32_t)size, p + 4); |
|
414 | 414 | putbe32((uint32_t)mtime, p + 8); |
|
415 | 415 | t = p + 12; |
|
416 | 416 | p += 16; |
|
417 | 417 | len = PyBytes_GET_SIZE(k); |
|
418 | 418 | memcpy(p, PyBytes_AS_STRING(k), len); |
|
419 | 419 | p += len; |
|
420 | 420 | o = PyDict_GetItem(copymap, k); |
|
421 | 421 | if (o) { |
|
422 | 422 | *p++ = '\0'; |
|
423 | 423 | l = PyBytes_GET_SIZE(o); |
|
424 | 424 | memcpy(p, PyBytes_AS_STRING(o), l); |
|
425 | 425 | p += l; |
|
426 | 426 | len += l + 1; |
|
427 | 427 | } |
|
428 | 428 | putbe32((uint32_t)len, t); |
|
429 | 429 | } |
|
430 | 430 | |
|
431 | 431 | pos = p - PyBytes_AS_STRING(packobj); |
|
432 | 432 | if (pos != nbytes) { |
|
433 | 433 | PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld", |
|
434 | 434 | (long)pos, (long)nbytes); |
|
435 | 435 | goto bail; |
|
436 | 436 | } |
|
437 | 437 | |
|
438 | 438 | return packobj; |
|
439 | 439 | bail: |
|
440 | 440 | Py_XDECREF(mtime_unset); |
|
441 | 441 | Py_XDECREF(packobj); |
|
442 | 442 | Py_XDECREF(v); |
|
443 | 443 | return NULL; |
|
444 | 444 | } |
|
445 | 445 | |
|
446 | 446 | #define BUMPED_FIX 1 |
|
447 | 447 | #define USING_SHA_256 2 |
|
448 | 448 | #define FM1_HEADER_SIZE (4 + 8 + 2 + 2 + 1 + 1 + 1) |
|
449 | 449 | |
|
450 | 450 | static PyObject *readshas(const char *source, unsigned char num, |
|
451 | 451 | Py_ssize_t hashwidth) |
|
452 | 452 | { |
|
453 | 453 | int i; |
|
454 | 454 | PyObject *list = PyTuple_New(num); |
|
455 | 455 | if (list == NULL) { |
|
456 | 456 | return NULL; |
|
457 | 457 | } |
|
458 | 458 | for (i = 0; i < num; i++) { |
|
459 | 459 | PyObject *hash = PyBytes_FromStringAndSize(source, hashwidth); |
|
460 | 460 | if (hash == NULL) { |
|
461 | 461 | Py_DECREF(list); |
|
462 | 462 | return NULL; |
|
463 | 463 | } |
|
464 | 464 | PyTuple_SET_ITEM(list, i, hash); |
|
465 | 465 | source += hashwidth; |
|
466 | 466 | } |
|
467 | 467 | return list; |
|
468 | 468 | } |
|
469 | 469 | |
|
470 | 470 | static PyObject *fm1readmarker(const char *databegin, const char *dataend, |
|
471 | 471 | uint32_t *msize) |
|
472 | 472 | { |
|
473 | 473 | const char *data = databegin; |
|
474 | 474 | const char *meta; |
|
475 | 475 | |
|
476 | 476 | double mtime; |
|
477 | 477 | int16_t tz; |
|
478 | 478 | uint16_t flags; |
|
479 | 479 | unsigned char nsuccs, nparents, nmetadata; |
|
480 | 480 | Py_ssize_t hashwidth = 20; |
|
481 | 481 | |
|
482 | 482 | PyObject *prec = NULL, *parents = NULL, *succs = NULL; |
|
483 | 483 | PyObject *metadata = NULL, *ret = NULL; |
|
484 | 484 | int i; |
|
485 | 485 | |
|
486 | 486 | if (data + FM1_HEADER_SIZE > dataend) { |
|
487 | 487 | goto overflow; |
|
488 | 488 | } |
|
489 | 489 | |
|
490 | 490 | *msize = getbe32(data); |
|
491 | 491 | data += 4; |
|
492 | 492 | mtime = getbefloat64(data); |
|
493 | 493 | data += 8; |
|
494 | 494 | tz = getbeint16(data); |
|
495 | 495 | data += 2; |
|
496 | 496 | flags = getbeuint16(data); |
|
497 | 497 | data += 2; |
|
498 | 498 | |
|
499 | 499 | if (flags & USING_SHA_256) { |
|
500 | 500 | hashwidth = 32; |
|
501 | 501 | } |
|
502 | 502 | |
|
503 | 503 | nsuccs = (unsigned char)(*data++); |
|
504 | 504 | nparents = (unsigned char)(*data++); |
|
505 | 505 | nmetadata = (unsigned char)(*data++); |
|
506 | 506 | |
|
507 | 507 | if (databegin + *msize > dataend) { |
|
508 | 508 | goto overflow; |
|
509 | 509 | } |
|
510 | 510 | dataend = databegin + *msize; /* narrow down to marker size */ |
|
511 | 511 | |
|
512 | 512 | if (data + hashwidth > dataend) { |
|
513 | 513 | goto overflow; |
|
514 | 514 | } |
|
515 | 515 | prec = PyBytes_FromStringAndSize(data, hashwidth); |
|
516 | 516 | data += hashwidth; |
|
517 | 517 | if (prec == NULL) { |
|
518 | 518 | goto bail; |
|
519 | 519 | } |
|
520 | 520 | |
|
521 | 521 | if (data + nsuccs * hashwidth > dataend) { |
|
522 | 522 | goto overflow; |
|
523 | 523 | } |
|
524 | 524 | succs = readshas(data, nsuccs, hashwidth); |
|
525 | 525 | if (succs == NULL) { |
|
526 | 526 | goto bail; |
|
527 | 527 | } |
|
528 | 528 | data += nsuccs * hashwidth; |
|
529 | 529 | |
|
530 | 530 | if (nparents == 1 || nparents == 2) { |
|
531 | 531 | if (data + nparents * hashwidth > dataend) { |
|
532 | 532 | goto overflow; |
|
533 | 533 | } |
|
534 | 534 | parents = readshas(data, nparents, hashwidth); |
|
535 | 535 | if (parents == NULL) { |
|
536 | 536 | goto bail; |
|
537 | 537 | } |
|
538 | 538 | data += nparents * hashwidth; |
|
539 | 539 | } else { |
|
540 | 540 | parents = Py_None; |
|
541 | 541 | Py_INCREF(parents); |
|
542 | 542 | } |
|
543 | 543 | |
|
544 | 544 | if (data + 2 * nmetadata > dataend) { |
|
545 | 545 | goto overflow; |
|
546 | 546 | } |
|
547 | 547 | meta = data + (2 * nmetadata); |
|
548 | 548 | metadata = PyTuple_New(nmetadata); |
|
549 | 549 | if (metadata == NULL) { |
|
550 | 550 | goto bail; |
|
551 | 551 | } |
|
552 | 552 | for (i = 0; i < nmetadata; i++) { |
|
553 | 553 | PyObject *tmp, *left = NULL, *right = NULL; |
|
554 | 554 | Py_ssize_t leftsize = (unsigned char)(*data++); |
|
555 | 555 | Py_ssize_t rightsize = (unsigned char)(*data++); |
|
556 | 556 | if (meta + leftsize + rightsize > dataend) { |
|
557 | 557 | goto overflow; |
|
558 | 558 | } |
|
559 | 559 | left = PyBytes_FromStringAndSize(meta, leftsize); |
|
560 | 560 | meta += leftsize; |
|
561 | 561 | right = PyBytes_FromStringAndSize(meta, rightsize); |
|
562 | 562 | meta += rightsize; |
|
563 | 563 | tmp = PyTuple_New(2); |
|
564 | 564 | if (!left || !right || !tmp) { |
|
565 | 565 | Py_XDECREF(left); |
|
566 | 566 | Py_XDECREF(right); |
|
567 | 567 | Py_XDECREF(tmp); |
|
568 | 568 | goto bail; |
|
569 | 569 | } |
|
570 | 570 | PyTuple_SET_ITEM(tmp, 0, left); |
|
571 | 571 | PyTuple_SET_ITEM(tmp, 1, right); |
|
572 | 572 | PyTuple_SET_ITEM(metadata, i, tmp); |
|
573 | 573 | } |
|
574 | 574 | ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags, metadata, mtime, |
|
575 | 575 | (int)tz * 60, parents); |
|
576 | 576 | goto bail; /* return successfully */ |
|
577 | 577 | |
|
578 | 578 | overflow: |
|
579 | 579 | PyErr_SetString(PyExc_ValueError, "overflow in obsstore"); |
|
580 | 580 | bail: |
|
581 | 581 | Py_XDECREF(prec); |
|
582 | 582 | Py_XDECREF(succs); |
|
583 | 583 | Py_XDECREF(metadata); |
|
584 | 584 | Py_XDECREF(parents); |
|
585 | 585 | return ret; |
|
586 | 586 | } |
|
587 | 587 | |
|
588 | 588 | static PyObject *fm1readmarkers(PyObject *self, PyObject *args) |
|
589 | 589 | { |
|
590 | 590 | const char *data, *dataend; |
|
591 | 591 | Py_ssize_t datalen, offset, stop; |
|
592 | 592 | PyObject *markers = NULL; |
|
593 | 593 | |
|
594 | 594 | if (!PyArg_ParseTuple(args, PY23("s#nn", "y#nn"), &data, &datalen, |
|
595 | 595 | &offset, &stop)) { |
|
596 | 596 | return NULL; |
|
597 | 597 | } |
|
598 | 598 | if (offset < 0) { |
|
599 | 599 | PyErr_SetString(PyExc_ValueError, |
|
600 | 600 | "invalid negative offset in fm1readmarkers"); |
|
601 | 601 | return NULL; |
|
602 | 602 | } |
|
603 | 603 | if (stop > datalen) { |
|
604 | 604 | PyErr_SetString( |
|
605 | 605 | PyExc_ValueError, |
|
606 | 606 | "stop longer than data length in fm1readmarkers"); |
|
607 | 607 | return NULL; |
|
608 | 608 | } |
|
609 | 609 | dataend = data + datalen; |
|
610 | 610 | data += offset; |
|
611 | 611 | markers = PyList_New(0); |
|
612 | 612 | if (!markers) { |
|
613 | 613 | return NULL; |
|
614 | 614 | } |
|
615 | 615 | while (offset < stop) { |
|
616 | 616 | uint32_t msize; |
|
617 | 617 | int error; |
|
618 | 618 | PyObject *record = fm1readmarker(data, dataend, &msize); |
|
619 | 619 | if (!record) { |
|
620 | 620 | goto bail; |
|
621 | 621 | } |
|
622 | 622 | error = PyList_Append(markers, record); |
|
623 | 623 | Py_DECREF(record); |
|
624 | 624 | if (error) { |
|
625 | 625 | goto bail; |
|
626 | 626 | } |
|
627 | 627 | data += msize; |
|
628 | 628 | offset += msize; |
|
629 | 629 | } |
|
630 | 630 | return markers; |
|
631 | 631 | bail: |
|
632 | 632 | Py_DECREF(markers); |
|
633 | 633 | return NULL; |
|
634 | 634 | } |
|
635 | 635 | |
|
636 | 636 | static char parsers_doc[] = "Efficient content parsing."; |
|
637 | 637 | |
|
638 | 638 | PyObject *encodedir(PyObject *self, PyObject *args); |
|
639 | 639 | PyObject *pathencode(PyObject *self, PyObject *args); |
|
640 | 640 | PyObject *lowerencode(PyObject *self, PyObject *args); |
|
641 | 641 | PyObject *parse_index2(PyObject *self, PyObject *args); |
|
642 | 642 | |
|
643 | 643 | static PyMethodDef methods[] = { |
|
644 | 644 | {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"}, |
|
645 | 645 | {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS, |
|
646 | 646 | "create a set containing non-normal and other parent entries of given " |
|
647 | 647 | "dirstate\n"}, |
|
648 | 648 | {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"}, |
|
649 | 649 | {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"}, |
|
650 | 650 | {"isasciistr", isasciistr, METH_VARARGS, "check if an ASCII string\n"}, |
|
651 | 651 | {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"}, |
|
652 | 652 | {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"}, |
|
653 | 653 | {"dict_new_presized", dict_new_presized, METH_VARARGS, |
|
654 | 654 | "construct a dict with an expected size\n"}, |
|
655 | 655 | {"make_file_foldmap", make_file_foldmap, METH_VARARGS, |
|
656 | 656 | "make file foldmap\n"}, |
|
657 | 657 | {"jsonescapeu8fast", jsonescapeu8fast, METH_VARARGS, |
|
658 | 658 | "escape a UTF-8 byte string to JSON (fast path)\n"}, |
|
659 | 659 | {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"}, |
|
660 | 660 | {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"}, |
|
661 | 661 | {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"}, |
|
662 | 662 | {"fm1readmarkers", fm1readmarkers, METH_VARARGS, |
|
663 | 663 | "parse v1 obsolete markers\n"}, |
|
664 | 664 | {NULL, NULL}}; |
|
665 | 665 | |
|
666 | 666 | void dirs_module_init(PyObject *mod); |
|
667 | 667 | void manifest_module_init(PyObject *mod); |
|
668 | 668 | void revlog_module_init(PyObject *mod); |
|
669 | 669 | |
|
670 | 670 | static const int version = 12; |
|
671 | 671 | |
|
672 | 672 | static void module_init(PyObject *mod) |
|
673 | 673 | { |
|
674 | PyObject *capsule = NULL; | |
|
674 | 675 | PyModule_AddIntConstant(mod, "version", version); |
|
675 | 676 | |
|
676 | 677 | /* This module constant has two purposes. First, it lets us unit test |
|
677 | 678 | * the ImportError raised without hard-coding any error text. This |
|
678 | 679 | * means we can change the text in the future without breaking tests, |
|
679 | 680 | * even across changesets without a recompile. Second, its presence |
|
680 | 681 | * can be used to determine whether the version-checking logic is |
|
681 | 682 | * present, which also helps in testing across changesets without a |
|
682 | 683 | * recompile. Note that this means the pure-Python version of parsers |
|
683 | 684 | * should not have this module constant. */ |
|
684 | 685 | PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext); |
|
685 | 686 | |
|
686 | 687 | dirs_module_init(mod); |
|
687 | 688 | manifest_module_init(mod); |
|
688 | 689 | revlog_module_init(mod); |
|
689 | 690 | |
|
691 | capsule = PyCapsule_New( | |
|
692 | make_dirstate_tuple, | |
|
693 | "mercurial.cext.parsers.make_dirstate_tuple_CAPI", NULL); | |
|
694 | if (capsule != NULL) | |
|
695 | PyModule_AddObject(mod, "make_dirstate_tuple_CAPI", capsule); | |
|
696 | ||
|
690 | 697 | if (PyType_Ready(&dirstateTupleType) < 0) { |
|
691 | 698 | return; |
|
692 | 699 | } |
|
693 | 700 | Py_INCREF(&dirstateTupleType); |
|
694 | 701 | PyModule_AddObject(mod, "dirstatetuple", |
|
695 | 702 | (PyObject *)&dirstateTupleType); |
|
696 | 703 | } |
|
697 | 704 | |
|
698 | 705 | static int check_python_version(void) |
|
699 | 706 | { |
|
700 | 707 | PyObject *sys = PyImport_ImportModule("sys"), *ver; |
|
701 | 708 | long hexversion; |
|
702 | 709 | if (!sys) { |
|
703 | 710 | return -1; |
|
704 | 711 | } |
|
705 | 712 | ver = PyObject_GetAttrString(sys, "hexversion"); |
|
706 | 713 | Py_DECREF(sys); |
|
707 | 714 | if (!ver) { |
|
708 | 715 | return -1; |
|
709 | 716 | } |
|
710 | 717 | hexversion = PyInt_AsLong(ver); |
|
711 | 718 | Py_DECREF(ver); |
|
712 | 719 | /* sys.hexversion is a 32-bit number by default, so the -1 case |
|
713 | 720 | * should only occur in unusual circumstances (e.g. if sys.hexversion |
|
714 | 721 | * is manually set to an invalid value). */ |
|
715 | 722 | if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) { |
|
716 | 723 | PyErr_Format(PyExc_ImportError, |
|
717 | 724 | "%s: The Mercurial extension " |
|
718 | 725 | "modules were compiled with Python " PY_VERSION |
|
719 | 726 | ", but " |
|
720 | 727 | "Mercurial is currently using Python with " |
|
721 | 728 | "sys.hexversion=%ld: " |
|
722 | 729 | "Python %s\n at: %s", |
|
723 | 730 | versionerrortext, hexversion, Py_GetVersion(), |
|
724 | 731 | Py_GetProgramFullPath()); |
|
725 | 732 | return -1; |
|
726 | 733 | } |
|
727 | 734 | return 0; |
|
728 | 735 | } |
|
729 | 736 | |
|
730 | 737 | #ifdef IS_PY3K |
|
731 | 738 | static struct PyModuleDef parsers_module = {PyModuleDef_HEAD_INIT, "parsers", |
|
732 | 739 | parsers_doc, -1, methods}; |
|
733 | 740 | |
|
734 | 741 | PyMODINIT_FUNC PyInit_parsers(void) |
|
735 | 742 | { |
|
736 | 743 | PyObject *mod; |
|
737 | 744 | |
|
738 | 745 | if (check_python_version() == -1) |
|
739 | 746 | return NULL; |
|
740 | 747 | mod = PyModule_Create(&parsers_module); |
|
741 | 748 | module_init(mod); |
|
742 | 749 | return mod; |
|
743 | 750 | } |
|
744 | 751 | #else |
|
745 | 752 | PyMODINIT_FUNC initparsers(void) |
|
746 | 753 | { |
|
747 | 754 | PyObject *mod; |
|
748 | 755 | |
|
749 | 756 | if (check_python_version() == -1) { |
|
750 | 757 | return; |
|
751 | 758 | } |
|
752 | 759 | mod = Py_InitModule3("parsers", methods, parsers_doc); |
|
753 | 760 | module_init(mod); |
|
754 | 761 | } |
|
755 | 762 | #endif |
@@ -1,341 +1,332 b'' | |||
|
1 | 1 | [[package]] |
|
2 | 2 | name = "aho-corasick" |
|
3 | 3 | version = "0.6.9" |
|
4 | 4 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
5 | 5 | dependencies = [ |
|
6 |
"memchr 2. |
|
|
6 | "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | |
|
7 | 7 | ] |
|
8 | 8 | |
|
9 | 9 | [[package]] |
|
10 | 10 | name = "autocfg" |
|
11 | 11 | version = "0.1.2" |
|
12 | 12 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
13 | 13 | |
|
14 | 14 | [[package]] |
|
15 | 15 | name = "bitflags" |
|
16 | 16 | version = "1.0.4" |
|
17 | 17 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
18 | 18 | |
|
19 | 19 | [[package]] |
|
20 | name = "cfg-if" | |
|
21 |
version = " |
|
|
20 | name = "byteorder" | |
|
21 | version = "1.3.1" | |
|
22 | 22 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
23 | 23 | |
|
24 | 24 | [[package]] |
|
25 | 25 | name = "cloudabi" |
|
26 | 26 | version = "0.0.3" |
|
27 | 27 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
28 | 28 | dependencies = [ |
|
29 | 29 | "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", |
|
30 | 30 | ] |
|
31 | 31 | |
|
32 | 32 | [[package]] |
|
33 | 33 | name = "cpython" |
|
34 | 34 | version = "0.2.1" |
|
35 | 35 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
36 | 36 | dependencies = [ |
|
37 | 37 | "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", |
|
38 | 38 | "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", |
|
39 | 39 | "python27-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
40 | 40 | "python3-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
41 | 41 | ] |
|
42 | 42 | |
|
43 | 43 | [[package]] |
|
44 | 44 | name = "fuchsia-cprng" |
|
45 | 45 | version = "0.1.0" |
|
46 | 46 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
47 | 47 | |
|
48 | 48 | [[package]] |
|
49 | 49 | name = "hg-core" |
|
50 | 50 | version = "0.1.0" |
|
51 | 51 | dependencies = [ |
|
52 | "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", | |
|
53 | "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | |
|
52 | 54 | "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", |
|
53 | 55 | "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
54 | 56 | ] |
|
55 | 57 | |
|
56 | 58 | [[package]] |
|
57 | 59 | name = "hg-cpython" |
|
58 | 60 | version = "0.1.0" |
|
59 | 61 | dependencies = [ |
|
60 | 62 | "cpython 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
61 | 63 | "hg-core 0.1.0", |
|
62 | 64 | "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", |
|
63 | 65 | "python27-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
64 | 66 | "python3-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
65 | 67 | ] |
|
66 | 68 | |
|
67 | 69 | [[package]] |
|
68 | 70 | name = "hgdirectffi" |
|
69 | 71 | version = "0.1.0" |
|
70 | 72 | dependencies = [ |
|
71 | 73 | "hg-core 0.1.0", |
|
72 | 74 | "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", |
|
73 | 75 | ] |
|
74 | 76 | |
|
75 | 77 | [[package]] |
|
76 | 78 | name = "lazy_static" |
|
77 | 79 | version = "1.2.0" |
|
78 | 80 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
79 | 81 | |
|
80 | 82 | [[package]] |
|
81 | 83 | name = "libc" |
|
82 | 84 | version = "0.2.45" |
|
83 | 85 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
84 | 86 | |
|
85 | 87 | [[package]] |
|
86 | 88 | name = "memchr" |
|
87 |
version = "2. |
|
|
89 | version = "2.2.0" | |
|
88 | 90 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
89 | dependencies = [ | |
|
90 | "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", | |
|
91 | "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", | |
|
92 | "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", | |
|
93 | ] | |
|
94 | 91 | |
|
95 | 92 | [[package]] |
|
96 | 93 | name = "num-traits" |
|
97 | 94 | version = "0.2.6" |
|
98 | 95 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
99 | 96 | |
|
100 | 97 | [[package]] |
|
101 | 98 | name = "python27-sys" |
|
102 | 99 | version = "0.2.1" |
|
103 | 100 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
104 | 101 | dependencies = [ |
|
105 | 102 | "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", |
|
106 | 103 | "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
107 | 104 | ] |
|
108 | 105 | |
|
109 | 106 | [[package]] |
|
110 | 107 | name = "python3-sys" |
|
111 | 108 | version = "0.2.1" |
|
112 | 109 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
113 | 110 | dependencies = [ |
|
114 | 111 | "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", |
|
115 | 112 | "regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
116 | 113 | ] |
|
117 | 114 | |
|
118 | 115 | [[package]] |
|
119 | 116 | name = "rand" |
|
120 | 117 | version = "0.6.5" |
|
121 | 118 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
122 | 119 | dependencies = [ |
|
123 | 120 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", |
|
124 | 121 | "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", |
|
125 | 122 | "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
126 | 123 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
127 | 124 | "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
128 | 125 | "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
129 | 126 | "rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", |
|
130 | 127 | "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", |
|
131 | 128 | "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
132 | 129 | "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
133 | 130 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", |
|
134 | 131 | ] |
|
135 | 132 | |
|
136 | 133 | [[package]] |
|
137 | 134 | name = "rand_chacha" |
|
138 | 135 | version = "0.1.1" |
|
139 | 136 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
140 | 137 | dependencies = [ |
|
141 | 138 | "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", |
|
142 | 139 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
143 | 140 | ] |
|
144 | 141 | |
|
145 | 142 | [[package]] |
|
146 | 143 | name = "rand_core" |
|
147 | 144 | version = "0.3.1" |
|
148 | 145 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
149 | 146 | dependencies = [ |
|
150 | 147 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
151 | 148 | ] |
|
152 | 149 | |
|
153 | 150 | [[package]] |
|
154 | 151 | name = "rand_core" |
|
155 | 152 | version = "0.4.0" |
|
156 | 153 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
157 | 154 | |
|
158 | 155 | [[package]] |
|
159 | 156 | name = "rand_hc" |
|
160 | 157 | version = "0.1.0" |
|
161 | 158 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
162 | 159 | dependencies = [ |
|
163 | 160 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
164 | 161 | ] |
|
165 | 162 | |
|
166 | 163 | [[package]] |
|
167 | 164 | name = "rand_isaac" |
|
168 | 165 | version = "0.1.1" |
|
169 | 166 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
170 | 167 | dependencies = [ |
|
171 | 168 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
172 | 169 | ] |
|
173 | 170 | |
|
174 | 171 | [[package]] |
|
175 | 172 | name = "rand_jitter" |
|
176 | 173 | version = "0.1.2" |
|
177 | 174 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
178 | 175 | dependencies = [ |
|
179 | 176 | "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", |
|
180 | 177 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
181 | 178 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", |
|
182 | 179 | ] |
|
183 | 180 | |
|
184 | 181 | [[package]] |
|
185 | 182 | name = "rand_os" |
|
186 | 183 | version = "0.1.2" |
|
187 | 184 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
188 | 185 | dependencies = [ |
|
189 | 186 | "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", |
|
190 | 187 | "fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
191 | 188 | "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", |
|
192 | 189 | "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
193 | 190 | "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
194 | 191 | "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", |
|
195 | 192 | ] |
|
196 | 193 | |
|
197 | 194 | [[package]] |
|
198 | 195 | name = "rand_pcg" |
|
199 | 196 | version = "0.1.1" |
|
200 | 197 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
201 | 198 | dependencies = [ |
|
202 | 199 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
203 | 200 | "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", |
|
204 | 201 | ] |
|
205 | 202 | |
|
206 | 203 | [[package]] |
|
207 | 204 | name = "rand_xorshift" |
|
208 | 205 | version = "0.1.1" |
|
209 | 206 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
210 | 207 | dependencies = [ |
|
211 | 208 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
212 | 209 | ] |
|
213 | 210 | |
|
214 | 211 | [[package]] |
|
215 | 212 | name = "rdrand" |
|
216 | 213 | version = "0.4.0" |
|
217 | 214 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
218 | 215 | dependencies = [ |
|
219 | 216 | "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", |
|
220 | 217 | ] |
|
221 | 218 | |
|
222 | 219 | [[package]] |
|
223 | 220 | name = "regex" |
|
224 | 221 | version = "1.1.0" |
|
225 | 222 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
226 | 223 | dependencies = [ |
|
227 | 224 | "aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", |
|
228 |
"memchr 2. |
|
|
225 | "memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", | |
|
229 | 226 | "regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", |
|
230 | 227 | "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", |
|
231 | 228 | "utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", |
|
232 | 229 | ] |
|
233 | 230 | |
|
234 | 231 | [[package]] |
|
235 | 232 | name = "regex-syntax" |
|
236 | 233 | version = "0.6.4" |
|
237 | 234 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
238 | 235 | dependencies = [ |
|
239 | 236 | "ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", |
|
240 | 237 | ] |
|
241 | 238 | |
|
242 | 239 | [[package]] |
|
243 | 240 | name = "rustc_version" |
|
244 | 241 | version = "0.2.3" |
|
245 | 242 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
246 | 243 | dependencies = [ |
|
247 | 244 | "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
248 | 245 | ] |
|
249 | 246 | |
|
250 | 247 | [[package]] |
|
251 | 248 | name = "semver" |
|
252 | 249 | version = "0.9.0" |
|
253 | 250 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
254 | 251 | dependencies = [ |
|
255 | 252 | "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
256 | 253 | ] |
|
257 | 254 | |
|
258 | 255 | [[package]] |
|
259 | 256 | name = "semver-parser" |
|
260 | 257 | version = "0.7.0" |
|
261 | 258 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
262 | 259 | |
|
263 | 260 | [[package]] |
|
264 | 261 | name = "thread_local" |
|
265 | 262 | version = "0.3.6" |
|
266 | 263 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
267 | 264 | dependencies = [ |
|
268 | 265 | "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
269 | 266 | ] |
|
270 | 267 | |
|
271 | 268 | [[package]] |
|
272 | 269 | name = "ucd-util" |
|
273 | 270 | version = "0.1.3" |
|
274 | 271 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
275 | 272 | |
|
276 | 273 | [[package]] |
|
277 | 274 | name = "utf8-ranges" |
|
278 | 275 | version = "1.0.2" |
|
279 | 276 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
280 | 277 | |
|
281 | 278 | [[package]] |
|
282 | name = "version_check" | |
|
283 | version = "0.1.5" | |
|
284 | source = "registry+https://github.com/rust-lang/crates.io-index" | |
|
285 | ||
|
286 | [[package]] | |
|
287 | 279 | name = "winapi" |
|
288 | 280 | version = "0.3.6" |
|
289 | 281 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
290 | 282 | dependencies = [ |
|
291 | 283 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
292 | 284 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", |
|
293 | 285 | ] |
|
294 | 286 | |
|
295 | 287 | [[package]] |
|
296 | 288 | name = "winapi-i686-pc-windows-gnu" |
|
297 | 289 | version = "0.4.0" |
|
298 | 290 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
299 | 291 | |
|
300 | 292 | [[package]] |
|
301 | 293 | name = "winapi-x86_64-pc-windows-gnu" |
|
302 | 294 | version = "0.4.0" |
|
303 | 295 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
304 | 296 | |
|
305 | 297 | [metadata] |
|
306 | 298 | "checksum aho-corasick 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1e9a933f4e58658d7b12defcf96dc5c720f20832deebe3e0a19efd3b6aaeeb9e" |
|
307 | 299 | "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" |
|
308 | 300 | "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" |
|
309 | "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" | |
|
301 | "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" | |
|
310 | 302 | "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" |
|
311 | 303 | "checksum cpython 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b489034e723e7f5109fecd19b719e664f89ef925be785885252469e9822fa940" |
|
312 | 304 | "checksum fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81f7f8eb465745ea9b02e2704612a9946a59fa40572086c6fd49d6ddcf30bf31" |
|
313 | 305 | "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" |
|
314 | 306 | "checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74" |
|
315 |
"checksum memchr 2. |
|
|
307 | "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" | |
|
316 | 308 | "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" |
|
317 | 309 | "checksum python27-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56114c37d4dca82526d74009df7782a28c871ac9d36b19d4cb9e67672258527e" |
|
318 | 310 | "checksum python3-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "61e4aac43f833fd637e429506cb2ac9d7df672c4b68f2eaaa163649b7fdc0444" |
|
319 | 311 | "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" |
|
320 | 312 | "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" |
|
321 | 313 | "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" |
|
322 | 314 | "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" |
|
323 | 315 | "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" |
|
324 | 316 | "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" |
|
325 | 317 | "checksum rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "080723c6145e37503a2224f801f252e14ac5531cb450f4502698542d188cb3c0" |
|
326 | 318 | "checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d" |
|
327 | 319 | "checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" |
|
328 | 320 | "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" |
|
329 | 321 | "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" |
|
330 | 322 | "checksum regex 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "37e7cbbd370869ce2e8dff25c7018702d10b21a20ef7135316f8daecd6c25b7f" |
|
331 | 323 | "checksum regex-syntax 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4e47a2ed29da7a9e1960e1639e7a982e6edc6d49be308a3b02daf511504a16d1" |
|
332 | 324 | "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" |
|
333 | 325 | "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" |
|
334 | 326 | "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" |
|
335 | 327 | "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" |
|
336 | 328 | "checksum ucd-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535c204ee4d8434478593480b8f86ab45ec9aae0e83c568ca81abf0fd0e88f86" |
|
337 | 329 | "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" |
|
338 | "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" | |
|
339 | 330 | "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" |
|
340 | 331 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" |
|
341 | 332 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" |
@@ -1,71 +1,75 b'' | |||
|
1 | 1 | // Copyright 2018 Georges Racinet <gracinet@anybox.fr> |
|
2 | 2 | // |
|
3 | 3 | // This software may be used and distributed according to the terms of the |
|
4 | 4 | // GNU General Public License version 2 or any later version. |
|
5 | 5 | extern crate byteorder; |
|
6 | 6 | extern crate memchr; |
|
7 | 7 | |
|
8 | 8 | mod ancestors; |
|
9 | 9 | pub mod dagops; |
|
10 | 10 | pub use ancestors::{AncestorsIterator, LazyAncestors, MissingAncestors}; |
|
11 | mod dirstate; | |
|
12 | pub mod discovery; | |
|
11 | 13 |
pub mod testing; |
|
12 | pub mod discovery; | |
|
14 | pub use dirstate::{ | |
|
15 | pack_dirstate, parse_dirstate, CopyVec, CopyVecEntry, DirstateEntry, | |
|
16 | DirstateParents, DirstateVec, | |
|
17 | }; | |
|
13 | 18 | |
|
14 | 19 | /// Mercurial revision numbers |
|
15 | 20 | /// |
|
16 | 21 | /// As noted in revlog.c, revision numbers are actually encoded in |
|
17 | 22 | /// 4 bytes, and are liberally converted to ints, whence the i32 |
|
18 | 23 | pub type Revision = i32; |
|
19 | 24 | |
|
20 | ||
|
21 | 25 | /// Marker expressing the absence of a parent |
|
22 | 26 | /// |
|
23 | 27 | /// Independently of the actual representation, `NULL_REVISION` is guaranteed |
|
24 | 28 | /// to be smaller that all existing revisions. |
|
25 | 29 | pub const NULL_REVISION: Revision = -1; |
|
26 | 30 | |
|
27 | 31 | /// Same as `mercurial.node.wdirrev` |
|
28 | 32 | /// |
|
29 | 33 | /// This is also equal to `i32::max_value()`, but it's better to spell |
|
30 | 34 | /// it out explicitely, same as in `mercurial.node` |
|
31 | 35 | pub const WORKING_DIRECTORY_REVISION: Revision = 0x7fffffff; |
|
32 | 36 | |
|
33 | 37 | /// The simplest expression of what we need of Mercurial DAGs. |
|
34 | 38 | pub trait Graph { |
|
35 | 39 | /// Return the two parents of the given `Revision`. |
|
36 | 40 | /// |
|
37 | 41 | /// Each of the parents can be independently `NULL_REVISION` |
|
38 | 42 | fn parents(&self, Revision) -> Result<[Revision; 2], GraphError>; |
|
39 | 43 | } |
|
40 | 44 | |
|
41 | 45 | #[derive(Clone, Debug, PartialEq)] |
|
42 | 46 | pub enum GraphError { |
|
43 | 47 | ParentOutOfRange(Revision), |
|
44 | 48 | WorkingDirectoryUnsupported, |
|
45 | 49 | } |
|
46 | 50 | |
|
47 | 51 | #[derive(Clone, Debug, PartialEq)] |
|
48 | 52 | pub enum DirstateParseError { |
|
49 | 53 | TooLittleData, |
|
50 | 54 | Overflow, |
|
51 | 55 | CorruptedEntry(String), |
|
52 | 56 | } |
|
53 | 57 | |
|
54 | 58 | #[derive(Debug, PartialEq)] |
|
55 | 59 | pub enum DirstatePackError { |
|
56 | 60 | CorruptedEntry(String), |
|
57 | 61 | CorruptedParent, |
|
58 | 62 | BadSize(usize, usize), |
|
59 | 63 | } |
|
60 | 64 | |
|
61 | 65 | impl From<std::io::Error> for DirstatePackError { |
|
62 | 66 | fn from(e: std::io::Error) -> Self { |
|
63 | 67 | DirstatePackError::CorruptedEntry(e.to_string()) |
|
64 | 68 | } |
|
65 | 69 | } |
|
66 | 70 | |
|
67 | 71 | impl From<std::io::Error> for DirstateParseError { |
|
68 | 72 | fn from(e: std::io::Error) -> Self { |
|
69 | 73 | DirstateParseError::CorruptedEntry(e.to_string()) |
|
70 | 74 | } |
|
71 | 75 | } |
@@ -1,47 +1,50 b'' | |||
|
1 | 1 | // lib.rs |
|
2 | 2 | // |
|
3 | 3 | // Copyright 2018 Georges Racinet <gracinet@anybox.fr> |
|
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 | //! Python bindings of `hg-core` objects using the `cpython` crate. |
|
9 | 9 | //! Once compiled, the resulting single shared library object can be placed in |
|
10 | 10 | //! the `mercurial` package directly as `rustext.so` or `rustext.dll`. |
|
11 | 11 | //! It holds several modules, so that from the point of view of Python, |
|
12 | 12 | //! it behaves as the `cext` package. |
|
13 | 13 | //! |
|
14 | 14 | //! Example: |
|
15 | 15 | //! |
|
16 | 16 | //! ```text |
|
17 | 17 | //! >>> from mercurial.rustext import ancestor |
|
18 | 18 | //! >>> ancestor.__doc__ |
|
19 | 19 | //! 'Generic DAG ancestor algorithms - Rust implementation' |
|
20 | 20 | //! ``` |
|
21 | 21 | |
|
22 | 22 | #[macro_use] |
|
23 | 23 | extern crate cpython; |
|
24 | 24 | extern crate hg; |
|
25 | 25 | extern crate libc; |
|
26 | extern crate python27_sys; | |
|
26 | 27 | |
|
27 | 28 | pub mod ancestors; |
|
28 | 29 | mod cindex; |
|
29 | 30 | mod conversion; |
|
30 | 31 | pub mod dagops; |
|
31 | 32 | pub mod discovery; |
|
32 | 33 | pub mod exceptions; |
|
34 | pub mod dirstate; | |
|
33 | 35 | |
|
34 | 36 | py_module_initializer!(rustext, initrustext, PyInit_rustext, |py, m| { |
|
35 | 37 | m.add( |
|
36 | 38 | py, |
|
37 | 39 | "__doc__", |
|
38 | 40 | "Mercurial core concepts - Rust implementation", |
|
39 | 41 | )?; |
|
40 | 42 | |
|
41 | 43 | let dotted_name: String = m.get(py, "__name__")?.extract(py)?; |
|
42 | 44 | m.add(py, "ancestor", ancestors::init_module(py, &dotted_name)?)?; |
|
43 | 45 | m.add(py, "dagop", dagops::init_module(py, &dotted_name)?)?; |
|
44 | 46 | m.add(py, "discovery", discovery::init_module(py, &dotted_name)?)?; |
|
47 | m.add(py, "dirstate", dirstate::init_module(py, &dotted_name)?)?; | |
|
45 | 48 | m.add(py, "GraphError", py.get_type::<exceptions::GraphError>())?; |
|
46 | 49 | Ok(()) |
|
47 | 50 | }); |
General Comments 0
You need to be logged in to leave comments.
Login now