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