Show More
@@ -69,7 +69,7 b' pub enum BadMatch {' | |||
|
69 | 69 | BadType(BadType), |
|
70 | 70 | } |
|
71 | 71 | |
|
72 |
/// |
|
|
72 | /// Enum used to dispatch new status entries into the right collections. | |
|
73 | 73 | /// Is similar to `crate::EntryState`, but represents the transient state of |
|
74 | 74 | /// entries during the lifetime of a command. |
|
75 | 75 | #[derive(Debug, Copy, Clone)] |
@@ -94,10 +94,18 b' pub enum Dispatch {' | |||
|
94 | 94 | } |
|
95 | 95 | |
|
96 | 96 | type IoResult<T> = std::io::Result<T>; |
|
97 | ||
|
97 | 98 | /// `Box<dyn Trait>` is syntactic sugar for `Box<dyn Trait, 'static>`, so add |
|
98 | 99 | /// an explicit lifetime here to not fight `'static` bounds "out of nowhere". |
|
99 | 100 | type IgnoreFnType<'a> = Box<dyn for<'r> Fn(&'r HgPath) -> bool + Sync + 'a>; |
|
100 | 101 | |
|
102 | /// We have a good mix of owned (from directory traversal) and borrowed (from | |
|
103 | /// the dirstate/explicit) paths, this comes up a lot. | |
|
104 | type HgPathCow<'a> = Cow<'a, HgPath>; | |
|
105 | ||
|
106 | /// A path with its computed ``Dispatch`` information | |
|
107 | type DispatchedPath<'a> = (HgPathCow<'a>, Dispatch); | |
|
108 | ||
|
101 | 109 | /// Dates and times that are outside the 31-bit signed range are compared |
|
102 | 110 | /// modulo 2^31. This should prevent hg from behaving badly with very large |
|
103 | 111 | /// files or corrupt dates while still having a high probability of detecting |
@@ -232,22 +240,25 b' pub struct StatusOptions {' | |||
|
232 | 240 | |
|
233 | 241 | #[derive(Debug)] |
|
234 | 242 | pub struct DirstateStatus<'a> { |
|
235 |
pub modified: Vec<Cow<'a |
|
|
236 |
pub added: Vec<Cow<'a |
|
|
237 |
pub removed: Vec<Cow<'a |
|
|
238 |
pub deleted: Vec<Cow<'a |
|
|
239 |
pub clean: Vec<Cow<'a |
|
|
240 |
pub ignored: Vec<Cow<'a |
|
|
241 |
pub unknown: Vec<Cow<'a |
|
|
242 |
pub bad: Vec<(Cow<'a |
|
|
243 | pub modified: Vec<HgPathCow<'a>>, | |
|
244 | pub added: Vec<HgPathCow<'a>>, | |
|
245 | pub removed: Vec<HgPathCow<'a>>, | |
|
246 | pub deleted: Vec<HgPathCow<'a>>, | |
|
247 | pub clean: Vec<HgPathCow<'a>>, | |
|
248 | pub ignored: Vec<HgPathCow<'a>>, | |
|
249 | pub unknown: Vec<HgPathCow<'a>>, | |
|
250 | pub bad: Vec<(HgPathCow<'a>, BadMatch)>, | |
|
243 | 251 | /// Only filled if `collect_traversed_dirs` is `true` |
|
244 | 252 | pub traversed: Vec<HgPathBuf>, |
|
245 | 253 | } |
|
246 | 254 | |
|
247 | 255 | #[derive(Debug)] |
|
248 | 256 | pub enum StatusError { |
|
257 | /// Generic IO error | |
|
249 | 258 | IO(std::io::Error), |
|
259 | /// An invalid path that cannot be represented in Mercurial was found | |
|
250 | 260 | Path(HgPathError), |
|
261 | /// An invalid "ignore" pattern was found | |
|
251 | 262 | Pattern(PatternError), |
|
252 | 263 | } |
|
253 | 264 | |
@@ -279,6 +290,8 b' impl ToString for StatusError {' | |||
|
279 | 290 | } |
|
280 | 291 | } |
|
281 | 292 | |
|
293 | /// Gives information about which files are changed in the working directory | |
|
294 | /// and how, compared to the revision we're based on | |
|
282 | 295 | pub struct Status<'a, M: Matcher + Sync> { |
|
283 | 296 | dmap: &'a DirstateMap, |
|
284 | 297 | matcher: &'a M, |
@@ -319,6 +332,7 b' where' | |||
|
319 | 332 | )) |
|
320 | 333 | } |
|
321 | 334 | |
|
335 | /// Is the path ignored? | |
|
322 | 336 | pub fn is_ignored(&self, path: impl AsRef<HgPath>) -> bool { |
|
323 | 337 | (self.ignore_fn)(path.as_ref()) |
|
324 | 338 | } |
@@ -342,16 +356,15 b' where' | |||
|
342 | 356 | } |
|
343 | 357 | } |
|
344 | 358 | |
|
345 | /// Get stat data about the files explicitly specified by match. | |
|
359 | /// Get stat data about the files explicitly specified by the matcher. | |
|
360 | /// Returns a tuple of the directories that need to be traversed and the | |
|
361 | /// files with their corresponding `Dispatch`. | |
|
346 | 362 | /// TODO subrepos |
|
347 | 363 | #[timed] |
|
348 | 364 | pub fn walk_explicit( |
|
349 | 365 | &self, |
|
350 | 366 | traversed_sender: crossbeam::Sender<HgPathBuf>, |
|
351 | ) -> ( | |
|
352 | Vec<(Cow<'a, HgPath>, Dispatch)>, | |
|
353 | Vec<(Cow<'a, HgPath>, Dispatch)>, | |
|
354 | ) { | |
|
367 | ) -> (Vec<DispatchedPath<'a>>, Vec<DispatchedPath<'a>>) { | |
|
355 | 368 | self.matcher |
|
356 | 369 | .file_set() |
|
357 | 370 | .unwrap_or(&DEFAULT_WORK) |
@@ -443,8 +456,8 b' where' | |||
|
443 | 456 | pub fn traverse( |
|
444 | 457 | &self, |
|
445 | 458 | path: impl AsRef<HgPath>, |
|
446 |
old_results: &FastHashMap<Cow<'a |
|
|
447 |
results: &mut Vec< |
|
|
459 | old_results: &FastHashMap<HgPathCow<'a>, Dispatch>, | |
|
460 | results: &mut Vec<DispatchedPath<'a>>, | |
|
448 | 461 | traversed_sender: crossbeam::Sender<HgPathBuf>, |
|
449 | 462 | ) -> IoResult<()> { |
|
450 | 463 | // The traversal is done in parallel, so use a channel to gather |
@@ -637,23 +650,25 b' where' | |||
|
637 | 650 | |
|
638 | 651 | let skip_dot_hg = !directory.as_bytes().is_empty(); |
|
639 | 652 | let entries = match list_directory(dir_path, skip_dot_hg) { |
|
640 |
Err(e) => |
|
|
641 | ErrorKind::NotFound | ErrorKind::PermissionDenied => { | |
|
642 | files_sender | |
|
643 |
|
|
|
644 |
|
|
|
645 | Dispatch::Bad(BadMatch::OsError( | |
|
646 | // Unwrapping here is OK because the error | |
|
647 |
|
|
|
648 |
|
|
|
649 |
|
|
|
650 | )), | |
|
651 |
)) |
|
|
652 |
|
|
|
653 | return Ok(()); | |
|
654 |
|
|
|
655 |
|
|
|
656 | }, | |
|
653 | Err(e) => { | |
|
654 | return match e.kind() { | |
|
655 | ErrorKind::NotFound | ErrorKind::PermissionDenied => { | |
|
656 | files_sender | |
|
657 | .send(Ok(( | |
|
658 | directory.to_owned(), | |
|
659 | Dispatch::Bad(BadMatch::OsError( | |
|
660 | // Unwrapping here is OK because the error | |
|
661 | // always is a | |
|
662 | // real os error | |
|
663 | e.raw_os_error().unwrap(), | |
|
664 | )), | |
|
665 | ))) | |
|
666 | .expect("receiver should outlive sender"); | |
|
667 | Ok(()) | |
|
668 | } | |
|
669 | _ => Err(e), | |
|
670 | }; | |
|
671 | } | |
|
657 | 672 | Ok(entries) => entries, |
|
658 | 673 | }; |
|
659 | 674 | |
@@ -686,12 +701,16 b' where' | |||
|
686 | 701 | }) |
|
687 | 702 | } |
|
688 | 703 | |
|
704 | /// Checks all files that are in the dirstate but were not found during the | |
|
705 | /// working directory traversal. This means that the rest must | |
|
706 | /// be either ignored, under a symlink or under a new nested repo. | |
|
707 | /// | |
|
689 | 708 | /// This takes a mutable reference to the results to account for the |
|
690 | 709 | /// `extend` in timings |
|
691 | 710 | #[timed] |
|
692 | 711 | fn handle_unknowns( |
|
693 | 712 | &self, |
|
694 |
results: &mut Vec< |
|
|
713 | results: &mut Vec<DispatchedPath<'a>>, | |
|
695 | 714 | ) -> IoResult<()> { |
|
696 | 715 | let to_visit: Vec<(&HgPath, &DirstateEntry)> = |
|
697 | 716 | if results.is_empty() && self.matcher.matches_everything() { |
@@ -714,9 +733,6 b' where' | |||
|
714 | 733 | .collect() |
|
715 | 734 | }; |
|
716 | 735 | |
|
717 | // We walked all dirs under the roots that weren't ignored, and | |
|
718 | // everything that matched was stat'ed and is already in results. | |
|
719 | // The rest must thus be ignored or under a symlink. | |
|
720 | 736 | let path_auditor = PathAuditor::new(&self.root_dir); |
|
721 | 737 | |
|
722 | 738 | // TODO don't collect. Find a way of replicating the behavior of |
@@ -766,13 +782,12 b' where' | |||
|
766 | 782 | Ok(()) |
|
767 | 783 | } |
|
768 | 784 | |
|
785 | /// Add the files in the dirstate to the results. | |
|
786 | /// | |
|
769 | 787 | /// This takes a mutable reference to the results to account for the |
|
770 | 788 | /// `extend` in timings |
|
771 | 789 | #[timed] |
|
772 | fn extend_from_dmap( | |
|
773 | &self, | |
|
774 | results: &mut Vec<(Cow<'a, HgPath>, Dispatch)>, | |
|
775 | ) { | |
|
790 | fn extend_from_dmap(&self, results: &mut Vec<DispatchedPath<'a>>) { | |
|
776 | 791 | results.par_extend(self.dmap.par_iter().flat_map( |
|
777 | 792 | move |(filename, entry)| { |
|
778 | 793 | let filename: &HgPath = filename; |
@@ -823,9 +838,9 b' where' | |||
|
823 | 838 | |
|
824 | 839 | #[timed] |
|
825 | 840 | fn build_response<'a>( |
|
826 |
results: impl IntoIterator<Item = |
|
|
841 | results: impl IntoIterator<Item = DispatchedPath<'a>>, | |
|
827 | 842 | traversed: Vec<HgPathBuf>, |
|
828 |
) -> (Vec<Cow<'a |
|
|
843 | ) -> (Vec<HgPathCow<'a>>, DirstateStatus<'a>) { | |
|
829 | 844 | let mut lookup = vec![]; |
|
830 | 845 | let mut modified = vec![]; |
|
831 | 846 | let mut added = vec![]; |
@@ -881,7 +896,7 b" pub fn status<'a>(" | |||
|
881 | 896 | ignore_files: Vec<PathBuf>, |
|
882 | 897 | options: StatusOptions, |
|
883 | 898 | ) -> StatusResult<( |
|
884 |
(Vec<Cow<'a |
|
|
899 | (Vec<HgPathCow<'a>>, DirstateStatus<'a>), | |
|
885 | 900 | Vec<PatternFileWarning>, |
|
886 | 901 | )> { |
|
887 | 902 | let (traversed_sender, traversed_receiver) = |
@@ -922,16 +937,12 b" pub fn status<'a>(" | |||
|
922 | 937 | } |
|
923 | 938 | |
|
924 | 939 | if !matcher.is_exact() { |
|
925 | // Step 3: Check the remaining files from the dmap. | |
|
926 | // If a dmap file is not in results yet, it was either | |
|
927 | // a) not matched b) ignored, c) missing, or d) under a | |
|
928 | // symlink directory. | |
|
929 | ||
|
930 | 940 | if options.list_unknown { |
|
931 | 941 | st.handle_unknowns(&mut results)?; |
|
932 | 942 | } else { |
|
933 | // We may not have walked the full directory tree above, so stat | |
|
934 | // and check everything we missed. | |
|
943 | // TODO this is incorrect, see issue6335 | |
|
944 | // This requires a fix in both Python and Rust that can happen | |
|
945 | // with other pending changes to `status`. | |
|
935 | 946 | st.extend_from_dmap(&mut results); |
|
936 | 947 | } |
|
937 | 948 | } |
General Comments 0
You need to be logged in to leave comments.
Login now