##// END OF EJS Templates
rust-cpython: don't swallow the dirstate error message...
Raphaël Gomès -
r52511:ccf5c440 stable
parent child Browse files
Show More
@@ -1,556 +1,556 b''
1 // dirstate_map.rs
1 // dirstate_map.rs
2 //
2 //
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 //
4 //
5 // This software may be used and distributed according to the terms of the
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.
6 // GNU General Public License version 2 or any later version.
7
7
8 //! Bindings for the `hg::dirstate::dirstate_map` file provided by the
8 //! Bindings for the `hg::dirstate::dirstate_map` file provided by the
9 //! `hg-core` package.
9 //! `hg-core` package.
10
10
11 use std::cell::{RefCell, RefMut};
11 use std::cell::{RefCell, RefMut};
12
12
13 use cpython::{
13 use cpython::{
14 exc, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList, PyNone, PyObject,
14 exc, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList, PyNone, PyObject,
15 PyResult, Python, PythonObject, ToPyObject, UnsafePyLeaked,
15 PyResult, Python, PythonObject, ToPyObject, UnsafePyLeaked,
16 };
16 };
17 use hg::dirstate::{ParentFileData, TruncatedTimestamp};
17 use hg::dirstate::{ParentFileData, TruncatedTimestamp};
18
18
19 use crate::{
19 use crate::{
20 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
20 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
21 dirstate::item::DirstateItem,
21 dirstate::item::DirstateItem,
22 pybytes_deref::PyBytesDeref,
22 pybytes_deref::PyBytesDeref,
23 };
23 };
24 use hg::{
24 use hg::{
25 dirstate::StateMapIter, dirstate_tree::dirstate_map::DirstateMapWriteMode,
25 dirstate::StateMapIter, dirstate_tree::dirstate_map::DirstateMapWriteMode,
26 dirstate_tree::on_disk::DirstateV2ParseError,
26 dirstate_tree::on_disk::DirstateV2ParseError,
27 dirstate_tree::owning::OwningDirstateMap, revlog::Node,
27 dirstate_tree::owning::OwningDirstateMap, revlog::Node,
28 utils::files::normalize_case, utils::hg_path::HgPath, DirstateEntry,
28 utils::files::normalize_case, utils::hg_path::HgPath, DirstateEntry,
29 DirstateError, DirstateParents,
29 DirstateError, DirstateParents,
30 };
30 };
31
31
32 // TODO
32 // TODO
33 // This object needs to share references to multiple members of its Rust
33 // This object needs to share references to multiple members of its Rust
34 // inner struct, namely `copy_map`, `dirs` and `all_dirs`.
34 // inner struct, namely `copy_map`, `dirs` and `all_dirs`.
35 // Right now `CopyMap` is done, but it needs to have an explicit reference
35 // Right now `CopyMap` is done, but it needs to have an explicit reference
36 // to `RustDirstateMap` which itself needs to have an encapsulation for
36 // to `RustDirstateMap` which itself needs to have an encapsulation for
37 // every method in `CopyMap` (copymapcopy, etc.).
37 // every method in `CopyMap` (copymapcopy, etc.).
38 // This is ugly and hard to maintain.
38 // This is ugly and hard to maintain.
39 // The same logic applies to `dirs` and `all_dirs`, however the `Dirs`
39 // The same logic applies to `dirs` and `all_dirs`, however the `Dirs`
40 // `py_class!` is already implemented and does not mention
40 // `py_class!` is already implemented and does not mention
41 // `RustDirstateMap`, rightfully so.
41 // `RustDirstateMap`, rightfully so.
42 // All attributes also have to have a separate refcount data attribute for
42 // All attributes also have to have a separate refcount data attribute for
43 // leaks, with all methods that go along for reference sharing.
43 // leaks, with all methods that go along for reference sharing.
44 py_class!(pub class DirstateMap |py| {
44 py_class!(pub class DirstateMap |py| {
45 @shared data inner: OwningDirstateMap;
45 @shared data inner: OwningDirstateMap;
46
46
47 /// Returns a `(dirstate_map, parents)` tuple
47 /// Returns a `(dirstate_map, parents)` tuple
48 @staticmethod
48 @staticmethod
49 def new_v1(
49 def new_v1(
50 on_disk: PyBytes,
50 on_disk: PyBytes,
51 identity: Option<u64>,
51 identity: Option<u64>,
52 ) -> PyResult<PyObject> {
52 ) -> PyResult<PyObject> {
53 let on_disk = PyBytesDeref::new(py, on_disk);
53 let on_disk = PyBytesDeref::new(py, on_disk);
54 let (map, parents) = OwningDirstateMap::new_v1(on_disk, identity)
54 let (map, parents) = OwningDirstateMap::new_v1(on_disk, identity)
55 .map_err(|e| dirstate_error(py, e))?;
55 .map_err(|e| dirstate_error(py, e))?;
56 let map = Self::create_instance(py, map)?;
56 let map = Self::create_instance(py, map)?;
57 let p1 = PyBytes::new(py, parents.p1.as_bytes());
57 let p1 = PyBytes::new(py, parents.p1.as_bytes());
58 let p2 = PyBytes::new(py, parents.p2.as_bytes());
58 let p2 = PyBytes::new(py, parents.p2.as_bytes());
59 let parents = (p1, p2);
59 let parents = (p1, p2);
60 Ok((map, parents).to_py_object(py).into_object())
60 Ok((map, parents).to_py_object(py).into_object())
61 }
61 }
62
62
63 /// Returns a DirstateMap
63 /// Returns a DirstateMap
64 @staticmethod
64 @staticmethod
65 def new_v2(
65 def new_v2(
66 on_disk: PyBytes,
66 on_disk: PyBytes,
67 data_size: usize,
67 data_size: usize,
68 tree_metadata: PyBytes,
68 tree_metadata: PyBytes,
69 uuid: PyBytes,
69 uuid: PyBytes,
70 identity: Option<u64>,
70 identity: Option<u64>,
71 ) -> PyResult<PyObject> {
71 ) -> PyResult<PyObject> {
72 let dirstate_error = |e: DirstateError| {
72 let dirstate_error = |e: DirstateError| {
73 PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e))
73 PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e))
74 };
74 };
75 let on_disk = PyBytesDeref::new(py, on_disk);
75 let on_disk = PyBytesDeref::new(py, on_disk);
76 let uuid = uuid.data(py);
76 let uuid = uuid.data(py);
77 let map = OwningDirstateMap::new_v2(
77 let map = OwningDirstateMap::new_v2(
78 on_disk,
78 on_disk,
79 data_size,
79 data_size,
80 tree_metadata.data(py),
80 tree_metadata.data(py),
81 uuid.to_owned(),
81 uuid.to_owned(),
82 identity,
82 identity,
83 ).map_err(dirstate_error)?;
83 ).map_err(dirstate_error)?;
84 let map = Self::create_instance(py, map)?;
84 let map = Self::create_instance(py, map)?;
85 Ok(map.into_object())
85 Ok(map.into_object())
86 }
86 }
87
87
88 /// Returns an empty DirstateMap. Only used for a new dirstate.
88 /// Returns an empty DirstateMap. Only used for a new dirstate.
89 @staticmethod
89 @staticmethod
90 def new_empty() -> PyResult<PyObject> {
90 def new_empty() -> PyResult<PyObject> {
91 let map = OwningDirstateMap::new_empty(vec![]);
91 let map = OwningDirstateMap::new_empty(vec![]);
92 let map = Self::create_instance(py, map)?;
92 let map = Self::create_instance(py, map)?;
93 Ok(map.into_object())
93 Ok(map.into_object())
94 }
94 }
95
95
96 def clear(&self) -> PyResult<PyObject> {
96 def clear(&self) -> PyResult<PyObject> {
97 self.inner(py).borrow_mut().clear();
97 self.inner(py).borrow_mut().clear();
98 Ok(py.None())
98 Ok(py.None())
99 }
99 }
100
100
101 def get(
101 def get(
102 &self,
102 &self,
103 key: PyObject,
103 key: PyObject,
104 default: Option<PyObject> = None
104 default: Option<PyObject> = None
105 ) -> PyResult<Option<PyObject>> {
105 ) -> PyResult<Option<PyObject>> {
106 let key = key.extract::<PyBytes>(py)?;
106 let key = key.extract::<PyBytes>(py)?;
107 match self
107 match self
108 .inner(py)
108 .inner(py)
109 .borrow()
109 .borrow()
110 .get(HgPath::new(key.data(py)))
110 .get(HgPath::new(key.data(py)))
111 .map_err(|e| v2_error(py, e))?
111 .map_err(|e| v2_error(py, e))?
112 {
112 {
113 Some(entry) => {
113 Some(entry) => {
114 Ok(Some(DirstateItem::new_as_pyobject(py, entry)?))
114 Ok(Some(DirstateItem::new_as_pyobject(py, entry)?))
115 },
115 },
116 None => Ok(default)
116 None => Ok(default)
117 }
117 }
118 }
118 }
119
119
120 def set_tracked(&self, f: PyObject) -> PyResult<PyBool> {
120 def set_tracked(&self, f: PyObject) -> PyResult<PyBool> {
121 let bytes = f.extract::<PyBytes>(py)?;
121 let bytes = f.extract::<PyBytes>(py)?;
122 let path = HgPath::new(bytes.data(py));
122 let path = HgPath::new(bytes.data(py));
123 let res = self.inner(py).borrow_mut().set_tracked(path);
123 let res = self.inner(py).borrow_mut().set_tracked(path);
124 let was_tracked = res.map_err(|_| PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))?;
124 let was_tracked = res.map_err(|_| PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))?;
125 Ok(was_tracked.to_py_object(py))
125 Ok(was_tracked.to_py_object(py))
126 }
126 }
127
127
128 def set_untracked(&self, f: PyObject) -> PyResult<PyBool> {
128 def set_untracked(&self, f: PyObject) -> PyResult<PyBool> {
129 let bytes = f.extract::<PyBytes>(py)?;
129 let bytes = f.extract::<PyBytes>(py)?;
130 let path = HgPath::new(bytes.data(py));
130 let path = HgPath::new(bytes.data(py));
131 let res = self.inner(py).borrow_mut().set_untracked(path);
131 let res = self.inner(py).borrow_mut().set_untracked(path);
132 let was_tracked = res.map_err(|_| PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))?;
132 let was_tracked = res.map_err(|_| PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))?;
133 Ok(was_tracked.to_py_object(py))
133 Ok(was_tracked.to_py_object(py))
134 }
134 }
135
135
136 def set_clean(
136 def set_clean(
137 &self,
137 &self,
138 f: PyObject,
138 f: PyObject,
139 mode: u32,
139 mode: u32,
140 size: u32,
140 size: u32,
141 mtime: (i64, u32, bool)
141 mtime: (i64, u32, bool)
142 ) -> PyResult<PyNone> {
142 ) -> PyResult<PyNone> {
143 let (mtime_s, mtime_ns, second_ambiguous) = mtime;
143 let (mtime_s, mtime_ns, second_ambiguous) = mtime;
144 let timestamp = TruncatedTimestamp::new_truncate(
144 let timestamp = TruncatedTimestamp::new_truncate(
145 mtime_s, mtime_ns, second_ambiguous
145 mtime_s, mtime_ns, second_ambiguous
146 );
146 );
147 let bytes = f.extract::<PyBytes>(py)?;
147 let bytes = f.extract::<PyBytes>(py)?;
148 let path = HgPath::new(bytes.data(py));
148 let path = HgPath::new(bytes.data(py));
149 let res = self.inner(py).borrow_mut().set_clean(
149 let res = self.inner(py).borrow_mut().set_clean(
150 path, mode, size, timestamp,
150 path, mode, size, timestamp,
151 );
151 );
152 res.map_err(|_| PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))?;
152 res.map_err(|_| PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))?;
153 Ok(PyNone)
153 Ok(PyNone)
154 }
154 }
155
155
156 def set_possibly_dirty(&self, f: PyObject) -> PyResult<PyNone> {
156 def set_possibly_dirty(&self, f: PyObject) -> PyResult<PyNone> {
157 let bytes = f.extract::<PyBytes>(py)?;
157 let bytes = f.extract::<PyBytes>(py)?;
158 let path = HgPath::new(bytes.data(py));
158 let path = HgPath::new(bytes.data(py));
159 let res = self.inner(py).borrow_mut().set_possibly_dirty(path);
159 let res = self.inner(py).borrow_mut().set_possibly_dirty(path);
160 res.map_err(|_| PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))?;
160 res.map_err(|_| PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))?;
161 Ok(PyNone)
161 Ok(PyNone)
162 }
162 }
163
163
164 def reset_state(
164 def reset_state(
165 &self,
165 &self,
166 f: PyObject,
166 f: PyObject,
167 wc_tracked: bool,
167 wc_tracked: bool,
168 p1_tracked: bool,
168 p1_tracked: bool,
169 p2_info: bool,
169 p2_info: bool,
170 has_meaningful_mtime: bool,
170 has_meaningful_mtime: bool,
171 parentfiledata: Option<(u32, u32, Option<(i64, u32, bool)>)>,
171 parentfiledata: Option<(u32, u32, Option<(i64, u32, bool)>)>,
172 ) -> PyResult<PyNone> {
172 ) -> PyResult<PyNone> {
173 let mut has_meaningful_mtime = has_meaningful_mtime;
173 let mut has_meaningful_mtime = has_meaningful_mtime;
174 let parent_file_data = match parentfiledata {
174 let parent_file_data = match parentfiledata {
175 None => {
175 None => {
176 has_meaningful_mtime = false;
176 has_meaningful_mtime = false;
177 None
177 None
178 },
178 },
179 Some(data) => {
179 Some(data) => {
180 let (mode, size, mtime_info) = data;
180 let (mode, size, mtime_info) = data;
181 let mtime = if let Some(mtime_info) = mtime_info {
181 let mtime = if let Some(mtime_info) = mtime_info {
182 let (mtime_s, mtime_ns, second_ambiguous) = mtime_info;
182 let (mtime_s, mtime_ns, second_ambiguous) = mtime_info;
183 let timestamp = TruncatedTimestamp::new_truncate(
183 let timestamp = TruncatedTimestamp::new_truncate(
184 mtime_s, mtime_ns, second_ambiguous
184 mtime_s, mtime_ns, second_ambiguous
185 );
185 );
186 Some(timestamp)
186 Some(timestamp)
187 } else {
187 } else {
188 has_meaningful_mtime = false;
188 has_meaningful_mtime = false;
189 None
189 None
190 };
190 };
191 Some(ParentFileData {
191 Some(ParentFileData {
192 mode_size: Some((mode, size)),
192 mode_size: Some((mode, size)),
193 mtime,
193 mtime,
194 })
194 })
195 }
195 }
196 };
196 };
197 let bytes = f.extract::<PyBytes>(py)?;
197 let bytes = f.extract::<PyBytes>(py)?;
198 let path = HgPath::new(bytes.data(py));
198 let path = HgPath::new(bytes.data(py));
199 let res = self.inner(py).borrow_mut().reset_state(
199 let res = self.inner(py).borrow_mut().reset_state(
200 path,
200 path,
201 wc_tracked,
201 wc_tracked,
202 p1_tracked,
202 p1_tracked,
203 p2_info,
203 p2_info,
204 has_meaningful_mtime,
204 has_meaningful_mtime,
205 parent_file_data,
205 parent_file_data,
206 );
206 );
207 res.map_err(|_| PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))?;
207 res.map_err(|_| PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))?;
208 Ok(PyNone)
208 Ok(PyNone)
209 }
209 }
210
210
211 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
211 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
212 let d = d.extract::<PyBytes>(py)?;
212 let d = d.extract::<PyBytes>(py)?;
213 Ok(self.inner(py).borrow_mut()
213 Ok(self.inner(py).borrow_mut()
214 .has_tracked_dir(HgPath::new(d.data(py)))
214 .has_tracked_dir(HgPath::new(d.data(py)))
215 .map_err(|e| {
215 .map_err(|e| {
216 PyErr::new::<exc::ValueError, _>(py, e.to_string())
216 PyErr::new::<exc::ValueError, _>(py, e.to_string())
217 })?
217 })?
218 .to_py_object(py))
218 .to_py_object(py))
219 }
219 }
220
220
221 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
221 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
222 let d = d.extract::<PyBytes>(py)?;
222 let d = d.extract::<PyBytes>(py)?;
223 Ok(self.inner(py).borrow_mut()
223 Ok(self.inner(py).borrow_mut()
224 .has_dir(HgPath::new(d.data(py)))
224 .has_dir(HgPath::new(d.data(py)))
225 .map_err(|e| {
225 .map_err(|e| {
226 PyErr::new::<exc::ValueError, _>(py, e.to_string())
226 PyErr::new::<exc::ValueError, _>(py, e.to_string())
227 })?
227 })?
228 .to_py_object(py))
228 .to_py_object(py))
229 }
229 }
230
230
231 def write_v1(
231 def write_v1(
232 &self,
232 &self,
233 p1: PyObject,
233 p1: PyObject,
234 p2: PyObject,
234 p2: PyObject,
235 ) -> PyResult<PyBytes> {
235 ) -> PyResult<PyBytes> {
236 let inner = self.inner(py).borrow();
236 let inner = self.inner(py).borrow();
237 let parents = DirstateParents {
237 let parents = DirstateParents {
238 p1: extract_node_id(py, &p1)?,
238 p1: extract_node_id(py, &p1)?,
239 p2: extract_node_id(py, &p2)?,
239 p2: extract_node_id(py, &p2)?,
240 };
240 };
241 let result = inner.pack_v1(parents);
241 let result = inner.pack_v1(parents);
242 match result {
242 match result {
243 Ok(packed) => Ok(PyBytes::new(py, &packed)),
243 Ok(packed) => Ok(PyBytes::new(py, &packed)),
244 Err(_) => Err(PyErr::new::<exc::OSError, _>(
244 Err(_) => Err(PyErr::new::<exc::OSError, _>(
245 py,
245 py,
246 "Dirstate error".to_string(),
246 "Dirstate error".to_string(),
247 )),
247 )),
248 }
248 }
249 }
249 }
250
250
251 /// Returns new data together with whether that data should be appended to
251 /// Returns new data together with whether that data should be appended to
252 /// the existing data file whose content is at `self.on_disk` (True),
252 /// the existing data file whose content is at `self.on_disk` (True),
253 /// instead of written to a new data file (False).
253 /// instead of written to a new data file (False).
254 def write_v2(
254 def write_v2(
255 &self,
255 &self,
256 write_mode: usize,
256 write_mode: usize,
257 ) -> PyResult<PyObject> {
257 ) -> PyResult<PyObject> {
258 let inner = self.inner(py).borrow();
258 let inner = self.inner(py).borrow();
259 let rust_write_mode = match write_mode {
259 let rust_write_mode = match write_mode {
260 0 => DirstateMapWriteMode::Auto,
260 0 => DirstateMapWriteMode::Auto,
261 1 => DirstateMapWriteMode::ForceNewDataFile,
261 1 => DirstateMapWriteMode::ForceNewDataFile,
262 2 => DirstateMapWriteMode::ForceAppend,
262 2 => DirstateMapWriteMode::ForceAppend,
263 _ => DirstateMapWriteMode::Auto, // XXX should we error out?
263 _ => DirstateMapWriteMode::Auto, // XXX should we error out?
264 };
264 };
265 let result = inner.pack_v2(rust_write_mode);
265 let result = inner.pack_v2(rust_write_mode);
266 match result {
266 match result {
267 Ok((packed, tree_metadata, append, _old_data_size)) => {
267 Ok((packed, tree_metadata, append, _old_data_size)) => {
268 let packed = PyBytes::new(py, &packed);
268 let packed = PyBytes::new(py, &packed);
269 let tree_metadata = PyBytes::new(py, tree_metadata.as_bytes());
269 let tree_metadata = PyBytes::new(py, tree_metadata.as_bytes());
270 let tuple = (packed, tree_metadata, append);
270 let tuple = (packed, tree_metadata, append);
271 Ok(tuple.to_py_object(py).into_object())
271 Ok(tuple.to_py_object(py).into_object())
272 },
272 },
273 Err(_) => Err(PyErr::new::<exc::OSError, _>(
273 Err(e) => Err(PyErr::new::<exc::OSError, _>(
274 py,
274 py,
275 "Dirstate error".to_string(),
275 e.to_string(),
276 )),
276 )),
277 }
277 }
278 }
278 }
279
279
280 def filefoldmapasdict(&self) -> PyResult<PyDict> {
280 def filefoldmapasdict(&self) -> PyResult<PyDict> {
281 let dict = PyDict::new(py);
281 let dict = PyDict::new(py);
282 for item in self.inner(py).borrow_mut().iter() {
282 for item in self.inner(py).borrow_mut().iter() {
283 let (path, entry) = item.map_err(|e| v2_error(py, e))?;
283 let (path, entry) = item.map_err(|e| v2_error(py, e))?;
284 if !entry.removed() {
284 if !entry.removed() {
285 let key = normalize_case(path);
285 let key = normalize_case(path);
286 let value = path;
286 let value = path;
287 dict.set_item(
287 dict.set_item(
288 py,
288 py,
289 PyBytes::new(py, key.as_bytes()).into_object(),
289 PyBytes::new(py, key.as_bytes()).into_object(),
290 PyBytes::new(py, value.as_bytes()).into_object(),
290 PyBytes::new(py, value.as_bytes()).into_object(),
291 )?;
291 )?;
292 }
292 }
293 }
293 }
294 Ok(dict)
294 Ok(dict)
295 }
295 }
296
296
297 def __len__(&self) -> PyResult<usize> {
297 def __len__(&self) -> PyResult<usize> {
298 Ok(self.inner(py).borrow().len())
298 Ok(self.inner(py).borrow().len())
299 }
299 }
300
300
301 def __contains__(&self, key: PyObject) -> PyResult<bool> {
301 def __contains__(&self, key: PyObject) -> PyResult<bool> {
302 let key = key.extract::<PyBytes>(py)?;
302 let key = key.extract::<PyBytes>(py)?;
303 self.inner(py)
303 self.inner(py)
304 .borrow()
304 .borrow()
305 .contains_key(HgPath::new(key.data(py)))
305 .contains_key(HgPath::new(key.data(py)))
306 .map_err(|e| v2_error(py, e))
306 .map_err(|e| v2_error(py, e))
307 }
307 }
308
308
309 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
309 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
310 let key = key.extract::<PyBytes>(py)?;
310 let key = key.extract::<PyBytes>(py)?;
311 let key = HgPath::new(key.data(py));
311 let key = HgPath::new(key.data(py));
312 match self
312 match self
313 .inner(py)
313 .inner(py)
314 .borrow()
314 .borrow()
315 .get(key)
315 .get(key)
316 .map_err(|e| v2_error(py, e))?
316 .map_err(|e| v2_error(py, e))?
317 {
317 {
318 Some(entry) => {
318 Some(entry) => {
319 Ok(DirstateItem::new_as_pyobject(py, entry)?)
319 Ok(DirstateItem::new_as_pyobject(py, entry)?)
320 },
320 },
321 None => Err(PyErr::new::<exc::KeyError, _>(
321 None => Err(PyErr::new::<exc::KeyError, _>(
322 py,
322 py,
323 String::from_utf8_lossy(key.as_bytes()),
323 String::from_utf8_lossy(key.as_bytes()),
324 )),
324 )),
325 }
325 }
326 }
326 }
327
327
328 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
328 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
329 let leaked_ref = self.inner(py).leak_immutable();
329 let leaked_ref = self.inner(py).leak_immutable();
330 DirstateMapKeysIterator::from_inner(
330 DirstateMapKeysIterator::from_inner(
331 py,
331 py,
332 unsafe { leaked_ref.map(py, |o| o.iter()) },
332 unsafe { leaked_ref.map(py, |o| o.iter()) },
333 )
333 )
334 }
334 }
335
335
336 def items(&self) -> PyResult<DirstateMapItemsIterator> {
336 def items(&self) -> PyResult<DirstateMapItemsIterator> {
337 let leaked_ref = self.inner(py).leak_immutable();
337 let leaked_ref = self.inner(py).leak_immutable();
338 DirstateMapItemsIterator::from_inner(
338 DirstateMapItemsIterator::from_inner(
339 py,
339 py,
340 unsafe { leaked_ref.map(py, |o| o.iter()) },
340 unsafe { leaked_ref.map(py, |o| o.iter()) },
341 )
341 )
342 }
342 }
343
343
344 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
344 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
345 let leaked_ref = self.inner(py).leak_immutable();
345 let leaked_ref = self.inner(py).leak_immutable();
346 DirstateMapKeysIterator::from_inner(
346 DirstateMapKeysIterator::from_inner(
347 py,
347 py,
348 unsafe { leaked_ref.map(py, |o| o.iter()) },
348 unsafe { leaked_ref.map(py, |o| o.iter()) },
349 )
349 )
350 }
350 }
351
351
352 // TODO all copymap* methods, see docstring above
352 // TODO all copymap* methods, see docstring above
353 def copymapcopy(&self) -> PyResult<PyDict> {
353 def copymapcopy(&self) -> PyResult<PyDict> {
354 let dict = PyDict::new(py);
354 let dict = PyDict::new(py);
355 for item in self.inner(py).borrow().copy_map_iter() {
355 for item in self.inner(py).borrow().copy_map_iter() {
356 let (key, value) = item.map_err(|e| v2_error(py, e))?;
356 let (key, value) = item.map_err(|e| v2_error(py, e))?;
357 dict.set_item(
357 dict.set_item(
358 py,
358 py,
359 PyBytes::new(py, key.as_bytes()),
359 PyBytes::new(py, key.as_bytes()),
360 PyBytes::new(py, value.as_bytes()),
360 PyBytes::new(py, value.as_bytes()),
361 )?;
361 )?;
362 }
362 }
363 Ok(dict)
363 Ok(dict)
364 }
364 }
365
365
366 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
366 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
367 let key = key.extract::<PyBytes>(py)?;
367 let key = key.extract::<PyBytes>(py)?;
368 match self
368 match self
369 .inner(py)
369 .inner(py)
370 .borrow()
370 .borrow()
371 .copy_map_get(HgPath::new(key.data(py)))
371 .copy_map_get(HgPath::new(key.data(py)))
372 .map_err(|e| v2_error(py, e))?
372 .map_err(|e| v2_error(py, e))?
373 {
373 {
374 Some(copy) => Ok(PyBytes::new(py, copy.as_bytes())),
374 Some(copy) => Ok(PyBytes::new(py, copy.as_bytes())),
375 None => Err(PyErr::new::<exc::KeyError, _>(
375 None => Err(PyErr::new::<exc::KeyError, _>(
376 py,
376 py,
377 String::from_utf8_lossy(key.data(py)),
377 String::from_utf8_lossy(key.data(py)),
378 )),
378 )),
379 }
379 }
380 }
380 }
381 def copymap(&self) -> PyResult<CopyMap> {
381 def copymap(&self) -> PyResult<CopyMap> {
382 CopyMap::from_inner(py, self.clone_ref(py))
382 CopyMap::from_inner(py, self.clone_ref(py))
383 }
383 }
384
384
385 def copymaplen(&self) -> PyResult<usize> {
385 def copymaplen(&self) -> PyResult<usize> {
386 Ok(self.inner(py).borrow().copy_map_len())
386 Ok(self.inner(py).borrow().copy_map_len())
387 }
387 }
388 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
388 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
389 let key = key.extract::<PyBytes>(py)?;
389 let key = key.extract::<PyBytes>(py)?;
390 self.inner(py)
390 self.inner(py)
391 .borrow()
391 .borrow()
392 .copy_map_contains_key(HgPath::new(key.data(py)))
392 .copy_map_contains_key(HgPath::new(key.data(py)))
393 .map_err(|e| v2_error(py, e))
393 .map_err(|e| v2_error(py, e))
394 }
394 }
395 def copymapget(
395 def copymapget(
396 &self,
396 &self,
397 key: PyObject,
397 key: PyObject,
398 default: Option<PyObject>
398 default: Option<PyObject>
399 ) -> PyResult<Option<PyObject>> {
399 ) -> PyResult<Option<PyObject>> {
400 let key = key.extract::<PyBytes>(py)?;
400 let key = key.extract::<PyBytes>(py)?;
401 match self
401 match self
402 .inner(py)
402 .inner(py)
403 .borrow()
403 .borrow()
404 .copy_map_get(HgPath::new(key.data(py)))
404 .copy_map_get(HgPath::new(key.data(py)))
405 .map_err(|e| v2_error(py, e))?
405 .map_err(|e| v2_error(py, e))?
406 {
406 {
407 Some(copy) => Ok(Some(
407 Some(copy) => Ok(Some(
408 PyBytes::new(py, copy.as_bytes()).into_object(),
408 PyBytes::new(py, copy.as_bytes()).into_object(),
409 )),
409 )),
410 None => Ok(default),
410 None => Ok(default),
411 }
411 }
412 }
412 }
413 def copymapsetitem(
413 def copymapsetitem(
414 &self,
414 &self,
415 key: PyObject,
415 key: PyObject,
416 value: PyObject
416 value: PyObject
417 ) -> PyResult<PyObject> {
417 ) -> PyResult<PyObject> {
418 let key = key.extract::<PyBytes>(py)?;
418 let key = key.extract::<PyBytes>(py)?;
419 let value = value.extract::<PyBytes>(py)?;
419 let value = value.extract::<PyBytes>(py)?;
420 self.inner(py)
420 self.inner(py)
421 .borrow_mut()
421 .borrow_mut()
422 .copy_map_insert(
422 .copy_map_insert(
423 HgPath::new(key.data(py)),
423 HgPath::new(key.data(py)),
424 HgPath::new(value.data(py)),
424 HgPath::new(value.data(py)),
425 )
425 )
426 .map_err(|e| v2_error(py, e))?;
426 .map_err(|e| v2_error(py, e))?;
427 Ok(py.None())
427 Ok(py.None())
428 }
428 }
429 def copymappop(
429 def copymappop(
430 &self,
430 &self,
431 key: PyObject,
431 key: PyObject,
432 default: Option<PyObject>
432 default: Option<PyObject>
433 ) -> PyResult<Option<PyObject>> {
433 ) -> PyResult<Option<PyObject>> {
434 let key = key.extract::<PyBytes>(py)?;
434 let key = key.extract::<PyBytes>(py)?;
435 match self
435 match self
436 .inner(py)
436 .inner(py)
437 .borrow_mut()
437 .borrow_mut()
438 .copy_map_remove(HgPath::new(key.data(py)))
438 .copy_map_remove(HgPath::new(key.data(py)))
439 .map_err(|e| v2_error(py, e))?
439 .map_err(|e| v2_error(py, e))?
440 {
440 {
441 Some(copy) => Ok(Some(
441 Some(copy) => Ok(Some(
442 PyBytes::new(py, copy.as_bytes()).into_object(),
442 PyBytes::new(py, copy.as_bytes()).into_object(),
443 )),
443 )),
444 None => Ok(default),
444 None => Ok(default),
445 }
445 }
446 }
446 }
447
447
448 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
448 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
449 let leaked_ref = self.inner(py).leak_immutable();
449 let leaked_ref = self.inner(py).leak_immutable();
450 CopyMapKeysIterator::from_inner(
450 CopyMapKeysIterator::from_inner(
451 py,
451 py,
452 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
452 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
453 )
453 )
454 }
454 }
455
455
456 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
456 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
457 let leaked_ref = self.inner(py).leak_immutable();
457 let leaked_ref = self.inner(py).leak_immutable();
458 CopyMapItemsIterator::from_inner(
458 CopyMapItemsIterator::from_inner(
459 py,
459 py,
460 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
460 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
461 )
461 )
462 }
462 }
463
463
464 def tracked_dirs(&self) -> PyResult<PyList> {
464 def tracked_dirs(&self) -> PyResult<PyList> {
465 let dirs = PyList::new(py, &[]);
465 let dirs = PyList::new(py, &[]);
466 for path in self.inner(py).borrow_mut().iter_tracked_dirs()
466 for path in self.inner(py).borrow_mut().iter_tracked_dirs()
467 .map_err(|e |dirstate_error(py, e))?
467 .map_err(|e |dirstate_error(py, e))?
468 {
468 {
469 let path = path.map_err(|e| v2_error(py, e))?;
469 let path = path.map_err(|e| v2_error(py, e))?;
470 let path = PyBytes::new(py, path.as_bytes());
470 let path = PyBytes::new(py, path.as_bytes());
471 dirs.append(py, path.into_object())
471 dirs.append(py, path.into_object())
472 }
472 }
473 Ok(dirs)
473 Ok(dirs)
474 }
474 }
475
475
476 def setparents_fixup(&self) -> PyResult<PyDict> {
476 def setparents_fixup(&self) -> PyResult<PyDict> {
477 let dict = PyDict::new(py);
477 let dict = PyDict::new(py);
478 let copies = self.inner(py).borrow_mut().setparents_fixup();
478 let copies = self.inner(py).borrow_mut().setparents_fixup();
479 for (key, value) in copies.map_err(|e| v2_error(py, e))? {
479 for (key, value) in copies.map_err(|e| v2_error(py, e))? {
480 dict.set_item(
480 dict.set_item(
481 py,
481 py,
482 PyBytes::new(py, key.as_bytes()),
482 PyBytes::new(py, key.as_bytes()),
483 PyBytes::new(py, value.as_bytes()),
483 PyBytes::new(py, value.as_bytes()),
484 )?;
484 )?;
485 }
485 }
486 Ok(dict)
486 Ok(dict)
487 }
487 }
488
488
489 def debug_iter(&self, all: bool) -> PyResult<PyList> {
489 def debug_iter(&self, all: bool) -> PyResult<PyList> {
490 let dirs = PyList::new(py, &[]);
490 let dirs = PyList::new(py, &[]);
491 for item in self.inner(py).borrow().debug_iter(all) {
491 for item in self.inner(py).borrow().debug_iter(all) {
492 let (path, (state, mode, size, mtime)) =
492 let (path, (state, mode, size, mtime)) =
493 item.map_err(|e| v2_error(py, e))?;
493 item.map_err(|e| v2_error(py, e))?;
494 let path = PyBytes::new(py, path.as_bytes());
494 let path = PyBytes::new(py, path.as_bytes());
495 let item = (path, state, mode, size, mtime);
495 let item = (path, state, mode, size, mtime);
496 dirs.append(py, item.to_py_object(py).into_object())
496 dirs.append(py, item.to_py_object(py).into_object())
497 }
497 }
498 Ok(dirs)
498 Ok(dirs)
499 }
499 }
500 });
500 });
501
501
502 impl DirstateMap {
502 impl DirstateMap {
503 pub fn get_inner_mut<'a>(
503 pub fn get_inner_mut<'a>(
504 &'a self,
504 &'a self,
505 py: Python<'a>,
505 py: Python<'a>,
506 ) -> RefMut<'a, OwningDirstateMap> {
506 ) -> RefMut<'a, OwningDirstateMap> {
507 self.inner(py).borrow_mut()
507 self.inner(py).borrow_mut()
508 }
508 }
509 fn translate_key(
509 fn translate_key(
510 py: Python,
510 py: Python,
511 res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>,
511 res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>,
512 ) -> PyResult<Option<PyBytes>> {
512 ) -> PyResult<Option<PyBytes>> {
513 let (f, _entry) = res.map_err(|e| v2_error(py, e))?;
513 let (f, _entry) = res.map_err(|e| v2_error(py, e))?;
514 Ok(Some(PyBytes::new(py, f.as_bytes())))
514 Ok(Some(PyBytes::new(py, f.as_bytes())))
515 }
515 }
516 fn translate_key_value(
516 fn translate_key_value(
517 py: Python,
517 py: Python,
518 res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>,
518 res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>,
519 ) -> PyResult<Option<(PyBytes, PyObject)>> {
519 ) -> PyResult<Option<(PyBytes, PyObject)>> {
520 let (f, entry) = res.map_err(|e| v2_error(py, e))?;
520 let (f, entry) = res.map_err(|e| v2_error(py, e))?;
521 Ok(Some((
521 Ok(Some((
522 PyBytes::new(py, f.as_bytes()),
522 PyBytes::new(py, f.as_bytes()),
523 DirstateItem::new_as_pyobject(py, entry)?,
523 DirstateItem::new_as_pyobject(py, entry)?,
524 )))
524 )))
525 }
525 }
526 }
526 }
527
527
528 py_shared_iterator!(
528 py_shared_iterator!(
529 DirstateMapKeysIterator,
529 DirstateMapKeysIterator,
530 UnsafePyLeaked<StateMapIter<'static>>,
530 UnsafePyLeaked<StateMapIter<'static>>,
531 DirstateMap::translate_key,
531 DirstateMap::translate_key,
532 Option<PyBytes>
532 Option<PyBytes>
533 );
533 );
534
534
535 py_shared_iterator!(
535 py_shared_iterator!(
536 DirstateMapItemsIterator,
536 DirstateMapItemsIterator,
537 UnsafePyLeaked<StateMapIter<'static>>,
537 UnsafePyLeaked<StateMapIter<'static>>,
538 DirstateMap::translate_key_value,
538 DirstateMap::translate_key_value,
539 Option<(PyBytes, PyObject)>
539 Option<(PyBytes, PyObject)>
540 );
540 );
541
541
542 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<Node> {
542 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<Node> {
543 let bytes = obj.extract::<PyBytes>(py)?;
543 let bytes = obj.extract::<PyBytes>(py)?;
544 match bytes.data(py).try_into() {
544 match bytes.data(py).try_into() {
545 Ok(s) => Ok(s),
545 Ok(s) => Ok(s),
546 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
546 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
547 }
547 }
548 }
548 }
549
549
550 pub(super) fn v2_error(py: Python<'_>, _: DirstateV2ParseError) -> PyErr {
550 pub(super) fn v2_error(py: Python<'_>, _: DirstateV2ParseError) -> PyErr {
551 PyErr::new::<exc::ValueError, _>(py, "corrupted dirstate-v2")
551 PyErr::new::<exc::ValueError, _>(py, "corrupted dirstate-v2")
552 }
552 }
553
553
554 fn dirstate_error(py: Python<'_>, e: DirstateError) -> PyErr {
554 fn dirstate_error(py: Python<'_>, e: DirstateError) -> PyErr {
555 PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e))
555 PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e))
556 }
556 }
General Comments 0
You need to be logged in to leave comments. Login now