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