##// END OF EJS Templates
rust: Align DirstateEntry internals with Python/C DirstateItem...
Simon Sapin -
r48856:008959fc default
parent child Browse files
Show More
@@ -1,6 +1,5 b''
1 # This file is automatically @generated by Cargo.
1 # This file is automatically @generated by Cargo.
2 # It is not intended for manual editing.
2 # It is not intended for manual editing.
3
4 [[package]]
3 [[package]]
5 name = "adler"
4 name = "adler"
6 version = "0.2.3"
5 version = "0.2.3"
@@ -375,6 +374,7 b' dependencies = ['
375 name = "hg-core"
374 name = "hg-core"
376 version = "0.1.0"
375 version = "0.1.0"
377 dependencies = [
376 dependencies = [
377 "bitflags",
378 "byteorder",
378 "byteorder",
379 "bytes-cast",
379 "bytes-cast",
380 "clap",
380 "clap",
@@ -9,6 +9,7 b' edition = "2018"'
9 name = "hg"
9 name = "hg"
10
10
11 [dependencies]
11 [dependencies]
12 bitflags = "1.2"
12 bytes-cast = "0.2"
13 bytes-cast = "0.2"
13 byteorder = "1.3.4"
14 byteorder = "1.3.4"
14 derive_more = "0.99"
15 derive_more = "0.99"
@@ -452,7 +452,8 b' mod tests {'
452 .collect();
452 .collect();
453
453
454 let mut non_normal = [
454 let mut non_normal = [
455 b"f1", b"f2", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", b"fb",
455 b"f1", b"f2", b"f4", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa",
456 b"fb",
456 ]
457 ]
457 .iter()
458 .iter()
458 .map(|x| HgPathBuf::from_bytes(x.as_ref()))
459 .map(|x| HgPathBuf::from_bytes(x.as_ref()))
@@ -1,4 +1,5 b''
1 use crate::errors::HgError;
1 use crate::errors::HgError;
2 use bitflags::bitflags;
2 use std::convert::TryFrom;
3 use std::convert::TryFrom;
3
4
4 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
5 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -14,12 +15,25 b' pub enum EntryState {'
14 /// comes first.
15 /// comes first.
15 #[derive(Debug, PartialEq, Copy, Clone)]
16 #[derive(Debug, PartialEq, Copy, Clone)]
16 pub struct DirstateEntry {
17 pub struct DirstateEntry {
17 state: EntryState,
18 flags: Flags,
18 mode: i32,
19 mode: i32,
19 size: i32,
20 size: i32,
20 mtime: i32,
21 mtime: i32,
21 }
22 }
22
23
24 bitflags! {
25 struct Flags: u8 {
26 const WDIR_TRACKED = 1 << 0;
27 const P1_TRACKED = 1 << 1;
28 const P2_TRACKED = 1 << 2;
29 const POSSIBLY_DIRTY = 1 << 3;
30 const MERGED = 1 << 4;
31 const CLEAN_P1 = 1 << 5;
32 const CLEAN_P2 = 1 << 6;
33 const ENTRYLESS_TREE_NODE = 1 << 7;
34 }
35 }
36
23 pub const V1_RANGEMASK: i32 = 0x7FFFFFFF;
37 pub const V1_RANGEMASK: i32 = 0x7FFFFFFF;
24
38
25 pub const MTIME_UNSET: i32 = -1;
39 pub const MTIME_UNSET: i32 = -1;
@@ -39,41 +53,148 b' impl DirstateEntry {'
39 size: i32,
53 size: i32,
40 mtime: i32,
54 mtime: i32,
41 ) -> Self {
55 ) -> Self {
56 match state {
57 EntryState::Normal => {
58 if size == SIZE_FROM_OTHER_PARENT {
59 Self::new_from_p2()
60 } else if size == SIZE_NON_NORMAL {
61 Self::new_possibly_dirty()
62 } else if mtime == MTIME_UNSET {
42 Self {
63 Self {
43 state,
64 flags: Flags::WDIR_TRACKED
65 | Flags::P1_TRACKED
66 | Flags::POSSIBLY_DIRTY,
67 mode,
68 size,
69 mtime: 0,
70 }
71 } else {
72 Self {
73 flags: Flags::WDIR_TRACKED | Flags::P1_TRACKED,
44 mode,
74 mode,
45 size,
75 size,
46 mtime,
76 mtime,
47 }
77 }
48 }
78 }
79 }
80 EntryState::Added => Self::new_added(),
81 EntryState::Removed => Self {
82 flags: if size == SIZE_NON_NORMAL {
83 Flags::P1_TRACKED // might not be true because of rename ?
84 | Flags::P2_TRACKED // might not be true because of rename ?
85 | Flags::MERGED
86 } else if size == SIZE_FROM_OTHER_PARENT {
87 // We don’t know if P1_TRACKED should be set (file history)
88 Flags::P2_TRACKED | Flags::CLEAN_P2
89 } else {
90 Flags::P1_TRACKED
91 },
92 mode: 0,
93 size: 0,
94 mtime: 0,
95 },
96 EntryState::Merged => Self::new_merged(),
97 }
98 }
99
100 fn new_from_p2() -> Self {
101 Self {
102 // might be missing P1_TRACKED
103 flags: Flags::WDIR_TRACKED | Flags::P2_TRACKED | Flags::CLEAN_P2,
104 mode: 0,
105 size: SIZE_FROM_OTHER_PARENT,
106 mtime: MTIME_UNSET,
107 }
108 }
109
110 fn new_possibly_dirty() -> Self {
111 Self {
112 flags: Flags::WDIR_TRACKED
113 | Flags::P1_TRACKED
114 | Flags::POSSIBLY_DIRTY,
115 mode: 0,
116 size: SIZE_NON_NORMAL,
117 mtime: MTIME_UNSET,
118 }
119 }
120
121 fn new_added() -> Self {
122 Self {
123 flags: Flags::WDIR_TRACKED,
124 mode: 0,
125 size: SIZE_NON_NORMAL,
126 mtime: MTIME_UNSET,
127 }
128 }
129
130 fn new_merged() -> Self {
131 Self {
132 flags: Flags::WDIR_TRACKED
133 | Flags::P1_TRACKED // might not be true because of rename ?
134 | Flags::P2_TRACKED // might not be true because of rename ?
135 | Flags::MERGED,
136 mode: 0,
137 size: SIZE_NON_NORMAL,
138 mtime: MTIME_UNSET,
139 }
140 }
49
141
50 /// Creates a new entry in "removed" state.
142 /// Creates a new entry in "removed" state.
51 ///
143 ///
52 /// `size` is expected to be zero, `SIZE_NON_NORMAL`, or
144 /// `size` is expected to be zero, `SIZE_NON_NORMAL`, or
53 /// `SIZE_FROM_OTHER_PARENT`
145 /// `SIZE_FROM_OTHER_PARENT`
54 pub fn new_removed(size: i32) -> Self {
146 pub fn new_removed(size: i32) -> Self {
55 Self {
147 Self::from_v1_data(EntryState::Removed, 0, size, 0)
56 state: EntryState::Removed,
57 mode: 0,
58 size,
59 mtime: 0,
60 }
61 }
148 }
62
149
63 /// TODO: refactor `DirstateMap::add_file` to not take a `DirstateEntry`
150 /// TODO: refactor `DirstateMap::add_file` to not take a `DirstateEntry`
64 /// parameter and remove this constructor
151 /// parameter and remove this constructor
65 pub fn new_for_add_file(mode: i32, size: i32, mtime: i32) -> Self {
152 pub fn new_for_add_file(mode: i32, size: i32, mtime: i32) -> Self {
66 Self {
67 // XXX Arbitrary default value since the value is determined later
153 // XXX Arbitrary default value since the value is determined later
68 state: EntryState::Normal,
154 let state = EntryState::Normal;
69 mode,
155 Self::from_v1_data(state, mode, size, mtime)
70 size,
156 }
71 mtime,
157
158 fn tracked_in_any_parent(&self) -> bool {
159 self.flags.intersects(Flags::P1_TRACKED | Flags::P2_TRACKED)
160 }
161
162 fn removed(&self) -> bool {
163 self.tracked_in_any_parent()
164 && !self.flags.contains(Flags::WDIR_TRACKED)
165 }
166
167 fn merged_removed(&self) -> bool {
168 self.removed() && self.flags.contains(Flags::MERGED)
72 }
169 }
170
171 fn from_p2_removed(&self) -> bool {
172 self.removed() && self.flags.contains(Flags::CLEAN_P2)
173 }
174
175 fn merged(&self) -> bool {
176 self.flags.contains(Flags::WDIR_TRACKED | Flags::MERGED)
177 }
178
179 fn added(&self) -> bool {
180 self.flags.contains(Flags::WDIR_TRACKED)
181 && !self.tracked_in_any_parent()
182 }
183
184 fn from_p2(&self) -> bool {
185 self.flags.contains(Flags::WDIR_TRACKED | Flags::CLEAN_P2)
73 }
186 }
74
187
75 pub fn state(&self) -> EntryState {
188 pub fn state(&self) -> EntryState {
76 self.state
189 if self.removed() {
190 EntryState::Removed
191 } else if self.merged() {
192 EntryState::Merged
193 } else if self.added() {
194 EntryState::Added
195 } else {
196 EntryState::Normal
197 }
77 }
198 }
78
199
79 pub fn mode(&self) -> i32 {
200 pub fn mode(&self) -> i32 {
@@ -81,12 +202,40 b' impl DirstateEntry {'
81 }
202 }
82
203
83 pub fn size(&self) -> i32 {
204 pub fn size(&self) -> i32 {
205 if self.merged_removed() {
206 SIZE_NON_NORMAL
207 } else if self.from_p2_removed() {
208 SIZE_FROM_OTHER_PARENT
209 } else if self.removed() {
210 0
211 } else if self.merged() {
212 SIZE_FROM_OTHER_PARENT
213 } else if self.added() {
214 SIZE_NON_NORMAL
215 } else if self.from_p2() {
216 SIZE_FROM_OTHER_PARENT
217 } else if self.flags.contains(Flags::POSSIBLY_DIRTY) {
218 self.size // TODO: SIZE_NON_NORMAL ?
219 } else {
84 self.size
220 self.size
85 }
221 }
222 }
86
223
87 pub fn mtime(&self) -> i32 {
224 pub fn mtime(&self) -> i32 {
225 if self.removed() {
226 0
227 } else if self.flags.contains(Flags::POSSIBLY_DIRTY) {
228 MTIME_UNSET
229 } else if self.merged() {
230 MTIME_UNSET
231 } else if self.added() {
232 MTIME_UNSET
233 } else if self.from_p2() {
234 MTIME_UNSET
235 } else {
88 self.mtime
236 self.mtime
89 }
237 }
238 }
90
239
91 /// Returns `(state, mode, size, mtime)` for the puprose of serialization
240 /// Returns `(state, mode, size, mtime)` for the puprose of serialization
92 /// in the dirstate-v1 format.
241 /// in the dirstate-v1 format.
@@ -95,15 +244,16 b' impl DirstateEntry {'
95 /// want to not represent these cases that way in memory, but serialization
244 /// want to not represent these cases that way in memory, but serialization
96 /// will need to keep the same format.
245 /// will need to keep the same format.
97 pub fn v1_data(&self) -> (u8, i32, i32, i32) {
246 pub fn v1_data(&self) -> (u8, i32, i32, i32) {
98 (self.state.into(), self.mode, self.size, self.mtime)
247 (self.state().into(), self.mode(), self.size(), self.mtime())
99 }
248 }
100
249
101 pub fn is_non_normal(&self) -> bool {
250 pub fn is_non_normal(&self) -> bool {
102 self.state != EntryState::Normal || self.mtime == MTIME_UNSET
251 self.state() != EntryState::Normal || self.mtime() == MTIME_UNSET
103 }
252 }
104
253
105 pub fn is_from_other_parent(&self) -> bool {
254 pub fn is_from_other_parent(&self) -> bool {
106 self.state == EntryState::Normal && self.size == SIZE_FROM_OTHER_PARENT
255 self.state() == EntryState::Normal
256 && self.size() == SIZE_FROM_OTHER_PARENT
107 }
257 }
108
258
109 // TODO: other platforms
259 // TODO: other platforms
@@ -114,7 +264,7 b' impl DirstateEntry {'
114 ) -> bool {
264 ) -> bool {
115 use std::os::unix::fs::MetadataExt;
265 use std::os::unix::fs::MetadataExt;
116 const EXEC_BIT_MASK: u32 = 0o100;
266 const EXEC_BIT_MASK: u32 = 0o100;
117 let dirstate_exec_bit = (self.mode as u32) & EXEC_BIT_MASK;
267 let dirstate_exec_bit = (self.mode() as u32) & EXEC_BIT_MASK;
118 let fs_exec_bit = filesystem_metadata.mode() & EXEC_BIT_MASK;
268 let fs_exec_bit = filesystem_metadata.mode() & EXEC_BIT_MASK;
119 dirstate_exec_bit != fs_exec_bit
269 dirstate_exec_bit != fs_exec_bit
120 }
270 }
@@ -122,11 +272,16 b' impl DirstateEntry {'
122 /// Returns a `(state, mode, size, mtime)` tuple as for
272 /// Returns a `(state, mode, size, mtime)` tuple as for
123 /// `DirstateMapMethods::debug_iter`.
273 /// `DirstateMapMethods::debug_iter`.
124 pub fn debug_tuple(&self) -> (u8, i32, i32, i32) {
274 pub fn debug_tuple(&self) -> (u8, i32, i32, i32) {
125 (self.state.into(), self.mode, self.size, self.mtime)
275 let state = if self.flags.contains(Flags::ENTRYLESS_TREE_NODE) {
276 b' '
277 } else {
278 self.state().into()
279 };
280 (state, self.mode(), self.size(), self.mtime())
126 }
281 }
127
282
128 pub fn mtime_is_ambiguous(&self, now: i32) -> bool {
283 pub fn mtime_is_ambiguous(&self, now: i32) -> bool {
129 self.state == EntryState::Normal && self.mtime == now
284 self.state() == EntryState::Normal && self.mtime() == now
130 }
285 }
131
286
132 pub fn clear_ambiguous_mtime(&mut self, now: i32) -> bool {
287 pub fn clear_ambiguous_mtime(&mut self, now: i32) -> bool {
General Comments 0
You need to be logged in to leave comments. Login now