##// END OF EJS Templates
rust: Add Python bindings for DirstateEntry as rustext.dirstate.DirstateItem...
Simon Sapin -
r48857:3e69bef2 default
parent child Browse files
Show More
@@ -0,0 +1,189 b''
1 use cpython::exc;
2 use cpython::PyBytes;
3 use cpython::PyErr;
4 use cpython::PyNone;
5 use cpython::PyObject;
6 use cpython::PyResult;
7 use cpython::Python;
8 use cpython::PythonObject;
9 use hg::dirstate::entry::Flags;
10 use hg::dirstate::DirstateEntry;
11 use hg::dirstate::EntryState;
12 use std::cell::Cell;
13 use std::convert::TryFrom;
14
15 py_class!(pub class DirstateItem |py| {
16 data entry: Cell<DirstateEntry>;
17
18 def __new__(
19 _cls,
20 wc_tracked: bool = false,
21 p1_tracked: bool = false,
22 p2_tracked: bool = false,
23 merged: bool = false,
24 clean_p1: bool = false,
25 clean_p2: bool = false,
26 possibly_dirty: bool = false,
27 parentfiledata: Option<(i32, i32, i32)> = None,
28
29 ) -> PyResult<DirstateItem> {
30 let mut flags = Flags::empty();
31 flags.set(Flags::WDIR_TRACKED, wc_tracked);
32 flags.set(Flags::P1_TRACKED, p1_tracked);
33 flags.set(Flags::P2_TRACKED, p2_tracked);
34 flags.set(Flags::MERGED, merged);
35 flags.set(Flags::CLEAN_P1, clean_p1);
36 flags.set(Flags::CLEAN_P2, clean_p2);
37 flags.set(Flags::POSSIBLY_DIRTY, possibly_dirty);
38 let entry = DirstateEntry::new(flags, parentfiledata);
39 DirstateItem::create_instance(py, Cell::new(entry))
40 }
41
42 @property
43 def state(&self) -> PyResult<PyBytes> {
44 let state_byte: u8 = self.entry(py).get().state().into();
45 Ok(PyBytes::new(py, &[state_byte]))
46 }
47
48 @property
49 def mode(&self) -> PyResult<i32> {
50 Ok(self.entry(py).get().mode())
51 }
52
53 @property
54 def size(&self) -> PyResult<i32> {
55 Ok(self.entry(py).get().size())
56 }
57
58 @property
59 def mtime(&self) -> PyResult<i32> {
60 Ok(self.entry(py).get().mtime())
61 }
62
63 @property
64 def tracked(&self) -> PyResult<bool> {
65 Ok(self.entry(py).get().tracked())
66 }
67
68 @property
69 def added(&self) -> PyResult<bool> {
70 Ok(self.entry(py).get().added())
71 }
72
73 @property
74 def merged(&self) -> PyResult<bool> {
75 Ok(self.entry(py).get().merged())
76 }
77
78 @property
79 def removed(&self) -> PyResult<bool> {
80 Ok(self.entry(py).get().removed())
81 }
82
83 @property
84 def from_p2(&self) -> PyResult<bool> {
85 Ok(self.entry(py).get().from_p2())
86 }
87
88 @property
89 def merged_removed(&self) -> PyResult<bool> {
90 Ok(self.entry(py).get().merged_removed())
91 }
92
93 @property
94 def from_p2_removed(&self) -> PyResult<bool> {
95 Ok(self.entry(py).get().from_p2_removed())
96 }
97
98 @property
99 def dm_nonnormal(&self) -> PyResult<bool> {
100 Ok(self.entry(py).get().is_non_normal())
101 }
102
103 @property
104 def dm_otherparent(&self) -> PyResult<bool> {
105 Ok(self.entry(py).get().is_from_other_parent())
106 }
107
108 def v1_state(&self) -> PyResult<PyBytes> {
109 let (state, _mode, _size, _mtime) = self.entry(py).get().v1_data();
110 let state_byte: u8 = state.into();
111 Ok(PyBytes::new(py, &[state_byte]))
112 }
113
114 def v1_mode(&self) -> PyResult<i32> {
115 let (_state, mode, _size, _mtime) = self.entry(py).get().v1_data();
116 Ok(mode)
117 }
118
119 def v1_size(&self) -> PyResult<i32> {
120 let (_state, _mode, size, _mtime) = self.entry(py).get().v1_data();
121 Ok(size)
122 }
123
124 def v1_mtime(&self) -> PyResult<i32> {
125 let (_state, _mode, _size, mtime) = self.entry(py).get().v1_data();
126 Ok(mtime)
127 }
128
129 def need_delay(&self, now: i32) -> PyResult<bool> {
130 Ok(self.entry(py).get().mtime_is_ambiguous(now))
131 }
132
133 @classmethod
134 def from_v1_data(
135 _cls,
136 state: PyBytes,
137 mode: i32,
138 size: i32,
139 mtime: i32,
140 ) -> PyResult<Self> {
141 let state = <[u8; 1]>::try_from(state.data(py))
142 .ok()
143 .and_then(|state| EntryState::try_from(state[0]).ok())
144 .ok_or_else(|| PyErr::new::<exc::ValueError, _>(py, "invalid state"))?;
145 let entry = DirstateEntry::from_v1_data(state, mode, size, mtime);
146 DirstateItem::create_instance(py, Cell::new(entry))
147 }
148
149 def set_clean(
150 &self,
151 mode: i32,
152 size: i32,
153 mtime: i32,
154 ) -> PyResult<PyNone> {
155 self.update(py, |entry| entry.set_clean(mode, size, mtime));
156 Ok(PyNone)
157 }
158
159 def set_possibly_dirty(&self) -> PyResult<PyNone> {
160 self.update(py, |entry| entry.set_possibly_dirty());
161 Ok(PyNone)
162 }
163
164 def set_tracked(&self) -> PyResult<PyNone> {
165 self.update(py, |entry| entry.set_tracked());
166 Ok(PyNone)
167 }
168
169 def set_untracked(&self) -> PyResult<PyNone> {
170 self.update(py, |entry| entry.set_untracked());
171 Ok(PyNone)
172 }
173 });
174
175 impl DirstateItem {
176 pub fn new_as_pyobject(
177 py: Python<'_>,
178 entry: DirstateEntry,
179 ) -> PyResult<PyObject> {
180 Ok(DirstateItem::create_instance(py, Cell::new(entry))?.into_object())
181 }
182
183 // TODO: Use https://doc.rust-lang.org/std/cell/struct.Cell.html#method.update instead when it’s stable
184 pub fn update(&self, py: Python<'_>, f: impl FnOnce(&mut DirstateEntry)) {
185 let mut entry = self.entry(py).get();
186 f(&mut entry);
187 self.entry(py).set(entry)
188 }
189 }
@@ -22,7 +22,7 b' pub struct DirstateEntry {'
22 }
22 }
23
23
24 bitflags! {
24 bitflags! {
25 struct Flags: u8 {
25 pub struct Flags: u8 {
26 const WDIR_TRACKED = 1 << 0;
26 const WDIR_TRACKED = 1 << 0;
27 const P1_TRACKED = 1 << 1;
27 const P1_TRACKED = 1 << 1;
28 const P2_TRACKED = 1 << 2;
28 const P2_TRACKED = 1 << 2;
@@ -47,6 +47,20 b' pub const SIZE_FROM_OTHER_PARENT: i32 = '
47 pub const SIZE_NON_NORMAL: i32 = -1;
47 pub const SIZE_NON_NORMAL: i32 = -1;
48
48
49 impl DirstateEntry {
49 impl DirstateEntry {
50 pub fn new(
51 flags: Flags,
52 mode_size_mtime: Option<(i32, i32, i32)>,
53 ) -> Self {
54 let (mode, size, mtime) =
55 mode_size_mtime.unwrap_or((0, SIZE_NON_NORMAL, MTIME_UNSET));
56 Self {
57 flags,
58 mode,
59 size,
60 mtime,
61 }
62 }
63
50 pub fn from_v1_data(
64 pub fn from_v1_data(
51 state: EntryState,
65 state: EntryState,
52 mode: i32,
66 mode: i32,
@@ -155,33 +169,37 b' impl DirstateEntry {'
155 Self::from_v1_data(state, mode, size, mtime)
169 Self::from_v1_data(state, mode, size, mtime)
156 }
170 }
157
171
172 pub fn tracked(&self) -> bool {
173 self.flags.contains(Flags::WDIR_TRACKED)
174 }
175
158 fn tracked_in_any_parent(&self) -> bool {
176 fn tracked_in_any_parent(&self) -> bool {
159 self.flags.intersects(Flags::P1_TRACKED | Flags::P2_TRACKED)
177 self.flags.intersects(Flags::P1_TRACKED | Flags::P2_TRACKED)
160 }
178 }
161
179
162 fn removed(&self) -> bool {
180 pub fn removed(&self) -> bool {
163 self.tracked_in_any_parent()
181 self.tracked_in_any_parent()
164 && !self.flags.contains(Flags::WDIR_TRACKED)
182 && !self.flags.contains(Flags::WDIR_TRACKED)
165 }
183 }
166
184
167 fn merged_removed(&self) -> bool {
185 pub fn merged_removed(&self) -> bool {
168 self.removed() && self.flags.contains(Flags::MERGED)
186 self.removed() && self.flags.contains(Flags::MERGED)
169 }
187 }
170
188
171 fn from_p2_removed(&self) -> bool {
189 pub fn from_p2_removed(&self) -> bool {
172 self.removed() && self.flags.contains(Flags::CLEAN_P2)
190 self.removed() && self.flags.contains(Flags::CLEAN_P2)
173 }
191 }
174
192
175 fn merged(&self) -> bool {
193 pub fn merged(&self) -> bool {
176 self.flags.contains(Flags::WDIR_TRACKED | Flags::MERGED)
194 self.flags.contains(Flags::WDIR_TRACKED | Flags::MERGED)
177 }
195 }
178
196
179 fn added(&self) -> bool {
197 pub fn added(&self) -> bool {
180 self.flags.contains(Flags::WDIR_TRACKED)
198 self.flags.contains(Flags::WDIR_TRACKED)
181 && !self.tracked_in_any_parent()
199 && !self.tracked_in_any_parent()
182 }
200 }
183
201
184 fn from_p2(&self) -> bool {
202 pub fn from_p2(&self) -> bool {
185 self.flags.contains(Flags::WDIR_TRACKED | Flags::CLEAN_P2)
203 self.flags.contains(Flags::WDIR_TRACKED | Flags::CLEAN_P2)
186 }
204 }
187
205
@@ -237,6 +255,39 b' impl DirstateEntry {'
237 }
255 }
238 }
256 }
239
257
258 pub fn set_possibly_dirty(&mut self) {
259 self.flags.insert(Flags::POSSIBLY_DIRTY)
260 }
261
262 pub fn set_clean(&mut self, mode: i32, size: i32, mtime: i32) {
263 self.flags.insert(Flags::WDIR_TRACKED | Flags::P1_TRACKED);
264 self.flags.remove(
265 Flags::P2_TRACKED // This might be wrong
266 | Flags::MERGED
267 | Flags::CLEAN_P2
268 | Flags::POSSIBLY_DIRTY,
269 );
270 self.mode = mode;
271 self.size = size;
272 self.mtime = mtime;
273 }
274
275 pub fn set_tracked(&mut self) {
276 self.flags
277 .insert(Flags::WDIR_TRACKED | Flags::POSSIBLY_DIRTY);
278 // size = None on the python size turn into size = NON_NORMAL when
279 // accessed. So the next line is currently required, but a some future
280 // clean up would be welcome.
281 self.size = SIZE_NON_NORMAL;
282 }
283
284 pub fn set_untracked(&mut self) {
285 self.flags.remove(Flags::WDIR_TRACKED);
286 self.mode = 0;
287 self.size = 0;
288 self.mtime = 0;
289 }
290
240 /// Returns `(state, mode, size, mtime)` for the puprose of serialization
291 /// Returns `(state, mode, size, mtime)` for the puprose of serialization
241 /// in the dirstate-v1 format.
292 /// in the dirstate-v1 format.
242 ///
293 ///
@@ -12,8 +12,10 b''
12 mod copymap;
12 mod copymap;
13 mod dirs_multiset;
13 mod dirs_multiset;
14 mod dirstate_map;
14 mod dirstate_map;
15 mod item;
15 mod non_normal_entries;
16 mod non_normal_entries;
16 mod status;
17 mod status;
18 use self::item::DirstateItem;
17 use crate::{
19 use crate::{
18 dirstate::{
20 dirstate::{
19 dirs_multiset::Dirs, dirstate_map::DirstateMap, status::status_wrapper,
21 dirs_multiset::Dirs, dirstate_map::DirstateMap, status::status_wrapper,
@@ -83,6 +85,7 b' pub fn init_module(py: Python, package: '
83 )?;
85 )?;
84 m.add_class::<Dirs>(py)?;
86 m.add_class::<Dirs>(py)?;
85 m.add_class::<DirstateMap>(py)?;
87 m.add_class::<DirstateMap>(py)?;
88 m.add_class::<DirstateItem>(py)?;
86 m.add(py, "V2_FORMAT_MARKER", PyBytes::new(py, V2_FORMAT_MARKER))?;
89 m.add(py, "V2_FORMAT_MARKER", PyBytes::new(py, V2_FORMAT_MARKER))?;
87 m.add(
90 m.add(
88 py,
91 py,
General Comments 0
You need to be logged in to leave comments. Login now