##// 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 1 # This file is automatically @generated by Cargo.
2 2 # It is not intended for manual editing.
3
4 3 [[package]]
5 4 name = "adler"
6 5 version = "0.2.3"
@@ -375,6 +374,7 b' dependencies = ['
375 374 name = "hg-core"
376 375 version = "0.1.0"
377 376 dependencies = [
377 "bitflags",
378 378 "byteorder",
379 379 "bytes-cast",
380 380 "clap",
@@ -9,6 +9,7 b' edition = "2018"'
9 9 name = "hg"
10 10
11 11 [dependencies]
12 bitflags = "1.2"
12 13 bytes-cast = "0.2"
13 14 byteorder = "1.3.4"
14 15 derive_more = "0.99"
@@ -452,7 +452,8 b' mod tests {'
452 452 .collect();
453 453
454 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 458 .iter()
458 459 .map(|x| HgPathBuf::from_bytes(x.as_ref()))
@@ -1,4 +1,5 b''
1 1 use crate::errors::HgError;
2 use bitflags::bitflags;
2 3 use std::convert::TryFrom;
3 4
4 5 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -14,12 +15,25 b' pub enum EntryState {'
14 15 /// comes first.
15 16 #[derive(Debug, PartialEq, Copy, Clone)]
16 17 pub struct DirstateEntry {
17 state: EntryState,
18 flags: Flags,
18 19 mode: i32,
19 20 size: i32,
20 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 37 pub const V1_RANGEMASK: i32 = 0x7FFFFFFF;
24 38
25 39 pub const MTIME_UNSET: i32 = -1;
@@ -39,11 +53,89 b' impl DirstateEntry {'
39 53 size: i32,
40 54 mtime: i32,
41 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 {
63 Self {
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,
74 mode,
75 size,
76 mtime,
77 }
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 {
42 101 Self {
43 state,
44 mode,
45 size,
46 mtime,
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,
47 139 }
48 140 }
49 141
@@ -52,28 +144,57 b' impl DirstateEntry {'
52 144 /// `size` is expected to be zero, `SIZE_NON_NORMAL`, or
53 145 /// `SIZE_FROM_OTHER_PARENT`
54 146 pub fn new_removed(size: i32) -> Self {
55 Self {
56 state: EntryState::Removed,
57 mode: 0,
58 size,
59 mtime: 0,
60 }
147 Self::from_v1_data(EntryState::Removed, 0, size, 0)
61 148 }
62 149
63 150 /// TODO: refactor `DirstateMap::add_file` to not take a `DirstateEntry`
64 151 /// parameter and remove this constructor
65 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
68 state: EntryState::Normal,
69 mode,
70 size,
71 mtime,
72 }
153 // XXX Arbitrary default value since the value is determined later
154 let state = EntryState::Normal;
155 Self::from_v1_data(state, mode, size, mtime)
156 }
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)
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 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 200 pub fn mode(&self) -> i32 {
@@ -81,11 +202,39 b' impl DirstateEntry {'
81 202 }
82 203
83 204 pub fn size(&self) -> i32 {
84 self.size
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 {
220 self.size
221 }
85 222 }
86 223
87 224 pub fn mtime(&self) -> i32 {
88 self.mtime
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 {
236 self.mtime
237 }
89 238 }
90 239
91 240 /// Returns `(state, mode, size, mtime)` for the puprose of serialization
@@ -95,15 +244,16 b' impl DirstateEntry {'
95 244 /// want to not represent these cases that way in memory, but serialization
96 245 /// will need to keep the same format.
97 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 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 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 259 // TODO: other platforms
@@ -114,7 +264,7 b' impl DirstateEntry {'
114 264 ) -> bool {
115 265 use std::os::unix::fs::MetadataExt;
116 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 268 let fs_exec_bit = filesystem_metadata.mode() & EXEC_BIT_MASK;
119 269 dirstate_exec_bit != fs_exec_bit
120 270 }
@@ -122,11 +272,16 b' impl DirstateEntry {'
122 272 /// Returns a `(state, mode, size, mtime)` tuple as for
123 273 /// `DirstateMapMethods::debug_iter`.
124 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 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 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