##// END OF EJS Templates
rust-status: improve documentation and readability...
Raphaël Gomès -
r45672:470d306e default
parent child Browse files
Show More
@@ -69,7 +69,7 b' pub enum BadMatch {'
69 BadType(BadType),
69 BadType(BadType),
70 }
70 }
71
71
72 /// Marker enum used to dispatch new status entries into the right collections.
72 /// Enum used to dispatch new status entries into the right collections.
73 /// Is similar to `crate::EntryState`, but represents the transient state of
73 /// Is similar to `crate::EntryState`, but represents the transient state of
74 /// entries during the lifetime of a command.
74 /// entries during the lifetime of a command.
75 #[derive(Debug, Copy, Clone)]
75 #[derive(Debug, Copy, Clone)]
@@ -94,10 +94,18 b' pub enum Dispatch {'
94 }
94 }
95
95
96 type IoResult<T> = std::io::Result<T>;
96 type IoResult<T> = std::io::Result<T>;
97
97 /// `Box<dyn Trait>` is syntactic sugar for `Box<dyn Trait, 'static>`, so add
98 /// `Box<dyn Trait>` is syntactic sugar for `Box<dyn Trait, 'static>`, so add
98 /// an explicit lifetime here to not fight `'static` bounds "out of nowhere".
99 /// an explicit lifetime here to not fight `'static` bounds "out of nowhere".
99 type IgnoreFnType<'a> = Box<dyn for<'r> Fn(&'r HgPath) -> bool + Sync + 'a>;
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 /// Dates and times that are outside the 31-bit signed range are compared
109 /// Dates and times that are outside the 31-bit signed range are compared
102 /// modulo 2^31. This should prevent hg from behaving badly with very large
110 /// modulo 2^31. This should prevent hg from behaving badly with very large
103 /// files or corrupt dates while still having a high probability of detecting
111 /// files or corrupt dates while still having a high probability of detecting
@@ -232,22 +240,25 b' pub struct StatusOptions {'
232
240
233 #[derive(Debug)]
241 #[derive(Debug)]
234 pub struct DirstateStatus<'a> {
242 pub struct DirstateStatus<'a> {
235 pub modified: Vec<Cow<'a, HgPath>>,
243 pub modified: Vec<HgPathCow<'a>>,
236 pub added: Vec<Cow<'a, HgPath>>,
244 pub added: Vec<HgPathCow<'a>>,
237 pub removed: Vec<Cow<'a, HgPath>>,
245 pub removed: Vec<HgPathCow<'a>>,
238 pub deleted: Vec<Cow<'a, HgPath>>,
246 pub deleted: Vec<HgPathCow<'a>>,
239 pub clean: Vec<Cow<'a, HgPath>>,
247 pub clean: Vec<HgPathCow<'a>>,
240 pub ignored: Vec<Cow<'a, HgPath>>,
248 pub ignored: Vec<HgPathCow<'a>>,
241 pub unknown: Vec<Cow<'a, HgPath>>,
249 pub unknown: Vec<HgPathCow<'a>>,
242 pub bad: Vec<(Cow<'a, HgPath>, BadMatch)>,
250 pub bad: Vec<(HgPathCow<'a>, BadMatch)>,
243 /// Only filled if `collect_traversed_dirs` is `true`
251 /// Only filled if `collect_traversed_dirs` is `true`
244 pub traversed: Vec<HgPathBuf>,
252 pub traversed: Vec<HgPathBuf>,
245 }
253 }
246
254
247 #[derive(Debug)]
255 #[derive(Debug)]
248 pub enum StatusError {
256 pub enum StatusError {
257 /// Generic IO error
249 IO(std::io::Error),
258 IO(std::io::Error),
259 /// An invalid path that cannot be represented in Mercurial was found
250 Path(HgPathError),
260 Path(HgPathError),
261 /// An invalid "ignore" pattern was found
251 Pattern(PatternError),
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 pub struct Status<'a, M: Matcher + Sync> {
295 pub struct Status<'a, M: Matcher + Sync> {
283 dmap: &'a DirstateMap,
296 dmap: &'a DirstateMap,
284 matcher: &'a M,
297 matcher: &'a M,
@@ -319,6 +332,7 b' where'
319 ))
332 ))
320 }
333 }
321
334
335 /// Is the path ignored?
322 pub fn is_ignored(&self, path: impl AsRef<HgPath>) -> bool {
336 pub fn is_ignored(&self, path: impl AsRef<HgPath>) -> bool {
323 (self.ignore_fn)(path.as_ref())
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 /// TODO subrepos
362 /// TODO subrepos
347 #[timed]
363 #[timed]
348 pub fn walk_explicit(
364 pub fn walk_explicit(
349 &self,
365 &self,
350 traversed_sender: crossbeam::Sender<HgPathBuf>,
366 traversed_sender: crossbeam::Sender<HgPathBuf>,
351 ) -> (
367 ) -> (Vec<DispatchedPath<'a>>, Vec<DispatchedPath<'a>>) {
352 Vec<(Cow<'a, HgPath>, Dispatch)>,
353 Vec<(Cow<'a, HgPath>, Dispatch)>,
354 ) {
355 self.matcher
368 self.matcher
356 .file_set()
369 .file_set()
357 .unwrap_or(&DEFAULT_WORK)
370 .unwrap_or(&DEFAULT_WORK)
@@ -443,8 +456,8 b' where'
443 pub fn traverse(
456 pub fn traverse(
444 &self,
457 &self,
445 path: impl AsRef<HgPath>,
458 path: impl AsRef<HgPath>,
446 old_results: &FastHashMap<Cow<'a, HgPath>, Dispatch>,
459 old_results: &FastHashMap<HgPathCow<'a>, Dispatch>,
447 results: &mut Vec<(Cow<'a, HgPath>, Dispatch)>,
460 results: &mut Vec<DispatchedPath<'a>>,
448 traversed_sender: crossbeam::Sender<HgPathBuf>,
461 traversed_sender: crossbeam::Sender<HgPathBuf>,
449 ) -> IoResult<()> {
462 ) -> IoResult<()> {
450 // The traversal is done in parallel, so use a channel to gather
463 // The traversal is done in parallel, so use a channel to gather
@@ -637,23 +650,25 b' where'
637
650
638 let skip_dot_hg = !directory.as_bytes().is_empty();
651 let skip_dot_hg = !directory.as_bytes().is_empty();
639 let entries = match list_directory(dir_path, skip_dot_hg) {
652 let entries = match list_directory(dir_path, skip_dot_hg) {
640 Err(e) => match e.kind() {
653 Err(e) => {
641 ErrorKind::NotFound | ErrorKind::PermissionDenied => {
654 return match e.kind() {
642 files_sender
655 ErrorKind::NotFound | ErrorKind::PermissionDenied => {
643 .send(Ok((
656 files_sender
644 directory.to_owned(),
657 .send(Ok((
645 Dispatch::Bad(BadMatch::OsError(
658 directory.to_owned(),
646 // Unwrapping here is OK because the error
659 Dispatch::Bad(BadMatch::OsError(
647 // always is a
660 // Unwrapping here is OK because the error
648 // real os error
661 // always is a
649 e.raw_os_error().unwrap(),
662 // real os error
650 )),
663 e.raw_os_error().unwrap(),
651 )))
664 )),
652 .unwrap();
665 )))
653 return Ok(());
666 .expect("receiver should outlive sender");
654 }
667 Ok(())
655 _ => return Err(e),
668 }
656 },
669 _ => Err(e),
670 };
671 }
657 Ok(entries) => entries,
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 /// This takes a mutable reference to the results to account for the
708 /// This takes a mutable reference to the results to account for the
690 /// `extend` in timings
709 /// `extend` in timings
691 #[timed]
710 #[timed]
692 fn handle_unknowns(
711 fn handle_unknowns(
693 &self,
712 &self,
694 results: &mut Vec<(Cow<'a, HgPath>, Dispatch)>,
713 results: &mut Vec<DispatchedPath<'a>>,
695 ) -> IoResult<()> {
714 ) -> IoResult<()> {
696 let to_visit: Vec<(&HgPath, &DirstateEntry)> =
715 let to_visit: Vec<(&HgPath, &DirstateEntry)> =
697 if results.is_empty() && self.matcher.matches_everything() {
716 if results.is_empty() && self.matcher.matches_everything() {
@@ -714,9 +733,6 b' where'
714 .collect()
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 let path_auditor = PathAuditor::new(&self.root_dir);
736 let path_auditor = PathAuditor::new(&self.root_dir);
721
737
722 // TODO don't collect. Find a way of replicating the behavior of
738 // TODO don't collect. Find a way of replicating the behavior of
@@ -766,13 +782,12 b' where'
766 Ok(())
782 Ok(())
767 }
783 }
768
784
785 /// Add the files in the dirstate to the results.
786 ///
769 /// This takes a mutable reference to the results to account for the
787 /// This takes a mutable reference to the results to account for the
770 /// `extend` in timings
788 /// `extend` in timings
771 #[timed]
789 #[timed]
772 fn extend_from_dmap(
790 fn extend_from_dmap(&self, results: &mut Vec<DispatchedPath<'a>>) {
773 &self,
774 results: &mut Vec<(Cow<'a, HgPath>, Dispatch)>,
775 ) {
776 results.par_extend(self.dmap.par_iter().flat_map(
791 results.par_extend(self.dmap.par_iter().flat_map(
777 move |(filename, entry)| {
792 move |(filename, entry)| {
778 let filename: &HgPath = filename;
793 let filename: &HgPath = filename;
@@ -823,9 +838,9 b' where'
823
838
824 #[timed]
839 #[timed]
825 fn build_response<'a>(
840 fn build_response<'a>(
826 results: impl IntoIterator<Item = (Cow<'a, HgPath>, Dispatch)>,
841 results: impl IntoIterator<Item = DispatchedPath<'a>>,
827 traversed: Vec<HgPathBuf>,
842 traversed: Vec<HgPathBuf>,
828 ) -> (Vec<Cow<'a, HgPath>>, DirstateStatus<'a>) {
843 ) -> (Vec<HgPathCow<'a>>, DirstateStatus<'a>) {
829 let mut lookup = vec![];
844 let mut lookup = vec![];
830 let mut modified = vec![];
845 let mut modified = vec![];
831 let mut added = vec![];
846 let mut added = vec![];
@@ -881,7 +896,7 b" pub fn status<'a>("
881 ignore_files: Vec<PathBuf>,
896 ignore_files: Vec<PathBuf>,
882 options: StatusOptions,
897 options: StatusOptions,
883 ) -> StatusResult<(
898 ) -> StatusResult<(
884 (Vec<Cow<'a, HgPath>>, DirstateStatus<'a>),
899 (Vec<HgPathCow<'a>>, DirstateStatus<'a>),
885 Vec<PatternFileWarning>,
900 Vec<PatternFileWarning>,
886 )> {
901 )> {
887 let (traversed_sender, traversed_receiver) =
902 let (traversed_sender, traversed_receiver) =
@@ -922,16 +937,12 b" pub fn status<'a>("
922 }
937 }
923
938
924 if !matcher.is_exact() {
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 if options.list_unknown {
940 if options.list_unknown {
931 st.handle_unknowns(&mut results)?;
941 st.handle_unknowns(&mut results)?;
932 } else {
942 } else {
933 // We may not have walked the full directory tree above, so stat
943 // TODO this is incorrect, see issue6335
934 // and check everything we missed.
944 // This requires a fix in both Python and Rust that can happen
945 // with other pending changes to `status`.
935 st.extend_from_dmap(&mut results);
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