##// END OF EJS Templates
dirstate-item: also build DistateItem in dirstate.directories()...
marmoute -
r48367:7a15dea6 default
parent child Browse files
Show More
@@ -1,147 +1,160 b''
1 // dirstate.rs
1 // dirstate.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` module provided by the
8 //! Bindings for the `hg::dirstate` module provided by the
9 //! `hg-core` package.
9 //! `hg-core` package.
10 //!
10 //!
11 //! From Python, this will be seen as `mercurial.rustext.dirstate`
11 //! From Python, this will be seen as `mercurial.rustext.dirstate`
12 mod copymap;
12 mod copymap;
13 mod dirs_multiset;
13 mod dirs_multiset;
14 mod dirstate_map;
14 mod dirstate_map;
15 mod dispatch;
15 mod dispatch;
16 mod non_normal_entries;
16 mod non_normal_entries;
17 mod owning;
17 mod owning;
18 mod status;
18 mod status;
19 use crate::{
19 use crate::{
20 dirstate::{
20 dirstate::{
21 dirs_multiset::Dirs, dirstate_map::DirstateMap, status::status_wrapper,
21 dirs_multiset::Dirs, dirstate_map::DirstateMap, status::status_wrapper,
22 },
22 },
23 exceptions,
23 exceptions,
24 };
24 };
25 use cpython::{
25 use cpython::{
26 exc, PyBytes, PyDict, PyErr, PyList, PyModule, PyObject, PyResult,
26 exc, PyBytes, PyDict, PyErr, PyList, PyModule, PyObject, PyResult,
27 PySequence, Python,
27 PySequence, Python,
28 };
28 };
29 use hg::dirstate_tree::on_disk::V2_FORMAT_MARKER;
29 use hg::dirstate_tree::on_disk::V2_FORMAT_MARKER;
30 use hg::{utils::hg_path::HgPathBuf, DirstateEntry, EntryState, StateMap};
30 use hg::{utils::hg_path::HgPathBuf, DirstateEntry, EntryState, StateMap};
31 use libc::{c_char, c_int};
31 use libc::{c_char, c_int};
32 use std::convert::TryFrom;
32 use std::convert::TryFrom;
33
33
34 // C code uses a custom `dirstate_tuple` type, checks in multiple instances
34 // C code uses a custom `dirstate_tuple` type, checks in multiple instances
35 // for this type, and raises a Python `Exception` if the check does not pass.
35 // for this type, and raises a Python `Exception` if the check does not pass.
36 // Because this type differs only in name from the regular Python tuple, it
36 // Because this type differs only in name from the regular Python tuple, it
37 // would be a good idea in the near future to remove it entirely to allow
37 // would be a good idea in the near future to remove it entirely to allow
38 // for a pure Python tuple of the same effective structure to be used,
38 // for a pure Python tuple of the same effective structure to be used,
39 // rendering this type and the capsule below useless.
39 // rendering this type and the capsule below useless.
40 py_capsule_fn!(
40 py_capsule_fn!(
41 from mercurial.cext.parsers import make_dirstate_item_CAPI
41 from mercurial.cext.parsers import make_dirstate_item_CAPI
42 as make_dirstate_item_capi
42 as make_dirstate_item_capi
43 signature (
43 signature (
44 state: c_char,
44 state: c_char,
45 mode: c_int,
45 mode: c_int,
46 size: c_int,
46 size: c_int,
47 mtime: c_int,
47 mtime: c_int,
48 ) -> *mut RawPyObject
48 ) -> *mut RawPyObject
49 );
49 );
50
50
51 pub fn make_dirstate_item(
51 pub fn make_dirstate_item(
52 py: Python,
52 py: Python,
53 entry: &DirstateEntry,
53 entry: &DirstateEntry,
54 ) -> PyResult<PyObject> {
54 ) -> PyResult<PyObject> {
55 // might be silly to retrieve capsule function in hot loop
55 // might be silly to retrieve capsule function in hot loop
56 let make = make_dirstate_item_capi::retrieve(py)?;
56 let make = make_dirstate_item_capi::retrieve(py)?;
57
57
58 let &DirstateEntry {
58 let &DirstateEntry {
59 state,
59 state,
60 mode,
60 mode,
61 size,
61 size,
62 mtime,
62 mtime,
63 } = entry;
63 } = entry;
64 // Explicitly go through u8 first, then cast to platform-specific `c_char`
64 // Explicitly go through u8 first, then cast to platform-specific `c_char`
65 // because Into<u8> has a specific implementation while `as c_char` would
65 // because Into<u8> has a specific implementation while `as c_char` would
66 // just do a naive enum cast.
66 // just do a naive enum cast.
67 let state_code: u8 = state.into();
67 let state_code: u8 = state.into();
68
68
69 let maybe_obj = unsafe {
69 let maybe_obj = unsafe {
70 let ptr = make(state_code as c_char, mode, size, mtime);
70 let ptr = make(state_code as c_char, mode, size, mtime);
71 PyObject::from_owned_ptr_opt(py, ptr)
71 PyObject::from_owned_ptr_opt(py, ptr)
72 };
72 };
73 maybe_obj.ok_or_else(|| PyErr::fetch(py))
73 maybe_obj.ok_or_else(|| PyErr::fetch(py))
74 }
74 }
75
75
76 // XXX a bit strange to have a dedicated function, but directory are not
77 // treated as dirstate node by hg-core for now so…
78 pub fn make_directory_item(py: Python, mtime: i32) -> PyResult<PyObject> {
79 // might be silly to retrieve capsule function in hot loop
80 let make = make_dirstate_item_capi::retrieve(py)?;
81
82 let maybe_obj = unsafe {
83 let ptr = make(b'd' as c_char, 0 as i32, 0 as i32, mtime);
84 PyObject::from_owned_ptr_opt(py, ptr)
85 };
86 maybe_obj.ok_or_else(|| PyErr::fetch(py))
87 }
88
76 pub fn extract_dirstate(py: Python, dmap: &PyDict) -> Result<StateMap, PyErr> {
89 pub fn extract_dirstate(py: Python, dmap: &PyDict) -> Result<StateMap, PyErr> {
77 dmap.items(py)
90 dmap.items(py)
78 .iter()
91 .iter()
79 .map(|(filename, stats)| {
92 .map(|(filename, stats)| {
80 let stats = stats.extract::<PySequence>(py)?;
93 let stats = stats.extract::<PySequence>(py)?;
81 let state = stats.get_item(py, 0)?.extract::<PyBytes>(py)?;
94 let state = stats.get_item(py, 0)?.extract::<PyBytes>(py)?;
82 let state =
95 let state =
83 EntryState::try_from(state.data(py)[0]).map_err(|e| {
96 EntryState::try_from(state.data(py)[0]).map_err(|e| {
84 PyErr::new::<exc::ValueError, _>(py, e.to_string())
97 PyErr::new::<exc::ValueError, _>(py, e.to_string())
85 })?;
98 })?;
86 let mode = stats.get_item(py, 1)?.extract(py)?;
99 let mode = stats.get_item(py, 1)?.extract(py)?;
87 let size = stats.get_item(py, 2)?.extract(py)?;
100 let size = stats.get_item(py, 2)?.extract(py)?;
88 let mtime = stats.get_item(py, 3)?.extract(py)?;
101 let mtime = stats.get_item(py, 3)?.extract(py)?;
89 let filename = filename.extract::<PyBytes>(py)?;
102 let filename = filename.extract::<PyBytes>(py)?;
90 let filename = filename.data(py);
103 let filename = filename.data(py);
91 Ok((
104 Ok((
92 HgPathBuf::from(filename.to_owned()),
105 HgPathBuf::from(filename.to_owned()),
93 DirstateEntry {
106 DirstateEntry {
94 state,
107 state,
95 mode,
108 mode,
96 size,
109 size,
97 mtime,
110 mtime,
98 },
111 },
99 ))
112 ))
100 })
113 })
101 .collect()
114 .collect()
102 }
115 }
103
116
104 /// Create the module, with `__package__` given from parent
117 /// Create the module, with `__package__` given from parent
105 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
118 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
106 let dotted_name = &format!("{}.dirstate", package);
119 let dotted_name = &format!("{}.dirstate", package);
107 let m = PyModule::new(py, dotted_name)?;
120 let m = PyModule::new(py, dotted_name)?;
108
121
109 env_logger::init();
122 env_logger::init();
110
123
111 m.add(py, "__package__", package)?;
124 m.add(py, "__package__", package)?;
112 m.add(py, "__doc__", "Dirstate - Rust implementation")?;
125 m.add(py, "__doc__", "Dirstate - Rust implementation")?;
113
126
114 m.add(
127 m.add(
115 py,
128 py,
116 "FallbackError",
129 "FallbackError",
117 py.get_type::<exceptions::FallbackError>(),
130 py.get_type::<exceptions::FallbackError>(),
118 )?;
131 )?;
119 m.add_class::<Dirs>(py)?;
132 m.add_class::<Dirs>(py)?;
120 m.add_class::<DirstateMap>(py)?;
133 m.add_class::<DirstateMap>(py)?;
121 m.add(py, "V2_FORMAT_MARKER", PyBytes::new(py, V2_FORMAT_MARKER))?;
134 m.add(py, "V2_FORMAT_MARKER", PyBytes::new(py, V2_FORMAT_MARKER))?;
122 m.add(
135 m.add(
123 py,
136 py,
124 "status",
137 "status",
125 py_fn!(
138 py_fn!(
126 py,
139 py,
127 status_wrapper(
140 status_wrapper(
128 dmap: DirstateMap,
141 dmap: DirstateMap,
129 root_dir: PyObject,
142 root_dir: PyObject,
130 matcher: PyObject,
143 matcher: PyObject,
131 ignorefiles: PyList,
144 ignorefiles: PyList,
132 check_exec: bool,
145 check_exec: bool,
133 last_normal_time: i64,
146 last_normal_time: i64,
134 list_clean: bool,
147 list_clean: bool,
135 list_ignored: bool,
148 list_ignored: bool,
136 list_unknown: bool,
149 list_unknown: bool,
137 collect_traversed_dirs: bool
150 collect_traversed_dirs: bool
138 )
151 )
139 ),
152 ),
140 )?;
153 )?;
141
154
142 let sys = PyModule::import(py, "sys")?;
155 let sys = PyModule::import(py, "sys")?;
143 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
156 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
144 sys_modules.set_item(py, dotted_name, &m)?;
157 sys_modules.set_item(py, dotted_name, &m)?;
145
158
146 Ok(m)
159 Ok(m)
147 }
160 }
@@ -1,580 +1,582 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 use std::convert::TryInto;
12 use std::convert::TryInto;
13
13
14 use cpython::{
14 use cpython::{
15 exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList,
15 exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList,
16 PyObject, PyResult, PySet, PyString, Python, PythonObject, ToPyObject,
16 PyObject, PyResult, PySet, PyString, Python, PythonObject, ToPyObject,
17 UnsafePyLeaked,
17 UnsafePyLeaked,
18 };
18 };
19
19
20 use crate::{
20 use crate::{
21 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
21 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
22 dirstate::make_directory_item,
22 dirstate::make_dirstate_item,
23 dirstate::make_dirstate_item,
23 dirstate::non_normal_entries::{
24 dirstate::non_normal_entries::{
24 NonNormalEntries, NonNormalEntriesIterator,
25 NonNormalEntries, NonNormalEntriesIterator,
25 },
26 },
26 dirstate::owning::OwningDirstateMap,
27 dirstate::owning::OwningDirstateMap,
27 parsers::dirstate_parents_to_pytuple,
28 parsers::dirstate_parents_to_pytuple,
28 };
29 };
29 use hg::{
30 use hg::{
30 dirstate::parsers::Timestamp,
31 dirstate::parsers::Timestamp,
31 dirstate::MTIME_UNSET,
32 dirstate::MTIME_UNSET,
32 dirstate::SIZE_NON_NORMAL,
33 dirstate::SIZE_NON_NORMAL,
33 dirstate_tree::dispatch::DirstateMapMethods,
34 dirstate_tree::dispatch::DirstateMapMethods,
34 dirstate_tree::on_disk::DirstateV2ParseError,
35 dirstate_tree::on_disk::DirstateV2ParseError,
35 revlog::Node,
36 revlog::Node,
36 utils::files::normalize_case,
37 utils::files::normalize_case,
37 utils::hg_path::{HgPath, HgPathBuf},
38 utils::hg_path::{HgPath, HgPathBuf},
38 DirstateEntry, DirstateError, DirstateMap as RustDirstateMap,
39 DirstateEntry, DirstateError, DirstateMap as RustDirstateMap,
39 DirstateParents, EntryState, StateMapIter,
40 DirstateParents, EntryState, StateMapIter,
40 };
41 };
41
42
42 // TODO
43 // TODO
43 // This object needs to share references to multiple members of its Rust
44 // This object needs to share references to multiple members of its Rust
44 // inner struct, namely `copy_map`, `dirs` and `all_dirs`.
45 // inner struct, namely `copy_map`, `dirs` and `all_dirs`.
45 // Right now `CopyMap` is done, but it needs to have an explicit reference
46 // Right now `CopyMap` is done, but it needs to have an explicit reference
46 // to `RustDirstateMap` which itself needs to have an encapsulation for
47 // to `RustDirstateMap` which itself needs to have an encapsulation for
47 // every method in `CopyMap` (copymapcopy, etc.).
48 // every method in `CopyMap` (copymapcopy, etc.).
48 // This is ugly and hard to maintain.
49 // This is ugly and hard to maintain.
49 // The same logic applies to `dirs` and `all_dirs`, however the `Dirs`
50 // The same logic applies to `dirs` and `all_dirs`, however the `Dirs`
50 // `py_class!` is already implemented and does not mention
51 // `py_class!` is already implemented and does not mention
51 // `RustDirstateMap`, rightfully so.
52 // `RustDirstateMap`, rightfully so.
52 // All attributes also have to have a separate refcount data attribute for
53 // All attributes also have to have a separate refcount data attribute for
53 // leaks, with all methods that go along for reference sharing.
54 // leaks, with all methods that go along for reference sharing.
54 py_class!(pub class DirstateMap |py| {
55 py_class!(pub class DirstateMap |py| {
55 @shared data inner: Box<dyn DirstateMapMethods + Send>;
56 @shared data inner: Box<dyn DirstateMapMethods + Send>;
56
57
57 /// Returns a `(dirstate_map, parents)` tuple
58 /// Returns a `(dirstate_map, parents)` tuple
58 @staticmethod
59 @staticmethod
59 def new(
60 def new(
60 use_dirstate_tree: bool,
61 use_dirstate_tree: bool,
61 use_dirstate_v2: bool,
62 use_dirstate_v2: bool,
62 on_disk: PyBytes,
63 on_disk: PyBytes,
63 ) -> PyResult<PyObject> {
64 ) -> PyResult<PyObject> {
64 let dirstate_error = |e: DirstateError| {
65 let dirstate_error = |e: DirstateError| {
65 PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e))
66 PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e))
66 };
67 };
67 let (inner, parents) = if use_dirstate_tree || use_dirstate_v2 {
68 let (inner, parents) = if use_dirstate_tree || use_dirstate_v2 {
68 let (map, parents) =
69 let (map, parents) =
69 OwningDirstateMap::new(py, on_disk, use_dirstate_v2)
70 OwningDirstateMap::new(py, on_disk, use_dirstate_v2)
70 .map_err(dirstate_error)?;
71 .map_err(dirstate_error)?;
71 (Box::new(map) as _, parents)
72 (Box::new(map) as _, parents)
72 } else {
73 } else {
73 let bytes = on_disk.data(py);
74 let bytes = on_disk.data(py);
74 let mut map = RustDirstateMap::default();
75 let mut map = RustDirstateMap::default();
75 let parents = map.read(bytes).map_err(dirstate_error)?;
76 let parents = map.read(bytes).map_err(dirstate_error)?;
76 (Box::new(map) as _, parents)
77 (Box::new(map) as _, parents)
77 };
78 };
78 let map = Self::create_instance(py, inner)?;
79 let map = Self::create_instance(py, inner)?;
79 let parents = parents.map(|p| dirstate_parents_to_pytuple(py, &p));
80 let parents = parents.map(|p| dirstate_parents_to_pytuple(py, &p));
80 Ok((map, parents).to_py_object(py).into_object())
81 Ok((map, parents).to_py_object(py).into_object())
81 }
82 }
82
83
83 def clear(&self) -> PyResult<PyObject> {
84 def clear(&self) -> PyResult<PyObject> {
84 self.inner(py).borrow_mut().clear();
85 self.inner(py).borrow_mut().clear();
85 Ok(py.None())
86 Ok(py.None())
86 }
87 }
87
88
88 def get(
89 def get(
89 &self,
90 &self,
90 key: PyObject,
91 key: PyObject,
91 default: Option<PyObject> = None
92 default: Option<PyObject> = None
92 ) -> PyResult<Option<PyObject>> {
93 ) -> PyResult<Option<PyObject>> {
93 let key = key.extract::<PyBytes>(py)?;
94 let key = key.extract::<PyBytes>(py)?;
94 match self
95 match self
95 .inner(py)
96 .inner(py)
96 .borrow()
97 .borrow()
97 .get(HgPath::new(key.data(py)))
98 .get(HgPath::new(key.data(py)))
98 .map_err(|e| v2_error(py, e))?
99 .map_err(|e| v2_error(py, e))?
99 {
100 {
100 Some(entry) => {
101 Some(entry) => {
101 Ok(Some(make_dirstate_item(py, &entry)?))
102 Ok(Some(make_dirstate_item(py, &entry)?))
102 },
103 },
103 None => Ok(default)
104 None => Ok(default)
104 }
105 }
105 }
106 }
106
107
107 def addfile(
108 def addfile(
108 &self,
109 &self,
109 f: PyObject,
110 f: PyObject,
110 mode: PyObject,
111 mode: PyObject,
111 size: PyObject,
112 size: PyObject,
112 mtime: PyObject,
113 mtime: PyObject,
113 added: PyObject,
114 added: PyObject,
114 merged: PyObject,
115 merged: PyObject,
115 from_p2: PyObject,
116 from_p2: PyObject,
116 possibly_dirty: PyObject,
117 possibly_dirty: PyObject,
117 ) -> PyResult<PyObject> {
118 ) -> PyResult<PyObject> {
118 let f = f.extract::<PyBytes>(py)?;
119 let f = f.extract::<PyBytes>(py)?;
119 let filename = HgPath::new(f.data(py));
120 let filename = HgPath::new(f.data(py));
120 let mode = if mode.is_none(py) {
121 let mode = if mode.is_none(py) {
121 // fallback default value
122 // fallback default value
122 0
123 0
123 } else {
124 } else {
124 mode.extract(py)?
125 mode.extract(py)?
125 };
126 };
126 let size = if size.is_none(py) {
127 let size = if size.is_none(py) {
127 // fallback default value
128 // fallback default value
128 SIZE_NON_NORMAL
129 SIZE_NON_NORMAL
129 } else {
130 } else {
130 size.extract(py)?
131 size.extract(py)?
131 };
132 };
132 let mtime = if mtime.is_none(py) {
133 let mtime = if mtime.is_none(py) {
133 // fallback default value
134 // fallback default value
134 MTIME_UNSET
135 MTIME_UNSET
135 } else {
136 } else {
136 mtime.extract(py)?
137 mtime.extract(py)?
137 };
138 };
138 let entry = DirstateEntry {
139 let entry = DirstateEntry {
139 // XXX Arbitrary default value since the value is determined later
140 // XXX Arbitrary default value since the value is determined later
140 state: EntryState::Normal,
141 state: EntryState::Normal,
141 mode: mode,
142 mode: mode,
142 size: size,
143 size: size,
143 mtime: mtime,
144 mtime: mtime,
144 };
145 };
145 let added = added.extract::<PyBool>(py)?.is_true();
146 let added = added.extract::<PyBool>(py)?.is_true();
146 let merged = merged.extract::<PyBool>(py)?.is_true();
147 let merged = merged.extract::<PyBool>(py)?.is_true();
147 let from_p2 = from_p2.extract::<PyBool>(py)?.is_true();
148 let from_p2 = from_p2.extract::<PyBool>(py)?.is_true();
148 let possibly_dirty = possibly_dirty.extract::<PyBool>(py)?.is_true();
149 let possibly_dirty = possibly_dirty.extract::<PyBool>(py)?.is_true();
149 self.inner(py).borrow_mut().add_file(
150 self.inner(py).borrow_mut().add_file(
150 filename,
151 filename,
151 entry,
152 entry,
152 added,
153 added,
153 merged,
154 merged,
154 from_p2,
155 from_p2,
155 possibly_dirty
156 possibly_dirty
156 ).and(Ok(py.None())).or_else(|e: DirstateError| {
157 ).and(Ok(py.None())).or_else(|e: DirstateError| {
157 Err(PyErr::new::<exc::ValueError, _>(py, e.to_string()))
158 Err(PyErr::new::<exc::ValueError, _>(py, e.to_string()))
158 })
159 })
159 }
160 }
160
161
161 def removefile(
162 def removefile(
162 &self,
163 &self,
163 f: PyObject,
164 f: PyObject,
164 in_merge: PyObject
165 in_merge: PyObject
165 ) -> PyResult<PyObject> {
166 ) -> PyResult<PyObject> {
166 self.inner(py).borrow_mut()
167 self.inner(py).borrow_mut()
167 .remove_file(
168 .remove_file(
168 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
169 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
169 in_merge.extract::<PyBool>(py)?.is_true(),
170 in_merge.extract::<PyBool>(py)?.is_true(),
170 )
171 )
171 .or_else(|_| {
172 .or_else(|_| {
172 Err(PyErr::new::<exc::OSError, _>(
173 Err(PyErr::new::<exc::OSError, _>(
173 py,
174 py,
174 "Dirstate error".to_string(),
175 "Dirstate error".to_string(),
175 ))
176 ))
176 })?;
177 })?;
177 Ok(py.None())
178 Ok(py.None())
178 }
179 }
179
180
180 def dropfile(
181 def dropfile(
181 &self,
182 &self,
182 f: PyObject,
183 f: PyObject,
183 ) -> PyResult<PyBool> {
184 ) -> PyResult<PyBool> {
184 self.inner(py).borrow_mut()
185 self.inner(py).borrow_mut()
185 .drop_file(
186 .drop_file(
186 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
187 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
187 )
188 )
188 .and_then(|b| Ok(b.to_py_object(py)))
189 .and_then(|b| Ok(b.to_py_object(py)))
189 .or_else(|e| {
190 .or_else(|e| {
190 Err(PyErr::new::<exc::OSError, _>(
191 Err(PyErr::new::<exc::OSError, _>(
191 py,
192 py,
192 format!("Dirstate error: {}", e.to_string()),
193 format!("Dirstate error: {}", e.to_string()),
193 ))
194 ))
194 })
195 })
195 }
196 }
196
197
197 def clearambiguoustimes(
198 def clearambiguoustimes(
198 &self,
199 &self,
199 files: PyObject,
200 files: PyObject,
200 now: PyObject
201 now: PyObject
201 ) -> PyResult<PyObject> {
202 ) -> PyResult<PyObject> {
202 let files: PyResult<Vec<HgPathBuf>> = files
203 let files: PyResult<Vec<HgPathBuf>> = files
203 .iter(py)?
204 .iter(py)?
204 .map(|filename| {
205 .map(|filename| {
205 Ok(HgPathBuf::from_bytes(
206 Ok(HgPathBuf::from_bytes(
206 filename?.extract::<PyBytes>(py)?.data(py),
207 filename?.extract::<PyBytes>(py)?.data(py),
207 ))
208 ))
208 })
209 })
209 .collect();
210 .collect();
210 self.inner(py)
211 self.inner(py)
211 .borrow_mut()
212 .borrow_mut()
212 .clear_ambiguous_times(files?, now.extract(py)?)
213 .clear_ambiguous_times(files?, now.extract(py)?)
213 .map_err(|e| v2_error(py, e))?;
214 .map_err(|e| v2_error(py, e))?;
214 Ok(py.None())
215 Ok(py.None())
215 }
216 }
216
217
217 def other_parent_entries(&self) -> PyResult<PyObject> {
218 def other_parent_entries(&self) -> PyResult<PyObject> {
218 let mut inner_shared = self.inner(py).borrow_mut();
219 let mut inner_shared = self.inner(py).borrow_mut();
219 let set = PySet::empty(py)?;
220 let set = PySet::empty(py)?;
220 for path in inner_shared.iter_other_parent_paths() {
221 for path in inner_shared.iter_other_parent_paths() {
221 let path = path.map_err(|e| v2_error(py, e))?;
222 let path = path.map_err(|e| v2_error(py, e))?;
222 set.add(py, PyBytes::new(py, path.as_bytes()))?;
223 set.add(py, PyBytes::new(py, path.as_bytes()))?;
223 }
224 }
224 Ok(set.into_object())
225 Ok(set.into_object())
225 }
226 }
226
227
227 def non_normal_entries(&self) -> PyResult<NonNormalEntries> {
228 def non_normal_entries(&self) -> PyResult<NonNormalEntries> {
228 NonNormalEntries::from_inner(py, self.clone_ref(py))
229 NonNormalEntries::from_inner(py, self.clone_ref(py))
229 }
230 }
230
231
231 def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> {
232 def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> {
232 let key = key.extract::<PyBytes>(py)?;
233 let key = key.extract::<PyBytes>(py)?;
233 self.inner(py)
234 self.inner(py)
234 .borrow_mut()
235 .borrow_mut()
235 .non_normal_entries_contains(HgPath::new(key.data(py)))
236 .non_normal_entries_contains(HgPath::new(key.data(py)))
236 .map_err(|e| v2_error(py, e))
237 .map_err(|e| v2_error(py, e))
237 }
238 }
238
239
239 def non_normal_entries_display(&self) -> PyResult<PyString> {
240 def non_normal_entries_display(&self) -> PyResult<PyString> {
240 let mut inner = self.inner(py).borrow_mut();
241 let mut inner = self.inner(py).borrow_mut();
241 let paths = inner
242 let paths = inner
242 .iter_non_normal_paths()
243 .iter_non_normal_paths()
243 .collect::<Result<Vec<_>, _>>()
244 .collect::<Result<Vec<_>, _>>()
244 .map_err(|e| v2_error(py, e))?;
245 .map_err(|e| v2_error(py, e))?;
245 let formatted = format!("NonNormalEntries: {}", hg::utils::join_display(paths, ", "));
246 let formatted = format!("NonNormalEntries: {}", hg::utils::join_display(paths, ", "));
246 Ok(PyString::new(py, &formatted))
247 Ok(PyString::new(py, &formatted))
247 }
248 }
248
249
249 def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> {
250 def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> {
250 let key = key.extract::<PyBytes>(py)?;
251 let key = key.extract::<PyBytes>(py)?;
251 self
252 self
252 .inner(py)
253 .inner(py)
253 .borrow_mut()
254 .borrow_mut()
254 .non_normal_entries_remove(HgPath::new(key.data(py)));
255 .non_normal_entries_remove(HgPath::new(key.data(py)));
255 Ok(py.None())
256 Ok(py.None())
256 }
257 }
257
258
258 def non_normal_or_other_parent_paths(&self) -> PyResult<PyList> {
259 def non_normal_or_other_parent_paths(&self) -> PyResult<PyList> {
259 let mut inner = self.inner(py).borrow_mut();
260 let mut inner = self.inner(py).borrow_mut();
260
261
261 let ret = PyList::new(py, &[]);
262 let ret = PyList::new(py, &[]);
262 for filename in inner.non_normal_or_other_parent_paths() {
263 for filename in inner.non_normal_or_other_parent_paths() {
263 let filename = filename.map_err(|e| v2_error(py, e))?;
264 let filename = filename.map_err(|e| v2_error(py, e))?;
264 let as_pystring = PyBytes::new(py, filename.as_bytes());
265 let as_pystring = PyBytes::new(py, filename.as_bytes());
265 ret.append(py, as_pystring.into_object());
266 ret.append(py, as_pystring.into_object());
266 }
267 }
267 Ok(ret)
268 Ok(ret)
268 }
269 }
269
270
270 def non_normal_entries_iter(&self) -> PyResult<NonNormalEntriesIterator> {
271 def non_normal_entries_iter(&self) -> PyResult<NonNormalEntriesIterator> {
271 // Make sure the sets are defined before we no longer have a mutable
272 // Make sure the sets are defined before we no longer have a mutable
272 // reference to the dmap.
273 // reference to the dmap.
273 self.inner(py)
274 self.inner(py)
274 .borrow_mut()
275 .borrow_mut()
275 .set_non_normal_other_parent_entries(false);
276 .set_non_normal_other_parent_entries(false);
276
277
277 let leaked_ref = self.inner(py).leak_immutable();
278 let leaked_ref = self.inner(py).leak_immutable();
278
279
279 NonNormalEntriesIterator::from_inner(py, unsafe {
280 NonNormalEntriesIterator::from_inner(py, unsafe {
280 leaked_ref.map(py, |o| {
281 leaked_ref.map(py, |o| {
281 o.iter_non_normal_paths_panic()
282 o.iter_non_normal_paths_panic()
282 })
283 })
283 })
284 })
284 }
285 }
285
286
286 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
287 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
287 let d = d.extract::<PyBytes>(py)?;
288 let d = d.extract::<PyBytes>(py)?;
288 Ok(self.inner(py).borrow_mut()
289 Ok(self.inner(py).borrow_mut()
289 .has_tracked_dir(HgPath::new(d.data(py)))
290 .has_tracked_dir(HgPath::new(d.data(py)))
290 .map_err(|e| {
291 .map_err(|e| {
291 PyErr::new::<exc::ValueError, _>(py, e.to_string())
292 PyErr::new::<exc::ValueError, _>(py, e.to_string())
292 })?
293 })?
293 .to_py_object(py))
294 .to_py_object(py))
294 }
295 }
295
296
296 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
297 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
297 let d = d.extract::<PyBytes>(py)?;
298 let d = d.extract::<PyBytes>(py)?;
298 Ok(self.inner(py).borrow_mut()
299 Ok(self.inner(py).borrow_mut()
299 .has_dir(HgPath::new(d.data(py)))
300 .has_dir(HgPath::new(d.data(py)))
300 .map_err(|e| {
301 .map_err(|e| {
301 PyErr::new::<exc::ValueError, _>(py, e.to_string())
302 PyErr::new::<exc::ValueError, _>(py, e.to_string())
302 })?
303 })?
303 .to_py_object(py))
304 .to_py_object(py))
304 }
305 }
305
306
306 def write(
307 def write(
307 &self,
308 &self,
308 use_dirstate_v2: bool,
309 use_dirstate_v2: bool,
309 p1: PyObject,
310 p1: PyObject,
310 p2: PyObject,
311 p2: PyObject,
311 now: PyObject
312 now: PyObject
312 ) -> PyResult<PyBytes> {
313 ) -> PyResult<PyBytes> {
313 let now = Timestamp(now.extract(py)?);
314 let now = Timestamp(now.extract(py)?);
314 let parents = DirstateParents {
315 let parents = DirstateParents {
315 p1: extract_node_id(py, &p1)?,
316 p1: extract_node_id(py, &p1)?,
316 p2: extract_node_id(py, &p2)?,
317 p2: extract_node_id(py, &p2)?,
317 };
318 };
318
319
319 let mut inner = self.inner(py).borrow_mut();
320 let mut inner = self.inner(py).borrow_mut();
320 let result = if use_dirstate_v2 {
321 let result = if use_dirstate_v2 {
321 inner.pack_v2(parents, now)
322 inner.pack_v2(parents, now)
322 } else {
323 } else {
323 inner.pack_v1(parents, now)
324 inner.pack_v1(parents, now)
324 };
325 };
325 match result {
326 match result {
326 Ok(packed) => Ok(PyBytes::new(py, &packed)),
327 Ok(packed) => Ok(PyBytes::new(py, &packed)),
327 Err(_) => Err(PyErr::new::<exc::OSError, _>(
328 Err(_) => Err(PyErr::new::<exc::OSError, _>(
328 py,
329 py,
329 "Dirstate error".to_string(),
330 "Dirstate error".to_string(),
330 )),
331 )),
331 }
332 }
332 }
333 }
333
334
334 def filefoldmapasdict(&self) -> PyResult<PyDict> {
335 def filefoldmapasdict(&self) -> PyResult<PyDict> {
335 let dict = PyDict::new(py);
336 let dict = PyDict::new(py);
336 for item in self.inner(py).borrow_mut().iter() {
337 for item in self.inner(py).borrow_mut().iter() {
337 let (path, entry) = item.map_err(|e| v2_error(py, e))?;
338 let (path, entry) = item.map_err(|e| v2_error(py, e))?;
338 if entry.state != EntryState::Removed {
339 if entry.state != EntryState::Removed {
339 let key = normalize_case(path);
340 let key = normalize_case(path);
340 let value = path;
341 let value = path;
341 dict.set_item(
342 dict.set_item(
342 py,
343 py,
343 PyBytes::new(py, key.as_bytes()).into_object(),
344 PyBytes::new(py, key.as_bytes()).into_object(),
344 PyBytes::new(py, value.as_bytes()).into_object(),
345 PyBytes::new(py, value.as_bytes()).into_object(),
345 )?;
346 )?;
346 }
347 }
347 }
348 }
348 Ok(dict)
349 Ok(dict)
349 }
350 }
350
351
351 def __len__(&self) -> PyResult<usize> {
352 def __len__(&self) -> PyResult<usize> {
352 Ok(self.inner(py).borrow().len())
353 Ok(self.inner(py).borrow().len())
353 }
354 }
354
355
355 def __contains__(&self, key: PyObject) -> PyResult<bool> {
356 def __contains__(&self, key: PyObject) -> PyResult<bool> {
356 let key = key.extract::<PyBytes>(py)?;
357 let key = key.extract::<PyBytes>(py)?;
357 self.inner(py)
358 self.inner(py)
358 .borrow()
359 .borrow()
359 .contains_key(HgPath::new(key.data(py)))
360 .contains_key(HgPath::new(key.data(py)))
360 .map_err(|e| v2_error(py, e))
361 .map_err(|e| v2_error(py, e))
361 }
362 }
362
363
363 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
364 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
364 let key = key.extract::<PyBytes>(py)?;
365 let key = key.extract::<PyBytes>(py)?;
365 let key = HgPath::new(key.data(py));
366 let key = HgPath::new(key.data(py));
366 match self
367 match self
367 .inner(py)
368 .inner(py)
368 .borrow()
369 .borrow()
369 .get(key)
370 .get(key)
370 .map_err(|e| v2_error(py, e))?
371 .map_err(|e| v2_error(py, e))?
371 {
372 {
372 Some(entry) => {
373 Some(entry) => {
373 Ok(make_dirstate_item(py, &entry)?)
374 Ok(make_dirstate_item(py, &entry)?)
374 },
375 },
375 None => Err(PyErr::new::<exc::KeyError, _>(
376 None => Err(PyErr::new::<exc::KeyError, _>(
376 py,
377 py,
377 String::from_utf8_lossy(key.as_bytes()),
378 String::from_utf8_lossy(key.as_bytes()),
378 )),
379 )),
379 }
380 }
380 }
381 }
381
382
382 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
383 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
383 let leaked_ref = self.inner(py).leak_immutable();
384 let leaked_ref = self.inner(py).leak_immutable();
384 DirstateMapKeysIterator::from_inner(
385 DirstateMapKeysIterator::from_inner(
385 py,
386 py,
386 unsafe { leaked_ref.map(py, |o| o.iter()) },
387 unsafe { leaked_ref.map(py, |o| o.iter()) },
387 )
388 )
388 }
389 }
389
390
390 def items(&self) -> PyResult<DirstateMapItemsIterator> {
391 def items(&self) -> PyResult<DirstateMapItemsIterator> {
391 let leaked_ref = self.inner(py).leak_immutable();
392 let leaked_ref = self.inner(py).leak_immutable();
392 DirstateMapItemsIterator::from_inner(
393 DirstateMapItemsIterator::from_inner(
393 py,
394 py,
394 unsafe { leaked_ref.map(py, |o| o.iter()) },
395 unsafe { leaked_ref.map(py, |o| o.iter()) },
395 )
396 )
396 }
397 }
397
398
398 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
399 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
399 let leaked_ref = self.inner(py).leak_immutable();
400 let leaked_ref = self.inner(py).leak_immutable();
400 DirstateMapKeysIterator::from_inner(
401 DirstateMapKeysIterator::from_inner(
401 py,
402 py,
402 unsafe { leaked_ref.map(py, |o| o.iter()) },
403 unsafe { leaked_ref.map(py, |o| o.iter()) },
403 )
404 )
404 }
405 }
405
406
406 // TODO all copymap* methods, see docstring above
407 // TODO all copymap* methods, see docstring above
407 def copymapcopy(&self) -> PyResult<PyDict> {
408 def copymapcopy(&self) -> PyResult<PyDict> {
408 let dict = PyDict::new(py);
409 let dict = PyDict::new(py);
409 for item in self.inner(py).borrow().copy_map_iter() {
410 for item in self.inner(py).borrow().copy_map_iter() {
410 let (key, value) = item.map_err(|e| v2_error(py, e))?;
411 let (key, value) = item.map_err(|e| v2_error(py, e))?;
411 dict.set_item(
412 dict.set_item(
412 py,
413 py,
413 PyBytes::new(py, key.as_bytes()),
414 PyBytes::new(py, key.as_bytes()),
414 PyBytes::new(py, value.as_bytes()),
415 PyBytes::new(py, value.as_bytes()),
415 )?;
416 )?;
416 }
417 }
417 Ok(dict)
418 Ok(dict)
418 }
419 }
419
420
420 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
421 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
421 let key = key.extract::<PyBytes>(py)?;
422 let key = key.extract::<PyBytes>(py)?;
422 match self
423 match self
423 .inner(py)
424 .inner(py)
424 .borrow()
425 .borrow()
425 .copy_map_get(HgPath::new(key.data(py)))
426 .copy_map_get(HgPath::new(key.data(py)))
426 .map_err(|e| v2_error(py, e))?
427 .map_err(|e| v2_error(py, e))?
427 {
428 {
428 Some(copy) => Ok(PyBytes::new(py, copy.as_bytes())),
429 Some(copy) => Ok(PyBytes::new(py, copy.as_bytes())),
429 None => Err(PyErr::new::<exc::KeyError, _>(
430 None => Err(PyErr::new::<exc::KeyError, _>(
430 py,
431 py,
431 String::from_utf8_lossy(key.data(py)),
432 String::from_utf8_lossy(key.data(py)),
432 )),
433 )),
433 }
434 }
434 }
435 }
435 def copymap(&self) -> PyResult<CopyMap> {
436 def copymap(&self) -> PyResult<CopyMap> {
436 CopyMap::from_inner(py, self.clone_ref(py))
437 CopyMap::from_inner(py, self.clone_ref(py))
437 }
438 }
438
439
439 def copymaplen(&self) -> PyResult<usize> {
440 def copymaplen(&self) -> PyResult<usize> {
440 Ok(self.inner(py).borrow().copy_map_len())
441 Ok(self.inner(py).borrow().copy_map_len())
441 }
442 }
442 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
443 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
443 let key = key.extract::<PyBytes>(py)?;
444 let key = key.extract::<PyBytes>(py)?;
444 self.inner(py)
445 self.inner(py)
445 .borrow()
446 .borrow()
446 .copy_map_contains_key(HgPath::new(key.data(py)))
447 .copy_map_contains_key(HgPath::new(key.data(py)))
447 .map_err(|e| v2_error(py, e))
448 .map_err(|e| v2_error(py, e))
448 }
449 }
449 def copymapget(
450 def copymapget(
450 &self,
451 &self,
451 key: PyObject,
452 key: PyObject,
452 default: Option<PyObject>
453 default: Option<PyObject>
453 ) -> PyResult<Option<PyObject>> {
454 ) -> PyResult<Option<PyObject>> {
454 let key = key.extract::<PyBytes>(py)?;
455 let key = key.extract::<PyBytes>(py)?;
455 match self
456 match self
456 .inner(py)
457 .inner(py)
457 .borrow()
458 .borrow()
458 .copy_map_get(HgPath::new(key.data(py)))
459 .copy_map_get(HgPath::new(key.data(py)))
459 .map_err(|e| v2_error(py, e))?
460 .map_err(|e| v2_error(py, e))?
460 {
461 {
461 Some(copy) => Ok(Some(
462 Some(copy) => Ok(Some(
462 PyBytes::new(py, copy.as_bytes()).into_object(),
463 PyBytes::new(py, copy.as_bytes()).into_object(),
463 )),
464 )),
464 None => Ok(default),
465 None => Ok(default),
465 }
466 }
466 }
467 }
467 def copymapsetitem(
468 def copymapsetitem(
468 &self,
469 &self,
469 key: PyObject,
470 key: PyObject,
470 value: PyObject
471 value: PyObject
471 ) -> PyResult<PyObject> {
472 ) -> PyResult<PyObject> {
472 let key = key.extract::<PyBytes>(py)?;
473 let key = key.extract::<PyBytes>(py)?;
473 let value = value.extract::<PyBytes>(py)?;
474 let value = value.extract::<PyBytes>(py)?;
474 self.inner(py)
475 self.inner(py)
475 .borrow_mut()
476 .borrow_mut()
476 .copy_map_insert(
477 .copy_map_insert(
477 HgPathBuf::from_bytes(key.data(py)),
478 HgPathBuf::from_bytes(key.data(py)),
478 HgPathBuf::from_bytes(value.data(py)),
479 HgPathBuf::from_bytes(value.data(py)),
479 )
480 )
480 .map_err(|e| v2_error(py, e))?;
481 .map_err(|e| v2_error(py, e))?;
481 Ok(py.None())
482 Ok(py.None())
482 }
483 }
483 def copymappop(
484 def copymappop(
484 &self,
485 &self,
485 key: PyObject,
486 key: PyObject,
486 default: Option<PyObject>
487 default: Option<PyObject>
487 ) -> PyResult<Option<PyObject>> {
488 ) -> PyResult<Option<PyObject>> {
488 let key = key.extract::<PyBytes>(py)?;
489 let key = key.extract::<PyBytes>(py)?;
489 match self
490 match self
490 .inner(py)
491 .inner(py)
491 .borrow_mut()
492 .borrow_mut()
492 .copy_map_remove(HgPath::new(key.data(py)))
493 .copy_map_remove(HgPath::new(key.data(py)))
493 .map_err(|e| v2_error(py, e))?
494 .map_err(|e| v2_error(py, e))?
494 {
495 {
495 Some(_) => Ok(None),
496 Some(_) => Ok(None),
496 None => Ok(default),
497 None => Ok(default),
497 }
498 }
498 }
499 }
499
500
500 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
501 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
501 let leaked_ref = self.inner(py).leak_immutable();
502 let leaked_ref = self.inner(py).leak_immutable();
502 CopyMapKeysIterator::from_inner(
503 CopyMapKeysIterator::from_inner(
503 py,
504 py,
504 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
505 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
505 )
506 )
506 }
507 }
507
508
508 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
509 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
509 let leaked_ref = self.inner(py).leak_immutable();
510 let leaked_ref = self.inner(py).leak_immutable();
510 CopyMapItemsIterator::from_inner(
511 CopyMapItemsIterator::from_inner(
511 py,
512 py,
512 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
513 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
513 )
514 )
514 }
515 }
515
516
516 def directories(&self) -> PyResult<PyList> {
517 def directories(&self) -> PyResult<PyList> {
517 let dirs = PyList::new(py, &[]);
518 let dirs = PyList::new(py, &[]);
518 for item in self.inner(py).borrow().iter_directories() {
519 for item in self.inner(py).borrow().iter_directories() {
519 let (path, mtime) = item.map_err(|e| v2_error(py, e))?;
520 let (path, mtime) = item.map_err(|e| v2_error(py, e))?;
520 let path = PyBytes::new(py, path.as_bytes());
521 let path = PyBytes::new(py, path.as_bytes());
521 let mtime = mtime.map(|t| t.0).unwrap_or(-1);
522 let mtime = mtime.map(|t| t.0).unwrap_or(-1);
522 let tuple = (path, (b'd', 0, 0, mtime));
523 let item = make_directory_item(py, mtime as i32)?;
524 let tuple = (path, item);
523 dirs.append(py, tuple.to_py_object(py).into_object())
525 dirs.append(py, tuple.to_py_object(py).into_object())
524 }
526 }
525 Ok(dirs)
527 Ok(dirs)
526 }
528 }
527
529
528 });
530 });
529
531
530 impl DirstateMap {
532 impl DirstateMap {
531 pub fn get_inner_mut<'a>(
533 pub fn get_inner_mut<'a>(
532 &'a self,
534 &'a self,
533 py: Python<'a>,
535 py: Python<'a>,
534 ) -> RefMut<'a, Box<dyn DirstateMapMethods + Send>> {
536 ) -> RefMut<'a, Box<dyn DirstateMapMethods + Send>> {
535 self.inner(py).borrow_mut()
537 self.inner(py).borrow_mut()
536 }
538 }
537 fn translate_key(
539 fn translate_key(
538 py: Python,
540 py: Python,
539 res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>,
541 res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>,
540 ) -> PyResult<Option<PyBytes>> {
542 ) -> PyResult<Option<PyBytes>> {
541 let (f, _entry) = res.map_err(|e| v2_error(py, e))?;
543 let (f, _entry) = res.map_err(|e| v2_error(py, e))?;
542 Ok(Some(PyBytes::new(py, f.as_bytes())))
544 Ok(Some(PyBytes::new(py, f.as_bytes())))
543 }
545 }
544 fn translate_key_value(
546 fn translate_key_value(
545 py: Python,
547 py: Python,
546 res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>,
548 res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>,
547 ) -> PyResult<Option<(PyBytes, PyObject)>> {
549 ) -> PyResult<Option<(PyBytes, PyObject)>> {
548 let (f, entry) = res.map_err(|e| v2_error(py, e))?;
550 let (f, entry) = res.map_err(|e| v2_error(py, e))?;
549 Ok(Some((
551 Ok(Some((
550 PyBytes::new(py, f.as_bytes()),
552 PyBytes::new(py, f.as_bytes()),
551 make_dirstate_item(py, &entry)?,
553 make_dirstate_item(py, &entry)?,
552 )))
554 )))
553 }
555 }
554 }
556 }
555
557
556 py_shared_iterator!(
558 py_shared_iterator!(
557 DirstateMapKeysIterator,
559 DirstateMapKeysIterator,
558 UnsafePyLeaked<StateMapIter<'static>>,
560 UnsafePyLeaked<StateMapIter<'static>>,
559 DirstateMap::translate_key,
561 DirstateMap::translate_key,
560 Option<PyBytes>
562 Option<PyBytes>
561 );
563 );
562
564
563 py_shared_iterator!(
565 py_shared_iterator!(
564 DirstateMapItemsIterator,
566 DirstateMapItemsIterator,
565 UnsafePyLeaked<StateMapIter<'static>>,
567 UnsafePyLeaked<StateMapIter<'static>>,
566 DirstateMap::translate_key_value,
568 DirstateMap::translate_key_value,
567 Option<(PyBytes, PyObject)>
569 Option<(PyBytes, PyObject)>
568 );
570 );
569
571
570 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<Node> {
572 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<Node> {
571 let bytes = obj.extract::<PyBytes>(py)?;
573 let bytes = obj.extract::<PyBytes>(py)?;
572 match bytes.data(py).try_into() {
574 match bytes.data(py).try_into() {
573 Ok(s) => Ok(s),
575 Ok(s) => Ok(s),
574 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
576 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
575 }
577 }
576 }
578 }
577
579
578 pub(super) fn v2_error(py: Python<'_>, _: DirstateV2ParseError) -> PyErr {
580 pub(super) fn v2_error(py: Python<'_>, _: DirstateV2ParseError) -> PyErr {
579 PyErr::new::<exc::ValueError, _>(py, "corrupted dirstate-v2")
581 PyErr::new::<exc::ValueError, _>(py, "corrupted dirstate-v2")
580 }
582 }
General Comments 0
You need to be logged in to leave comments. Login now