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 use crate::dirstate::parsers::Timestamp; |
8 use crate::dirstate::parsers::Timestamp; |
|
9 use crate::errors::HgError; |
9 use crate::{ |
10 use crate::{ |
10 dirstate::EntryState, |
11 dirstate::EntryState, |
11 dirstate::SIZE_FROM_OTHER_PARENT, |
12 dirstate::SIZE_FROM_OTHER_PARENT, |
12 dirstate::SIZE_NON_NORMAL, |
13 dirstate::SIZE_NON_NORMAL, |
13 pack_dirstate, parse_dirstate, |
14 pack_dirstate, parse_dirstate, |
14 utils::hg_path::{HgPath, HgPathBuf}, |
15 utils::hg_path::{HgPath, HgPathBuf}, |
15 CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateParents, |
16 CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateParents, |
16 StateMap, |
17 StateMap, |
17 }; |
18 }; |
18 use micro_timer::timed; |
19 use micro_timer::timed; |
19 use std::collections::HashSet; |
|
20 use std::iter::FromIterator; |
20 use std::iter::FromIterator; |
21 use std::ops::Deref; |
21 use std::ops::Deref; |
22 |
22 |
23 #[derive(Default)] |
23 #[derive(Default)] |
24 pub struct DirstateMap { |
24 pub struct DirstateMap { |
25 state_map: StateMap, |
25 state_map: StateMap, |
26 pub copy_map: CopyMap, |
26 pub copy_map: CopyMap, |
27 pub dirs: Option<DirsMultiset>, |
27 pub dirs: Option<DirsMultiset>, |
28 pub all_dirs: Option<DirsMultiset>, |
28 pub all_dirs: Option<DirsMultiset>, |
29 non_normal_set: Option<HashSet<HgPathBuf>>, |
|
30 other_parent_set: Option<HashSet<HgPathBuf>>, |
|
31 } |
29 } |
32 |
30 |
33 /// Should only really be used in python interface code, for clarity |
31 /// Should only really be used in python interface code, for clarity |
34 impl Deref for DirstateMap { |
32 impl Deref for DirstateMap { |
35 type Target = StateMap; |
33 type Target = StateMap; |
56 } |
54 } |
57 |
55 |
58 pub fn clear(&mut self) { |
56 pub fn clear(&mut self) { |
59 self.state_map = StateMap::default(); |
57 self.state_map = StateMap::default(); |
60 self.copy_map.clear(); |
58 self.copy_map.clear(); |
61 self.non_normal_set = None; |
|
62 self.other_parent_set = None; |
|
63 } |
59 } |
64 |
60 |
65 pub fn set_entry(&mut self, filename: &HgPath, entry: DirstateEntry) { |
61 pub fn set_entry(&mut self, filename: &HgPath, entry: DirstateEntry) { |
66 self.state_map.insert(filename.to_owned(), entry); |
62 self.state_map.insert(filename.to_owned(), entry); |
67 } |
63 } |
82 if let Some(ref mut all_dirs) = self.all_dirs { |
78 if let Some(ref mut all_dirs) = self.all_dirs { |
83 all_dirs.add_path(filename)?; |
79 all_dirs.add_path(filename)?; |
84 } |
80 } |
85 } |
81 } |
86 self.state_map.insert(filename.to_owned(), entry.to_owned()); |
82 self.state_map.insert(filename.to_owned(), entry.to_owned()); |
87 |
|
88 if entry.is_non_normal() { |
|
89 self.get_non_normal_other_parent_entries() |
|
90 .0 |
|
91 .insert(filename.to_owned()); |
|
92 } |
|
93 |
|
94 if entry.is_from_other_parent() { |
|
95 self.get_non_normal_other_parent_entries() |
|
96 .1 |
|
97 .insert(filename.to_owned()); |
|
98 } |
|
99 Ok(()) |
83 Ok(()) |
100 } |
84 } |
101 |
85 |
102 /// Mark a file as removed in the dirstate. |
86 /// Mark a file as removed in the dirstate. |
103 /// |
87 /// |
171 } |
149 } |
172 if let Some(ref mut all_dirs) = self.all_dirs { |
150 if let Some(ref mut all_dirs) = self.all_dirs { |
173 all_dirs.delete_path(filename)?; |
151 all_dirs.delete_path(filename)?; |
174 } |
152 } |
175 } |
153 } |
176 self.get_non_normal_other_parent_entries() |
|
177 .0 |
|
178 .remove(filename); |
|
179 |
|
180 self.copy_map.remove(filename); |
154 self.copy_map.remove(filename); |
181 |
155 |
182 Ok(()) |
156 Ok(()) |
183 } |
|
184 |
|
185 pub fn non_normal_entries_remove( |
|
186 &mut self, |
|
187 key: impl AsRef<HgPath>, |
|
188 ) -> bool { |
|
189 self.get_non_normal_other_parent_entries() |
|
190 .0 |
|
191 .remove(key.as_ref()) |
|
192 } |
|
193 |
|
194 pub fn non_normal_entries_add(&mut self, key: impl AsRef<HgPath>) { |
|
195 self.get_non_normal_other_parent_entries() |
|
196 .0 |
|
197 .insert(key.as_ref().into()); |
|
198 } |
|
199 |
|
200 pub fn non_normal_entries_union( |
|
201 &mut self, |
|
202 other: HashSet<HgPathBuf>, |
|
203 ) -> Vec<HgPathBuf> { |
|
204 self.get_non_normal_other_parent_entries() |
|
205 .0 |
|
206 .union(&other) |
|
207 .map(ToOwned::to_owned) |
|
208 .collect() |
|
209 } |
|
210 |
|
211 pub fn get_non_normal_other_parent_entries( |
|
212 &mut self, |
|
213 ) -> (&mut HashSet<HgPathBuf>, &mut HashSet<HgPathBuf>) { |
|
214 self.set_non_normal_other_parent_entries(false); |
|
215 ( |
|
216 self.non_normal_set.as_mut().unwrap(), |
|
217 self.other_parent_set.as_mut().unwrap(), |
|
218 ) |
|
219 } |
|
220 |
|
221 /// Useful to get immutable references to those sets in contexts where |
|
222 /// you only have an immutable reference to the `DirstateMap`, like when |
|
223 /// sharing references with Python. |
|
224 /// |
|
225 /// TODO, get rid of this along with the other "setter/getter" stuff when |
|
226 /// a nice typestate plan is defined. |
|
227 /// |
|
228 /// # Panics |
|
229 /// |
|
230 /// Will panic if either set is `None`. |
|
231 pub fn get_non_normal_other_parent_entries_panic( |
|
232 &self, |
|
233 ) -> (&HashSet<HgPathBuf>, &HashSet<HgPathBuf>) { |
|
234 ( |
|
235 self.non_normal_set.as_ref().unwrap(), |
|
236 self.other_parent_set.as_ref().unwrap(), |
|
237 ) |
|
238 } |
|
239 |
|
240 pub fn set_non_normal_other_parent_entries(&mut self, force: bool) { |
|
241 if !force |
|
242 && self.non_normal_set.is_some() |
|
243 && self.other_parent_set.is_some() |
|
244 { |
|
245 return; |
|
246 } |
|
247 let mut non_normal = HashSet::new(); |
|
248 let mut other_parent = HashSet::new(); |
|
249 |
|
250 for (filename, entry) in self.state_map.iter() { |
|
251 if entry.is_non_normal() { |
|
252 non_normal.insert(filename.to_owned()); |
|
253 } |
|
254 if entry.is_from_other_parent() { |
|
255 other_parent.insert(filename.to_owned()); |
|
256 } |
|
257 } |
|
258 self.non_normal_set = Some(non_normal); |
|
259 self.other_parent_set = Some(other_parent); |
|
260 } |
157 } |
261 |
158 |
262 /// Both of these setters and their uses appear to be the simplest way to |
159 /// Both of these setters and their uses appear to be the simplest way to |
263 /// emulate a Python lazy property, but it is ugly and unidiomatic. |
160 /// emulate a Python lazy property, but it is ugly and unidiomatic. |
264 /// TODO One day, rewriting this struct using the typestate might be a |
161 /// TODO One day, rewriting this struct using the typestate might be a |
364 DirstateEntry::from_v1_data(EntryState::Normal, 1337, 1337, 1337), |
257 DirstateEntry::from_v1_data(EntryState::Normal, 1337, 1337, 1337), |
365 ) |
258 ) |
366 .unwrap(); |
259 .unwrap(); |
367 |
260 |
368 assert_eq!(1, map.len()); |
261 assert_eq!(1, map.len()); |
369 assert_eq!(0, map.get_non_normal_other_parent_entries().0.len()); |
262 } |
370 assert_eq!(0, map.get_non_normal_other_parent_entries().1.len()); |
263 } |
371 } |
|
372 |
|
373 #[test] |
|
374 fn test_non_normal_other_parent_entries() { |
|
375 let mut map: DirstateMap = [ |
|
376 (b"f1", (EntryState::Removed, 1337, 1337, 1337)), |
|
377 (b"f2", (EntryState::Normal, 1337, 1337, -1)), |
|
378 (b"f3", (EntryState::Normal, 1337, 1337, 1337)), |
|
379 (b"f4", (EntryState::Normal, 1337, -2, 1337)), |
|
380 (b"f5", (EntryState::Added, 1337, 1337, 1337)), |
|
381 (b"f6", (EntryState::Added, 1337, 1337, -1)), |
|
382 (b"f7", (EntryState::Merged, 1337, 1337, -1)), |
|
383 (b"f8", (EntryState::Merged, 1337, 1337, 1337)), |
|
384 (b"f9", (EntryState::Merged, 1337, -2, 1337)), |
|
385 (b"fa", (EntryState::Added, 1337, -2, 1337)), |
|
386 (b"fb", (EntryState::Removed, 1337, -2, 1337)), |
|
387 ] |
|
388 .iter() |
|
389 .map(|(fname, (state, mode, size, mtime))| { |
|
390 ( |
|
391 HgPathBuf::from_bytes(fname.as_ref()), |
|
392 DirstateEntry::from_v1_data(*state, *mode, *size, *mtime), |
|
393 ) |
|
394 }) |
|
395 .collect(); |
|
396 |
|
397 let mut non_normal = [ |
|
398 b"f1", b"f2", b"f4", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", |
|
399 b"fb", |
|
400 ] |
|
401 .iter() |
|
402 .map(|x| HgPathBuf::from_bytes(x.as_ref())) |
|
403 .collect(); |
|
404 |
|
405 let mut other_parent = HashSet::new(); |
|
406 other_parent.insert(HgPathBuf::from_bytes(b"f4")); |
|
407 let entries = map.get_non_normal_other_parent_entries(); |
|
408 |
|
409 assert_eq!( |
|
410 (&mut non_normal, &mut other_parent), |
|
411 (entries.0, entries.1) |
|
412 ); |
|
413 } |
|
414 } |
|