##// END OF EJS Templates
rust-dirstate-status: rust-cpython bindings for `dirstate.status`...
Raphaël Gomès -
r43567:478d0b1b default
parent child Browse files
Show More
@@ -0,0 +1,82 b''
1 // status.rs
2 //
3 // Copyright 2019, Raphaël Gomès <rgomes@octobus.net>
4 //
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
7
8 //! Bindings for the `hg::status` module provided by the
9 //! `hg-core` crate. From Python, this will be seen as `rustext.dirstate.status`.
10 //!
11
12 use crate::dirstate::DirstateMap;
13 use cpython::exc::ValueError;
14 use cpython::{
15 PyBytes, PyErr, PyList, PyObject, PyResult, Python, PythonObject,
16 ToPyObject,
17 };
18 use hg::utils::files::get_path_from_bytes;
19
20 use hg::utils::hg_path::HgPath;
21 use hg::{status, utils::hg_path::HgPathBuf};
22
23 /// This will be useless once trait impls for collection are added to `PyBytes`
24 /// upstream.
25 fn collect_pybytes_list<P: AsRef<HgPath>>(
26 py: Python,
27 collection: &[P],
28 ) -> PyList {
29 let list = PyList::new(py, &[]);
30
31 for (i, path) in collection.iter().enumerate() {
32 list.insert_item(
33 py,
34 i,
35 PyBytes::new(py, path.as_ref().as_bytes()).into_object(),
36 )
37 }
38
39 list
40 }
41
42 pub fn status_wrapper(
43 py: Python,
44 dmap: DirstateMap,
45 root_dir: PyObject,
46 files: PyList,
47 list_clean: bool,
48 last_normal_time: i64,
49 check_exec: bool,
50 ) -> PyResult<(PyList, PyList, PyList, PyList, PyList, PyList, PyList)> {
51 let bytes = root_dir.extract::<PyBytes>(py)?;
52 let root_dir = get_path_from_bytes(bytes.data(py));
53
54 let dmap: DirstateMap = dmap.to_py_object(py);
55 let dmap = dmap.get_inner(py);
56
57 let files: PyResult<Vec<HgPathBuf>> = files
58 .iter(py)
59 .map(|f| Ok(HgPathBuf::from_bytes(f.extract::<PyBytes>(py)?.data(py))))
60 .collect();
61 let files = files?;
62
63 let (lookup, status_res) = status(
64 &dmap,
65 &root_dir,
66 &files,
67 list_clean,
68 last_normal_time,
69 check_exec,
70 )
71 .map_err(|e| PyErr::new::<ValueError, _>(py, e.to_string()))?;
72
73 let modified = collect_pybytes_list(py, status_res.modified.as_ref());
74 let added = collect_pybytes_list(py, status_res.added.as_ref());
75 let removed = collect_pybytes_list(py, status_res.removed.as_ref());
76 let deleted = collect_pybytes_list(py, status_res.deleted.as_ref());
77 let clean = collect_pybytes_list(py, status_res.clean.as_ref());
78 let lookup = collect_pybytes_list(py, lookup.as_ref());
79 let unknown = PyList::new(py, &[]);
80
81 Ok((lookup, modified, added, removed, deleted, unknown, clean))
82 }
@@ -1,114 +1,132 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 use crate::dirstate::{dirs_multiset::Dirs, dirstate_map::DirstateMap};
15 mod status;
16 use crate::dirstate::{
17 dirs_multiset::Dirs, dirstate_map::DirstateMap, status::status_wrapper,
18 };
16 use cpython::{
19 use cpython::{
17 exc, PyBytes, PyDict, PyErr, PyModule, PyObject, PyResult, PySequence,
20 exc, PyBytes, PyDict, PyErr, PyList, PyModule, PyObject, PyResult,
18 Python,
21 PySequence, Python,
19 };
22 };
20 use hg::{
23 use hg::{
21 utils::hg_path::HgPathBuf, DirstateEntry, DirstateParseError, EntryState,
24 utils::hg_path::HgPathBuf, DirstateEntry, DirstateParseError, EntryState,
22 StateMap,
25 StateMap,
23 };
26 };
24 use libc::{c_char, c_int};
27 use libc::{c_char, c_int};
25 use std::convert::TryFrom;
28 use std::convert::TryFrom;
26
29
27 // C code uses a custom `dirstate_tuple` type, checks in multiple instances
30 // C code uses a custom `dirstate_tuple` type, checks in multiple instances
28 // for this type, and raises a Python `Exception` if the check does not pass.
31 // for this type, and raises a Python `Exception` if the check does not pass.
29 // Because this type differs only in name from the regular Python tuple, it
32 // Because this type differs only in name from the regular Python tuple, it
30 // would be a good idea in the near future to remove it entirely to allow
33 // would be a good idea in the near future to remove it entirely to allow
31 // for a pure Python tuple of the same effective structure to be used,
34 // for a pure Python tuple of the same effective structure to be used,
32 // rendering this type and the capsule below useless.
35 // rendering this type and the capsule below useless.
33 py_capsule_fn!(
36 py_capsule_fn!(
34 from mercurial.cext.parsers import make_dirstate_tuple_CAPI
37 from mercurial.cext.parsers import make_dirstate_tuple_CAPI
35 as make_dirstate_tuple_capi
38 as make_dirstate_tuple_capi
36 signature (
39 signature (
37 state: c_char,
40 state: c_char,
38 mode: c_int,
41 mode: c_int,
39 size: c_int,
42 size: c_int,
40 mtime: c_int,
43 mtime: c_int,
41 ) -> *mut RawPyObject
44 ) -> *mut RawPyObject
42 );
45 );
43
46
44 pub fn make_dirstate_tuple(
47 pub fn make_dirstate_tuple(
45 py: Python,
48 py: Python,
46 entry: &DirstateEntry,
49 entry: &DirstateEntry,
47 ) -> PyResult<PyObject> {
50 ) -> PyResult<PyObject> {
48 // might be silly to retrieve capsule function in hot loop
51 // might be silly to retrieve capsule function in hot loop
49 let make = make_dirstate_tuple_capi::retrieve(py)?;
52 let make = make_dirstate_tuple_capi::retrieve(py)?;
50
53
51 let &DirstateEntry {
54 let &DirstateEntry {
52 state,
55 state,
53 mode,
56 mode,
54 size,
57 size,
55 mtime,
58 mtime,
56 } = entry;
59 } = entry;
57 // Explicitly go through u8 first, then cast to platform-specific `c_char`
60 // Explicitly go through u8 first, then cast to platform-specific `c_char`
58 // because Into<u8> has a specific implementation while `as c_char` would
61 // because Into<u8> has a specific implementation while `as c_char` would
59 // just do a naive enum cast.
62 // just do a naive enum cast.
60 let state_code: u8 = state.into();
63 let state_code: u8 = state.into();
61
64
62 let maybe_obj = unsafe {
65 let maybe_obj = unsafe {
63 let ptr = make(state_code as c_char, mode, size, mtime);
66 let ptr = make(state_code as c_char, mode, size, mtime);
64 PyObject::from_owned_ptr_opt(py, ptr)
67 PyObject::from_owned_ptr_opt(py, ptr)
65 };
68 };
66 maybe_obj.ok_or_else(|| PyErr::fetch(py))
69 maybe_obj.ok_or_else(|| PyErr::fetch(py))
67 }
70 }
68
71
69 pub fn extract_dirstate(py: Python, dmap: &PyDict) -> Result<StateMap, PyErr> {
72 pub fn extract_dirstate(py: Python, dmap: &PyDict) -> Result<StateMap, PyErr> {
70 dmap.items(py)
73 dmap.items(py)
71 .iter()
74 .iter()
72 .map(|(filename, stats)| {
75 .map(|(filename, stats)| {
73 let stats = stats.extract::<PySequence>(py)?;
76 let stats = stats.extract::<PySequence>(py)?;
74 let state = stats.get_item(py, 0)?.extract::<PyBytes>(py)?;
77 let state = stats.get_item(py, 0)?.extract::<PyBytes>(py)?;
75 let state = EntryState::try_from(state.data(py)[0]).map_err(
78 let state = EntryState::try_from(state.data(py)[0]).map_err(
76 |e: DirstateParseError| {
79 |e: DirstateParseError| {
77 PyErr::new::<exc::ValueError, _>(py, e.to_string())
80 PyErr::new::<exc::ValueError, _>(py, e.to_string())
78 },
81 },
79 )?;
82 )?;
80 let mode = stats.get_item(py, 1)?.extract(py)?;
83 let mode = stats.get_item(py, 1)?.extract(py)?;
81 let size = stats.get_item(py, 2)?.extract(py)?;
84 let size = stats.get_item(py, 2)?.extract(py)?;
82 let mtime = stats.get_item(py, 3)?.extract(py)?;
85 let mtime = stats.get_item(py, 3)?.extract(py)?;
83 let filename = filename.extract::<PyBytes>(py)?;
86 let filename = filename.extract::<PyBytes>(py)?;
84 let filename = filename.data(py);
87 let filename = filename.data(py);
85 Ok((
88 Ok((
86 HgPathBuf::from(filename.to_owned()),
89 HgPathBuf::from(filename.to_owned()),
87 DirstateEntry {
90 DirstateEntry {
88 state,
91 state,
89 mode,
92 mode,
90 size,
93 size,
91 mtime,
94 mtime,
92 },
95 },
93 ))
96 ))
94 })
97 })
95 .collect()
98 .collect()
96 }
99 }
97
100
98 /// Create the module, with `__package__` given from parent
101 /// Create the module, with `__package__` given from parent
99 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
102 pub fn init_module(py: Python, package: &str) -> PyResult<PyModule> {
100 let dotted_name = &format!("{}.dirstate", package);
103 let dotted_name = &format!("{}.dirstate", package);
101 let m = PyModule::new(py, dotted_name)?;
104 let m = PyModule::new(py, dotted_name)?;
102
105
103 m.add(py, "__package__", package)?;
106 m.add(py, "__package__", package)?;
104 m.add(py, "__doc__", "Dirstate - Rust implementation")?;
107 m.add(py, "__doc__", "Dirstate - Rust implementation")?;
105
108
106 m.add_class::<Dirs>(py)?;
109 m.add_class::<Dirs>(py)?;
107 m.add_class::<DirstateMap>(py)?;
110 m.add_class::<DirstateMap>(py)?;
111 m.add(
112 py,
113 "status",
114 py_fn!(
115 py,
116 status_wrapper(
117 dmap: DirstateMap,
118 root_dir: PyObject,
119 files: PyList,
120 list_clean: bool,
121 last_normal_time: i64,
122 check_exec: bool
123 )
124 ),
125 )?;
108
126
109 let sys = PyModule::import(py, "sys")?;
127 let sys = PyModule::import(py, "sys")?;
110 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
128 let sys_modules: PyDict = sys.get(py, "modules")?.extract(py)?;
111 sys_modules.set_item(py, dotted_name, &m)?;
129 sys_modules.set_item(py, dotted_name, &m)?;
112
130
113 Ok(m)
131 Ok(m)
114 }
132 }
@@ -1,510 +1,516 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;
11 use std::cell::{Ref, RefCell};
12 use std::convert::TryInto;
12 use std::convert::TryInto;
13 use std::time::Duration;
13 use std::time::Duration;
14
14
15 use cpython::{
15 use cpython::{
16 exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyObject,
16 exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyObject,
17 PyResult, PyTuple, Python, PythonObject, ToPyObject,
17 PyResult, PyTuple, Python, PythonObject, ToPyObject,
18 };
18 };
19
19
20 use crate::{
20 use crate::{
21 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
21 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
22 dirstate::{dirs_multiset::Dirs, make_dirstate_tuple},
22 dirstate::{dirs_multiset::Dirs, make_dirstate_tuple},
23 ref_sharing::{PyLeakedRef, PySharedRefCell},
23 ref_sharing::{PyLeakedRef, PySharedRefCell},
24 };
24 };
25 use hg::{
25 use hg::{
26 utils::hg_path::{HgPath, HgPathBuf},
26 utils::hg_path::{HgPath, HgPathBuf},
27 DirsMultiset, DirstateEntry, DirstateMap as RustDirstateMap,
27 DirsMultiset, DirstateEntry, DirstateMap as RustDirstateMap,
28 DirstateParents, DirstateParseError, EntryState, StateMapIter,
28 DirstateParents, DirstateParseError, EntryState, StateMapIter,
29 PARENT_SIZE,
29 PARENT_SIZE,
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 data inner: PySharedRefCell<RustDirstateMap>;
45 data inner: PySharedRefCell<RustDirstateMap>;
46
46
47 def __new__(_cls, _root: PyObject) -> PyResult<Self> {
47 def __new__(_cls, _root: PyObject) -> PyResult<Self> {
48 let inner = RustDirstateMap::default();
48 let inner = RustDirstateMap::default();
49 Self::create_instance(
49 Self::create_instance(
50 py,
50 py,
51 PySharedRefCell::new(inner),
51 PySharedRefCell::new(inner),
52 )
52 )
53 }
53 }
54
54
55 def clear(&self) -> PyResult<PyObject> {
55 def clear(&self) -> PyResult<PyObject> {
56 self.inner_shared(py).borrow_mut()?.clear();
56 self.inner_shared(py).borrow_mut()?.clear();
57 Ok(py.None())
57 Ok(py.None())
58 }
58 }
59
59
60 def get(
60 def get(
61 &self,
61 &self,
62 key: PyObject,
62 key: PyObject,
63 default: Option<PyObject> = None
63 default: Option<PyObject> = None
64 ) -> PyResult<Option<PyObject>> {
64 ) -> PyResult<Option<PyObject>> {
65 let key = key.extract::<PyBytes>(py)?;
65 let key = key.extract::<PyBytes>(py)?;
66 match self.inner(py).borrow().get(HgPath::new(key.data(py))) {
66 match self.inner(py).borrow().get(HgPath::new(key.data(py))) {
67 Some(entry) => {
67 Some(entry) => {
68 Ok(Some(make_dirstate_tuple(py, entry)?))
68 Ok(Some(make_dirstate_tuple(py, entry)?))
69 },
69 },
70 None => Ok(default)
70 None => Ok(default)
71 }
71 }
72 }
72 }
73
73
74 def addfile(
74 def addfile(
75 &self,
75 &self,
76 f: PyObject,
76 f: PyObject,
77 oldstate: PyObject,
77 oldstate: PyObject,
78 state: PyObject,
78 state: PyObject,
79 mode: PyObject,
79 mode: PyObject,
80 size: PyObject,
80 size: PyObject,
81 mtime: PyObject
81 mtime: PyObject
82 ) -> PyResult<PyObject> {
82 ) -> PyResult<PyObject> {
83 self.inner_shared(py).borrow_mut()?.add_file(
83 self.inner_shared(py).borrow_mut()?.add_file(
84 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
84 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
85 oldstate.extract::<PyBytes>(py)?.data(py)[0]
85 oldstate.extract::<PyBytes>(py)?.data(py)[0]
86 .try_into()
86 .try_into()
87 .map_err(|e: DirstateParseError| {
87 .map_err(|e: DirstateParseError| {
88 PyErr::new::<exc::ValueError, _>(py, e.to_string())
88 PyErr::new::<exc::ValueError, _>(py, e.to_string())
89 })?,
89 })?,
90 DirstateEntry {
90 DirstateEntry {
91 state: state.extract::<PyBytes>(py)?.data(py)[0]
91 state: state.extract::<PyBytes>(py)?.data(py)[0]
92 .try_into()
92 .try_into()
93 .map_err(|e: DirstateParseError| {
93 .map_err(|e: DirstateParseError| {
94 PyErr::new::<exc::ValueError, _>(py, e.to_string())
94 PyErr::new::<exc::ValueError, _>(py, e.to_string())
95 })?,
95 })?,
96 mode: mode.extract(py)?,
96 mode: mode.extract(py)?,
97 size: size.extract(py)?,
97 size: size.extract(py)?,
98 mtime: mtime.extract(py)?,
98 mtime: mtime.extract(py)?,
99 },
99 },
100 );
100 );
101 Ok(py.None())
101 Ok(py.None())
102 }
102 }
103
103
104 def removefile(
104 def removefile(
105 &self,
105 &self,
106 f: PyObject,
106 f: PyObject,
107 oldstate: PyObject,
107 oldstate: PyObject,
108 size: PyObject
108 size: PyObject
109 ) -> PyResult<PyObject> {
109 ) -> PyResult<PyObject> {
110 self.inner_shared(py).borrow_mut()?
110 self.inner_shared(py).borrow_mut()?
111 .remove_file(
111 .remove_file(
112 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
112 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
113 oldstate.extract::<PyBytes>(py)?.data(py)[0]
113 oldstate.extract::<PyBytes>(py)?.data(py)[0]
114 .try_into()
114 .try_into()
115 .map_err(|e: DirstateParseError| {
115 .map_err(|e: DirstateParseError| {
116 PyErr::new::<exc::ValueError, _>(py, e.to_string())
116 PyErr::new::<exc::ValueError, _>(py, e.to_string())
117 })?,
117 })?,
118 size.extract(py)?,
118 size.extract(py)?,
119 )
119 )
120 .or_else(|_| {
120 .or_else(|_| {
121 Err(PyErr::new::<exc::OSError, _>(
121 Err(PyErr::new::<exc::OSError, _>(
122 py,
122 py,
123 "Dirstate error".to_string(),
123 "Dirstate error".to_string(),
124 ))
124 ))
125 })?;
125 })?;
126 Ok(py.None())
126 Ok(py.None())
127 }
127 }
128
128
129 def dropfile(
129 def dropfile(
130 &self,
130 &self,
131 f: PyObject,
131 f: PyObject,
132 oldstate: PyObject
132 oldstate: PyObject
133 ) -> PyResult<PyBool> {
133 ) -> PyResult<PyBool> {
134 self.inner_shared(py).borrow_mut()?
134 self.inner_shared(py).borrow_mut()?
135 .drop_file(
135 .drop_file(
136 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
136 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
137 oldstate.extract::<PyBytes>(py)?.data(py)[0]
137 oldstate.extract::<PyBytes>(py)?.data(py)[0]
138 .try_into()
138 .try_into()
139 .map_err(|e: DirstateParseError| {
139 .map_err(|e: DirstateParseError| {
140 PyErr::new::<exc::ValueError, _>(py, e.to_string())
140 PyErr::new::<exc::ValueError, _>(py, e.to_string())
141 })?,
141 })?,
142 )
142 )
143 .and_then(|b| Ok(b.to_py_object(py)))
143 .and_then(|b| Ok(b.to_py_object(py)))
144 .or_else(|_| {
144 .or_else(|_| {
145 Err(PyErr::new::<exc::OSError, _>(
145 Err(PyErr::new::<exc::OSError, _>(
146 py,
146 py,
147 "Dirstate error".to_string(),
147 "Dirstate error".to_string(),
148 ))
148 ))
149 })
149 })
150 }
150 }
151
151
152 def clearambiguoustimes(
152 def clearambiguoustimes(
153 &self,
153 &self,
154 files: PyObject,
154 files: PyObject,
155 now: PyObject
155 now: PyObject
156 ) -> PyResult<PyObject> {
156 ) -> PyResult<PyObject> {
157 let files: PyResult<Vec<HgPathBuf>> = files
157 let files: PyResult<Vec<HgPathBuf>> = files
158 .iter(py)?
158 .iter(py)?
159 .map(|filename| {
159 .map(|filename| {
160 Ok(HgPathBuf::from_bytes(
160 Ok(HgPathBuf::from_bytes(
161 filename?.extract::<PyBytes>(py)?.data(py),
161 filename?.extract::<PyBytes>(py)?.data(py),
162 ))
162 ))
163 })
163 })
164 .collect();
164 .collect();
165 self.inner_shared(py).borrow_mut()?
165 self.inner_shared(py).borrow_mut()?
166 .clear_ambiguous_times(files?, now.extract(py)?);
166 .clear_ambiguous_times(files?, now.extract(py)?);
167 Ok(py.None())
167 Ok(py.None())
168 }
168 }
169
169
170 // TODO share the reference
170 // TODO share the reference
171 def nonnormalentries(&self) -> PyResult<PyObject> {
171 def nonnormalentries(&self) -> PyResult<PyObject> {
172 let (non_normal, other_parent) =
172 let (non_normal, other_parent) =
173 self.inner(py).borrow().non_normal_other_parent_entries();
173 self.inner(py).borrow().non_normal_other_parent_entries();
174
174
175 let locals = PyDict::new(py);
175 let locals = PyDict::new(py);
176 locals.set_item(
176 locals.set_item(
177 py,
177 py,
178 "non_normal",
178 "non_normal",
179 non_normal
179 non_normal
180 .iter()
180 .iter()
181 .map(|v| PyBytes::new(py, v.as_ref()))
181 .map(|v| PyBytes::new(py, v.as_ref()))
182 .collect::<Vec<PyBytes>>()
182 .collect::<Vec<PyBytes>>()
183 .to_py_object(py),
183 .to_py_object(py),
184 )?;
184 )?;
185 locals.set_item(
185 locals.set_item(
186 py,
186 py,
187 "other_parent",
187 "other_parent",
188 other_parent
188 other_parent
189 .iter()
189 .iter()
190 .map(|v| PyBytes::new(py, v.as_ref()))
190 .map(|v| PyBytes::new(py, v.as_ref()))
191 .collect::<Vec<PyBytes>>()
191 .collect::<Vec<PyBytes>>()
192 .to_py_object(py),
192 .to_py_object(py),
193 )?;
193 )?;
194
194
195 py.eval("set(non_normal), set(other_parent)", None, Some(&locals))
195 py.eval("set(non_normal), set(other_parent)", None, Some(&locals))
196 }
196 }
197
197
198 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
198 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
199 let d = d.extract::<PyBytes>(py)?;
199 let d = d.extract::<PyBytes>(py)?;
200 Ok(self.inner_shared(py).borrow_mut()?
200 Ok(self.inner_shared(py).borrow_mut()?
201 .has_tracked_dir(HgPath::new(d.data(py)))
201 .has_tracked_dir(HgPath::new(d.data(py)))
202 .to_py_object(py))
202 .to_py_object(py))
203 }
203 }
204
204
205 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
205 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
206 let d = d.extract::<PyBytes>(py)?;
206 let d = d.extract::<PyBytes>(py)?;
207 Ok(self.inner_shared(py).borrow_mut()?
207 Ok(self.inner_shared(py).borrow_mut()?
208 .has_dir(HgPath::new(d.data(py)))
208 .has_dir(HgPath::new(d.data(py)))
209 .to_py_object(py))
209 .to_py_object(py))
210 }
210 }
211
211
212 def parents(&self, st: PyObject) -> PyResult<PyTuple> {
212 def parents(&self, st: PyObject) -> PyResult<PyTuple> {
213 self.inner_shared(py).borrow_mut()?
213 self.inner_shared(py).borrow_mut()?
214 .parents(st.extract::<PyBytes>(py)?.data(py))
214 .parents(st.extract::<PyBytes>(py)?.data(py))
215 .and_then(|d| {
215 .and_then(|d| {
216 Ok((PyBytes::new(py, &d.p1), PyBytes::new(py, &d.p2))
216 Ok((PyBytes::new(py, &d.p1), PyBytes::new(py, &d.p2))
217 .to_py_object(py))
217 .to_py_object(py))
218 })
218 })
219 .or_else(|_| {
219 .or_else(|_| {
220 Err(PyErr::new::<exc::OSError, _>(
220 Err(PyErr::new::<exc::OSError, _>(
221 py,
221 py,
222 "Dirstate error".to_string(),
222 "Dirstate error".to_string(),
223 ))
223 ))
224 })
224 })
225 }
225 }
226
226
227 def setparents(&self, p1: PyObject, p2: PyObject) -> PyResult<PyObject> {
227 def setparents(&self, p1: PyObject, p2: PyObject) -> PyResult<PyObject> {
228 let p1 = extract_node_id(py, &p1)?;
228 let p1 = extract_node_id(py, &p1)?;
229 let p2 = extract_node_id(py, &p2)?;
229 let p2 = extract_node_id(py, &p2)?;
230
230
231 self.inner_shared(py).borrow_mut()?
231 self.inner_shared(py).borrow_mut()?
232 .set_parents(&DirstateParents { p1, p2 });
232 .set_parents(&DirstateParents { p1, p2 });
233 Ok(py.None())
233 Ok(py.None())
234 }
234 }
235
235
236 def read(&self, st: PyObject) -> PyResult<Option<PyObject>> {
236 def read(&self, st: PyObject) -> PyResult<Option<PyObject>> {
237 match self.inner_shared(py).borrow_mut()?
237 match self.inner_shared(py).borrow_mut()?
238 .read(st.extract::<PyBytes>(py)?.data(py))
238 .read(st.extract::<PyBytes>(py)?.data(py))
239 {
239 {
240 Ok(Some(parents)) => Ok(Some(
240 Ok(Some(parents)) => Ok(Some(
241 (PyBytes::new(py, &parents.p1), PyBytes::new(py, &parents.p2))
241 (PyBytes::new(py, &parents.p1), PyBytes::new(py, &parents.p2))
242 .to_py_object(py)
242 .to_py_object(py)
243 .into_object(),
243 .into_object(),
244 )),
244 )),
245 Ok(None) => Ok(Some(py.None())),
245 Ok(None) => Ok(Some(py.None())),
246 Err(_) => Err(PyErr::new::<exc::OSError, _>(
246 Err(_) => Err(PyErr::new::<exc::OSError, _>(
247 py,
247 py,
248 "Dirstate error".to_string(),
248 "Dirstate error".to_string(),
249 )),
249 )),
250 }
250 }
251 }
251 }
252 def write(
252 def write(
253 &self,
253 &self,
254 p1: PyObject,
254 p1: PyObject,
255 p2: PyObject,
255 p2: PyObject,
256 now: PyObject
256 now: PyObject
257 ) -> PyResult<PyBytes> {
257 ) -> PyResult<PyBytes> {
258 let now = Duration::new(now.extract(py)?, 0);
258 let now = Duration::new(now.extract(py)?, 0);
259 let parents = DirstateParents {
259 let parents = DirstateParents {
260 p1: extract_node_id(py, &p1)?,
260 p1: extract_node_id(py, &p1)?,
261 p2: extract_node_id(py, &p2)?,
261 p2: extract_node_id(py, &p2)?,
262 };
262 };
263
263
264 match self.inner_shared(py).borrow_mut()?.pack(parents, now) {
264 match self.inner_shared(py).borrow_mut()?.pack(parents, now) {
265 Ok(packed) => Ok(PyBytes::new(py, &packed)),
265 Ok(packed) => Ok(PyBytes::new(py, &packed)),
266 Err(_) => Err(PyErr::new::<exc::OSError, _>(
266 Err(_) => Err(PyErr::new::<exc::OSError, _>(
267 py,
267 py,
268 "Dirstate error".to_string(),
268 "Dirstate error".to_string(),
269 )),
269 )),
270 }
270 }
271 }
271 }
272
272
273 def filefoldmapasdict(&self) -> PyResult<PyDict> {
273 def filefoldmapasdict(&self) -> PyResult<PyDict> {
274 let dict = PyDict::new(py);
274 let dict = PyDict::new(py);
275 for (key, value) in
275 for (key, value) in
276 self.inner_shared(py).borrow_mut()?.build_file_fold_map().iter()
276 self.inner_shared(py).borrow_mut()?.build_file_fold_map().iter()
277 {
277 {
278 dict.set_item(py, key.as_ref().to_vec(), value.as_ref().to_vec())?;
278 dict.set_item(py, key.as_ref().to_vec(), value.as_ref().to_vec())?;
279 }
279 }
280 Ok(dict)
280 Ok(dict)
281 }
281 }
282
282
283 def __len__(&self) -> PyResult<usize> {
283 def __len__(&self) -> PyResult<usize> {
284 Ok(self.inner(py).borrow().len())
284 Ok(self.inner(py).borrow().len())
285 }
285 }
286
286
287 def __contains__(&self, key: PyObject) -> PyResult<bool> {
287 def __contains__(&self, key: PyObject) -> PyResult<bool> {
288 let key = key.extract::<PyBytes>(py)?;
288 let key = key.extract::<PyBytes>(py)?;
289 Ok(self.inner(py).borrow().contains_key(HgPath::new(key.data(py))))
289 Ok(self.inner(py).borrow().contains_key(HgPath::new(key.data(py))))
290 }
290 }
291
291
292 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
292 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
293 let key = key.extract::<PyBytes>(py)?;
293 let key = key.extract::<PyBytes>(py)?;
294 let key = HgPath::new(key.data(py));
294 let key = HgPath::new(key.data(py));
295 match self.inner(py).borrow().get(key) {
295 match self.inner(py).borrow().get(key) {
296 Some(entry) => {
296 Some(entry) => {
297 Ok(make_dirstate_tuple(py, entry)?)
297 Ok(make_dirstate_tuple(py, entry)?)
298 },
298 },
299 None => Err(PyErr::new::<exc::KeyError, _>(
299 None => Err(PyErr::new::<exc::KeyError, _>(
300 py,
300 py,
301 String::from_utf8_lossy(key.as_bytes()),
301 String::from_utf8_lossy(key.as_bytes()),
302 )),
302 )),
303 }
303 }
304 }
304 }
305
305
306 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
306 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
307 let (leak_handle, leaked_ref) =
307 let (leak_handle, leaked_ref) =
308 unsafe { self.inner_shared(py).leak_immutable()? };
308 unsafe { self.inner_shared(py).leak_immutable()? };
309 DirstateMapKeysIterator::from_inner(
309 DirstateMapKeysIterator::from_inner(
310 py,
310 py,
311 leak_handle,
311 leak_handle,
312 leaked_ref.iter(),
312 leaked_ref.iter(),
313 )
313 )
314 }
314 }
315
315
316 def items(&self) -> PyResult<DirstateMapItemsIterator> {
316 def items(&self) -> PyResult<DirstateMapItemsIterator> {
317 let (leak_handle, leaked_ref) =
317 let (leak_handle, leaked_ref) =
318 unsafe { self.inner_shared(py).leak_immutable()? };
318 unsafe { self.inner_shared(py).leak_immutable()? };
319 DirstateMapItemsIterator::from_inner(
319 DirstateMapItemsIterator::from_inner(
320 py,
320 py,
321 leak_handle,
321 leak_handle,
322 leaked_ref.iter(),
322 leaked_ref.iter(),
323 )
323 )
324 }
324 }
325
325
326 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
326 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
327 let (leak_handle, leaked_ref) =
327 let (leak_handle, leaked_ref) =
328 unsafe { self.inner_shared(py).leak_immutable()? };
328 unsafe { self.inner_shared(py).leak_immutable()? };
329 DirstateMapKeysIterator::from_inner(
329 DirstateMapKeysIterator::from_inner(
330 py,
330 py,
331 leak_handle,
331 leak_handle,
332 leaked_ref.iter(),
332 leaked_ref.iter(),
333 )
333 )
334 }
334 }
335
335
336 def getdirs(&self) -> PyResult<Dirs> {
336 def getdirs(&self) -> PyResult<Dirs> {
337 // TODO don't copy, share the reference
337 // TODO don't copy, share the reference
338 self.inner_shared(py).borrow_mut()?.set_dirs();
338 self.inner_shared(py).borrow_mut()?.set_dirs();
339 Dirs::from_inner(
339 Dirs::from_inner(
340 py,
340 py,
341 DirsMultiset::from_dirstate(
341 DirsMultiset::from_dirstate(
342 &self.inner(py).borrow(),
342 &self.inner(py).borrow(),
343 Some(EntryState::Removed),
343 Some(EntryState::Removed),
344 ),
344 ),
345 )
345 )
346 }
346 }
347 def getalldirs(&self) -> PyResult<Dirs> {
347 def getalldirs(&self) -> PyResult<Dirs> {
348 // TODO don't copy, share the reference
348 // TODO don't copy, share the reference
349 self.inner_shared(py).borrow_mut()?.set_all_dirs();
349 self.inner_shared(py).borrow_mut()?.set_all_dirs();
350 Dirs::from_inner(
350 Dirs::from_inner(
351 py,
351 py,
352 DirsMultiset::from_dirstate(
352 DirsMultiset::from_dirstate(
353 &self.inner(py).borrow(),
353 &self.inner(py).borrow(),
354 None,
354 None,
355 ),
355 ),
356 )
356 )
357 }
357 }
358
358
359 // TODO all copymap* methods, see docstring above
359 // TODO all copymap* methods, see docstring above
360 def copymapcopy(&self) -> PyResult<PyDict> {
360 def copymapcopy(&self) -> PyResult<PyDict> {
361 let dict = PyDict::new(py);
361 let dict = PyDict::new(py);
362 for (key, value) in self.inner(py).borrow().copy_map.iter() {
362 for (key, value) in self.inner(py).borrow().copy_map.iter() {
363 dict.set_item(
363 dict.set_item(
364 py,
364 py,
365 PyBytes::new(py, key.as_ref()),
365 PyBytes::new(py, key.as_ref()),
366 PyBytes::new(py, value.as_ref()),
366 PyBytes::new(py, value.as_ref()),
367 )?;
367 )?;
368 }
368 }
369 Ok(dict)
369 Ok(dict)
370 }
370 }
371
371
372 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
372 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
373 let key = key.extract::<PyBytes>(py)?;
373 let key = key.extract::<PyBytes>(py)?;
374 match self.inner(py).borrow().copy_map.get(HgPath::new(key.data(py))) {
374 match self.inner(py).borrow().copy_map.get(HgPath::new(key.data(py))) {
375 Some(copy) => Ok(PyBytes::new(py, copy.as_ref())),
375 Some(copy) => Ok(PyBytes::new(py, copy.as_ref())),
376 None => Err(PyErr::new::<exc::KeyError, _>(
376 None => Err(PyErr::new::<exc::KeyError, _>(
377 py,
377 py,
378 String::from_utf8_lossy(key.data(py)),
378 String::from_utf8_lossy(key.data(py)),
379 )),
379 )),
380 }
380 }
381 }
381 }
382 def copymap(&self) -> PyResult<CopyMap> {
382 def copymap(&self) -> PyResult<CopyMap> {
383 CopyMap::from_inner(py, self.clone_ref(py))
383 CopyMap::from_inner(py, self.clone_ref(py))
384 }
384 }
385
385
386 def copymaplen(&self) -> PyResult<usize> {
386 def copymaplen(&self) -> PyResult<usize> {
387 Ok(self.inner(py).borrow().copy_map.len())
387 Ok(self.inner(py).borrow().copy_map.len())
388 }
388 }
389 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
389 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
390 let key = key.extract::<PyBytes>(py)?;
390 let key = key.extract::<PyBytes>(py)?;
391 Ok(self
391 Ok(self
392 .inner(py)
392 .inner(py)
393 .borrow()
393 .borrow()
394 .copy_map
394 .copy_map
395 .contains_key(HgPath::new(key.data(py))))
395 .contains_key(HgPath::new(key.data(py))))
396 }
396 }
397 def copymapget(
397 def copymapget(
398 &self,
398 &self,
399 key: PyObject,
399 key: PyObject,
400 default: Option<PyObject>
400 default: Option<PyObject>
401 ) -> PyResult<Option<PyObject>> {
401 ) -> PyResult<Option<PyObject>> {
402 let key = key.extract::<PyBytes>(py)?;
402 let key = key.extract::<PyBytes>(py)?;
403 match self
403 match self
404 .inner(py)
404 .inner(py)
405 .borrow()
405 .borrow()
406 .copy_map
406 .copy_map
407 .get(HgPath::new(key.data(py)))
407 .get(HgPath::new(key.data(py)))
408 {
408 {
409 Some(copy) => Ok(Some(
409 Some(copy) => Ok(Some(
410 PyBytes::new(py, copy.as_ref()).into_object(),
410 PyBytes::new(py, copy.as_ref()).into_object(),
411 )),
411 )),
412 None => Ok(default),
412 None => Ok(default),
413 }
413 }
414 }
414 }
415 def copymapsetitem(
415 def copymapsetitem(
416 &self,
416 &self,
417 key: PyObject,
417 key: PyObject,
418 value: PyObject
418 value: PyObject
419 ) -> PyResult<PyObject> {
419 ) -> PyResult<PyObject> {
420 let key = key.extract::<PyBytes>(py)?;
420 let key = key.extract::<PyBytes>(py)?;
421 let value = value.extract::<PyBytes>(py)?;
421 let value = value.extract::<PyBytes>(py)?;
422 self.inner_shared(py).borrow_mut()?.copy_map.insert(
422 self.inner_shared(py).borrow_mut()?.copy_map.insert(
423 HgPathBuf::from_bytes(key.data(py)),
423 HgPathBuf::from_bytes(key.data(py)),
424 HgPathBuf::from_bytes(value.data(py)),
424 HgPathBuf::from_bytes(value.data(py)),
425 );
425 );
426 Ok(py.None())
426 Ok(py.None())
427 }
427 }
428 def copymappop(
428 def copymappop(
429 &self,
429 &self,
430 key: PyObject,
430 key: PyObject,
431 default: Option<PyObject>
431 default: Option<PyObject>
432 ) -> PyResult<Option<PyObject>> {
432 ) -> PyResult<Option<PyObject>> {
433 let key = key.extract::<PyBytes>(py)?;
433 let key = key.extract::<PyBytes>(py)?;
434 match self
434 match self
435 .inner_shared(py)
435 .inner_shared(py)
436 .borrow_mut()?
436 .borrow_mut()?
437 .copy_map
437 .copy_map
438 .remove(HgPath::new(key.data(py)))
438 .remove(HgPath::new(key.data(py)))
439 {
439 {
440 Some(_) => Ok(None),
440 Some(_) => Ok(None),
441 None => Ok(default),
441 None => Ok(default),
442 }
442 }
443 }
443 }
444
444
445 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
445 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
446 let (leak_handle, leaked_ref) =
446 let (leak_handle, leaked_ref) =
447 unsafe { self.inner_shared(py).leak_immutable()? };
447 unsafe { self.inner_shared(py).leak_immutable()? };
448 CopyMapKeysIterator::from_inner(
448 CopyMapKeysIterator::from_inner(
449 py,
449 py,
450 leak_handle,
450 leak_handle,
451 leaked_ref.copy_map.iter(),
451 leaked_ref.copy_map.iter(),
452 )
452 )
453 }
453 }
454
454
455 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
455 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
456 let (leak_handle, leaked_ref) =
456 let (leak_handle, leaked_ref) =
457 unsafe { self.inner_shared(py).leak_immutable()? };
457 unsafe { self.inner_shared(py).leak_immutable()? };
458 CopyMapItemsIterator::from_inner(
458 CopyMapItemsIterator::from_inner(
459 py,
459 py,
460 leak_handle,
460 leak_handle,
461 leaked_ref.copy_map.iter(),
461 leaked_ref.copy_map.iter(),
462 )
462 )
463 }
463 }
464
464
465 });
465 });
466
466
467 impl DirstateMap {
467 impl DirstateMap {
468 pub fn get_inner<'a>(
469 &'a self,
470 py: Python<'a>,
471 ) -> Ref<'a, RustDirstateMap> {
472 self.inner_shared(py).borrow()
473 }
468 fn translate_key(
474 fn translate_key(
469 py: Python,
475 py: Python,
470 res: (&HgPathBuf, &DirstateEntry),
476 res: (&HgPathBuf, &DirstateEntry),
471 ) -> PyResult<Option<PyBytes>> {
477 ) -> PyResult<Option<PyBytes>> {
472 Ok(Some(PyBytes::new(py, res.0.as_ref())))
478 Ok(Some(PyBytes::new(py, res.0.as_ref())))
473 }
479 }
474 fn translate_key_value(
480 fn translate_key_value(
475 py: Python,
481 py: Python,
476 res: (&HgPathBuf, &DirstateEntry),
482 res: (&HgPathBuf, &DirstateEntry),
477 ) -> PyResult<Option<(PyBytes, PyObject)>> {
483 ) -> PyResult<Option<(PyBytes, PyObject)>> {
478 let (f, entry) = res;
484 let (f, entry) = res;
479 Ok(Some((
485 Ok(Some((
480 PyBytes::new(py, f.as_ref()),
486 PyBytes::new(py, f.as_ref()),
481 make_dirstate_tuple(py, entry)?,
487 make_dirstate_tuple(py, entry)?,
482 )))
488 )))
483 }
489 }
484 }
490 }
485
491
486 py_shared_ref!(DirstateMap, RustDirstateMap, inner, inner_shared);
492 py_shared_ref!(DirstateMap, RustDirstateMap, inner, inner_shared);
487
493
488 py_shared_iterator!(
494 py_shared_iterator!(
489 DirstateMapKeysIterator,
495 DirstateMapKeysIterator,
490 PyLeakedRef,
496 PyLeakedRef,
491 StateMapIter<'static>,
497 StateMapIter<'static>,
492 DirstateMap::translate_key,
498 DirstateMap::translate_key,
493 Option<PyBytes>
499 Option<PyBytes>
494 );
500 );
495
501
496 py_shared_iterator!(
502 py_shared_iterator!(
497 DirstateMapItemsIterator,
503 DirstateMapItemsIterator,
498 PyLeakedRef,
504 PyLeakedRef,
499 StateMapIter<'static>,
505 StateMapIter<'static>,
500 DirstateMap::translate_key_value,
506 DirstateMap::translate_key_value,
501 Option<(PyBytes, PyObject)>
507 Option<(PyBytes, PyObject)>
502 );
508 );
503
509
504 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<[u8; PARENT_SIZE]> {
510 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<[u8; PARENT_SIZE]> {
505 let bytes = obj.extract::<PyBytes>(py)?;
511 let bytes = obj.extract::<PyBytes>(py)?;
506 match bytes.data(py).try_into() {
512 match bytes.data(py).try_into() {
507 Ok(s) => Ok(s),
513 Ok(s) => Ok(s),
508 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
514 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
509 }
515 }
510 }
516 }
General Comments 0
You need to be logged in to leave comments. Login now