Mercurial > hg
diff rust/hg-core/src/dirstate/status.rs @ 44537:5f6a504dc0bd
rust-status: refactor handling of unknown files
Differential Revision: https://phab.mercurial-scm.org/D8249
author | Raphaël Gomès <rgomes@octobus.net> |
---|---|
date | Fri, 06 Mar 2020 17:48:30 +0100 |
parents | f8a9922a02cb |
children | b8ba46c97cdd |
line wrap: on
line diff
--- a/rust/hg-core/src/dirstate/status.rs Wed Feb 19 11:14:30 2020 +0100 +++ b/rust/hg-core/src/dirstate/status.rs Fri Mar 06 17:48:30 2020 +0100 @@ -597,6 +597,85 @@ } } +/// This takes a mutable reference to the results to account for the `extend` +/// in timings +fn handle_unknowns<'a>( + dmap: &'a DirstateMap, + matcher: &(impl Matcher + Sync), + root_dir: impl AsRef<Path> + Sync + Send + Copy, + options: StatusOptions, + results: &mut Vec<(Cow<'a, HgPath>, Dispatch)>, +) -> IoResult<()> { + let to_visit: Vec<(&HgPath, &DirstateEntry)> = if results.is_empty() + && matcher.matches_everything() + { + dmap.iter().map(|(f, e)| (f.deref(), e)).collect() + } else { + // Only convert to a hashmap if needed. + let old_results: FastHashMap<_, _> = results.iter().cloned().collect(); + dmap.iter() + .filter_map(move |(f, e)| { + if !old_results.contains_key(f.deref()) && matcher.matches(f) { + Some((f.deref(), e)) + } else { + None + } + }) + .collect() + }; + + // We walked all dirs under the roots that weren't ignored, and + // everything that matched was stat'ed and is already in results. + // The rest must thus be ignored or under a symlink. + let path_auditor = PathAuditor::new(root_dir); + + // TODO don't collect. Find a way of replicating the behavior of + // `itertools::process_results`, but for `rayon::ParallelIterator` + let new_results: IoResult<Vec<_>> = to_visit + .into_par_iter() + .filter_map(|(filename, entry)| -> Option<IoResult<_>> { + // Report ignored items in the dmap as long as they are not + // under a symlink directory. + if path_auditor.check(filename) { + // TODO normalize for case-insensitive filesystems + let buf = match hg_path_to_path_buf(filename) { + Ok(x) => x, + Err(e) => return Some(Err(e.into())), + }; + Some(Ok(( + Cow::Borrowed(filename), + match root_dir.as_ref().join(&buf).symlink_metadata() { + // File was just ignored, no links, and exists + Ok(meta) => { + let metadata = HgMetadata::from_metadata(meta); + dispatch_found( + filename, + *entry, + metadata, + &dmap.copy_map, + options, + ) + } + // File doesn't exist + Err(_) => dispatch_missing(entry.state), + }, + ))) + } else { + // It's either missing or under a symlink directory which + // we, in this case, report as missing. + Some(Ok(( + Cow::Borrowed(filename), + dispatch_missing(entry.state), + ))) + } + }) + .collect(); + + results.par_extend(new_results?); + + Ok(()) +} + /// Get the status of files in the working directory. /// /// This is the current entry-point for `hg-core` and is realistically unusable @@ -683,64 +762,7 @@ // symlink directory. if options.list_unknown { - let to_visit: Box<dyn Iterator<Item = (&HgPath, &DirstateEntry)>> = - if results.is_empty() && matcher.matches_everything() { - Box::new(dmap.iter().map(|(f, e)| (f.deref(), e))) - } else { - // Only convert to a hashmap if needed. - let old_results: FastHashMap<_, _> = - results.iter().cloned().collect(); - Box::new(dmap.iter().filter_map(move |(f, e)| { - if !old_results.contains_key(f.deref()) - && matcher.matches(f) - { - Some((f.deref(), e)) - } else { - None - } - })) - }; - let mut to_visit: Vec<_> = to_visit.collect(); - to_visit.sort_by(|a, b| a.0.cmp(&b.0)); - - // We walked all dirs under the roots that weren't ignored, and - // everything that matched was stat'ed and is already in results. - // The rest must thus be ignored or under a symlink. - let path_auditor = PathAuditor::new(root_dir); - - for (ref filename, entry) in to_visit { - // Report ignored items in the dmap as long as they are not - // under a symlink directory. - if path_auditor.check(filename) { - // TODO normalize for case-insensitive filesystems - let buf = hg_path_to_path_buf(filename)?; - results.push(( - Cow::Borrowed(filename), - match root_dir.as_ref().join(&buf).symlink_metadata() { - // File was just ignored, no links, and exists - Ok(meta) => { - let metadata = HgMetadata::from_metadata(meta); - dispatch_found( - filename, - *entry, - metadata, - &dmap.copy_map, - options, - ) - } - // File doesn't exist - Err(_) => dispatch_missing(entry.state), - }, - )); - } else { - // It's either missing or under a symlink directory which - // we, in this case, report as missing. - results.push(( - Cow::Borrowed(filename), - dispatch_missing(entry.state), - )); - } - } + handle_unknowns(dmap, matcher, root_dir, options, &mut results)?; } else { // We may not have walked the full directory tree above, so stat // and check everything we missed.