##// END OF EJS Templates
rust-dirstate: architecture independence fix...
Georges Racinet -
r42600:4e4fa3a9 default
parent child Browse files
Show More
@@ -1,227 +1,227 b''
1 1 // dirstate.rs
2 2 //
3 3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
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 //! Bindings for the `hg::dirstate` module provided by the
9 9 //! `hg-core` package.
10 10 //!
11 11 //! From Python, this will be seen as `mercurial.rustext.dirstate`
12 12
13 13 use cpython::{
14 14 exc, PyBytes, PyDict, PyErr, PyInt, PyModule, PyObject, PyResult,
15 15 PySequence, PythonObject, PyTuple, Python, ToPyObject,
16 16 };
17 17 use hg::{
18 18 pack_dirstate, parse_dirstate, CopyVecEntry, DirstateEntry,
19 19 DirstatePackError, DirstateParents, DirstateParseError, DirstateVec,
20 20 };
21 21 use std::collections::HashMap;
22 22 use std::ffi::CStr;
23 23 #[cfg(feature = "python27")]
24 24 extern crate python27_sys as python_sys;
25 25 #[cfg(feature = "python3")]
26 26 extern crate python3_sys as python_sys;
27 27 use self::python_sys::PyCapsule_Import;
28 28 use libc::{c_char, c_int};
29 29 use std::mem::transmute;
30 30
31 31 /// C code uses a custom `dirstate_tuple` type, checks in multiple instances
32 32 /// for this type, and raises a Python `Exception` if the check does not pass.
33 33 /// Because this type differs only in name from the regular Python tuple, it
34 34 /// would be a good idea in the near future to remove it entirely to allow
35 35 /// for a pure Python tuple of the same effective structure to be used,
36 36 /// rendering this type and the capsule below useless.
37 37 type MakeDirstateTupleFn = extern "C" fn(
38 38 state: c_char,
39 39 mode: c_int,
40 40 size: c_int,
41 41 mtime: c_int,
42 42 ) -> PyObject;
43 43
44 44 /// This is largely a copy/paste from cindex.rs, pending the merge of a
45 45 /// `py_capsule_fn!` macro in the rust-cpython project:
46 46 /// https://github.com/dgrunwald/rust-cpython/pull/169
47 47 fn decapsule_make_dirstate_tuple(py: Python) -> PyResult<MakeDirstateTupleFn> {
48 48 unsafe {
49 49 let caps_name = CStr::from_bytes_with_nul_unchecked(
50 50 b"mercurial.cext.parsers.make_dirstate_tuple_CAPI\0",
51 51 );
52 52 let from_caps = PyCapsule_Import(caps_name.as_ptr(), 0);
53 53 if from_caps.is_null() {
54 54 return Err(PyErr::fetch(py));
55 55 }
56 56 Ok(transmute(from_caps))
57 57 }
58 58 }
59 59
60 60 fn parse_dirstate_wrapper(
61 61 py: Python,
62 62 dmap: PyDict,
63 63 copymap: PyDict,
64 64 st: PyBytes,
65 65 ) -> PyResult<PyTuple> {
66 66 match parse_dirstate(st.data(py)) {
67 67 Ok((parents, dirstate_vec, copies)) => {
68 68 for (filename, entry) in dirstate_vec {
69 69 dmap.set_item(
70 70 py,
71 71 PyBytes::new(py, &filename[..]),
72 72 decapsule_make_dirstate_tuple(py)?(
73 entry.state,
73 entry.state as c_char,
74 74 entry.mode,
75 75 entry.size,
76 76 entry.mtime,
77 77 ),
78 78 )?;
79 79 }
80 80 for CopyVecEntry { path, copy_path } in copies {
81 81 copymap.set_item(
82 82 py,
83 83 PyBytes::new(py, path),
84 84 PyBytes::new(py, copy_path),
85 85 )?;
86 86 }
87 87 Ok((PyBytes::new(py, parents.p1), PyBytes::new(py, parents.p2))
88 88 .to_py_object(py))
89 89 }
90 90 Err(e) => Err(PyErr::new::<exc::ValueError, _>(
91 91 py,
92 92 match e {
93 93 DirstateParseError::TooLittleData => {
94 94 "too little data for parents".to_string()
95 95 }
96 96 DirstateParseError::Overflow => {
97 97 "overflow in dirstate".to_string()
98 98 }
99 99 DirstateParseError::CorruptedEntry(e) => e,
100 100 },
101 101 )),
102 102 }
103 103 }
104 104
105 105 fn pack_dirstate_wrapper(
106 106 py: Python,
107 107 dmap: PyDict,
108 108 copymap: PyDict,
109 109 pl: PyTuple,
110 110 now: PyInt,
111 111 ) -> PyResult<PyBytes> {
112 112 let p1 = pl.get_item(py, 0).extract::<PyBytes>(py)?;
113 113 let p1: &[u8] = p1.data(py);
114 114 let p2 = pl.get_item(py, 1).extract::<PyBytes>(py)?;
115 115 let p2: &[u8] = p2.data(py);
116 116
117 117 let dirstate_vec: Result<DirstateVec, PyErr> = dmap
118 118 .items(py)
119 119 .iter()
120 120 .map(|(filename, stats)| {
121 121 let stats = stats.extract::<PySequence>(py)?;
122 122 let state = stats.get_item(py, 0)?.extract::<PyBytes>(py)?;
123 123 let state = state.data(py)[0] as i8;
124 124 let mode = stats.get_item(py, 1)?.extract(py)?;
125 125 let size = stats.get_item(py, 2)?.extract(py)?;
126 126 let mtime = stats.get_item(py, 3)?.extract(py)?;
127 127 let filename = filename.extract::<PyBytes>(py)?;
128 128 let filename = filename.data(py);
129 129 Ok((
130 130 filename.to_owned(),
131 131 DirstateEntry {
132 132 state,
133 133 mode,
134 134 size,
135 135 mtime,
136 136 },
137 137 ))
138 138 })
139 139 .collect();
140 140
141 141 let copies: Result<HashMap<Vec<u8>, Vec<u8>>, PyErr> = copymap
142 142 .items(py)
143 143 .iter()
144 144 .map(|(key, value)| {
145 145 Ok((
146 146 key.extract::<PyBytes>(py)?.data(py).to_owned(),
147 147 value.extract::<PyBytes>(py)?.data(py).to_owned(),
148 148 ))
149 149 })
150 150 .collect();
151 151
152 152 match pack_dirstate(
153 153 &dirstate_vec?,
154 154 &copies?,
155 155 DirstateParents { p1, p2 },
156 156 now.as_object().extract::<i32>(py)?,
157 157 ) {
158 158 Ok((packed, new_dirstate_vec)) => {
159 159 for (
160 160 filename,
161 161 DirstateEntry {
162 162 state,
163 163 mode,
164 164 size,
165 165 mtime,
166 166 },
167 167 ) in new_dirstate_vec
168 168 {
169 169 dmap.set_item(
170 170 py,
171 171 PyBytes::new(py, &filename[..]),
172 172 decapsule_make_dirstate_tuple(py)?(
173 state, mode, size, mtime,
173 state as c_char, mode, size, mtime,
174 174 ),
175 175 )?;
176 176 }
177 177 Ok(PyBytes::new(py, &packed))
178 178 }
179 179 Err(error) => Err(PyErr::new::<exc::ValueError, _>(
180 180 py,
181 181 match error {
182 182 DirstatePackError::CorruptedParent => {
183 183 "expected a 20-byte hash".to_string()
184 184 }
185 185 DirstatePackError::CorruptedEntry(e) => e,
186 186 DirstatePackError::BadSize(expected, actual) => {
187 187 format!("bad dirstate size: {} != {}", actual, expected)
188 188 }
189 189 },
190 190 )),
191 191 }
192 192 }
193 193
194 194 /// Create the module, with `__package__` given from parent
195 195 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
196 196 let dotted_name = &format!("{}.dirstate", package);
197 197 let m = PyModule::new(py, dotted_name)?;
198 198 m.add(py, "__package__", package)?;
199 199 m.add(py, "__doc__", "Dirstate - Rust implementation")?;
200 200 m.add(
201 201 py,
202 202 "parse_dirstate",
203 203 py_fn!(
204 204 py,
205 205 parse_dirstate_wrapper(dmap: PyDict, copymap: PyDict, st: PyBytes)
206 206 ),
207 207 )?;
208 208 m.add(
209 209 py,
210 210 "pack_dirstate",
211 211 py_fn!(
212 212 py,
213 213 pack_dirstate_wrapper(
214 214 dmap: PyDict,
215 215 copymap: PyDict,
216 216 pl: PyTuple,
217 217 now: PyInt
218 218 )
219 219 ),
220 220 )?;
221 221
222 222 let sys = PyModule::import(py, "sys")?;
223 223 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
224 224 sys_modules.set_item(py, dotted_name, &m)?;
225 225
226 226 Ok(m)
227 227 }
General Comments 0
You need to be logged in to leave comments. Login now