Details
Details
- Reviewers
- None
- Group Reviewers
hg-reviewers - Commits
- rHG5f6a504dc0bd: rust-status: refactor handling of unknown files
Diff Detail
Diff Detail
- Repository
- rHG Mercurial
- Branch
- default
- Lint
No Linters Available - Unit
No Unit Test Coverage
hg-reviewers |
No Linters Available |
No Unit Test Coverage |
Path | Packages | |||
---|---|---|---|---|
M | rust/hg-core/src/dirstate/status.rs (138 lines) |
Commit | Parents | Author | Summary | Date |
---|---|---|---|---|
afce9a4a6d56 | 7bea3ca9a4ff | Raphaël Gomès | Mar 6 2020, 11:48 AM |
Status | Author | Revision | |
---|---|---|---|
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | D8252 rust: add logging utils | |
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare | ||
Closed | Alphare |
match self { | match self { | ||||
StatusError::IO(e) => e.to_string(), | StatusError::IO(e) => e.to_string(), | ||||
StatusError::Path(e) => e.to_string(), | StatusError::Path(e) => e.to_string(), | ||||
StatusError::Pattern(e) => e.to_string(), | StatusError::Pattern(e) => e.to_string(), | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/// 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. | /// Get the status of files in the working directory. | ||||
/// | /// | ||||
/// This is the current entry-point for `hg-core` and is realistically unusable | /// This is the current entry-point for `hg-core` and is realistically unusable | ||||
/// outside of a Python context because its arguments need to provide a lot of | /// outside of a Python context because its arguments need to provide a lot of | ||||
/// information that will not be necessary in the future. | /// information that will not be necessary in the future. | ||||
pub fn status<'a: 'c, 'b: 'c, 'c>( | pub fn status<'a: 'c, 'b: 'c, 'c>( | ||||
dmap: &'a DirstateMap, | dmap: &'a DirstateMap, | ||||
matcher: &'b (impl Matcher + Sync), | matcher: &'b (impl Matcher + Sync), | ||||
if !matcher.is_exact() { | if !matcher.is_exact() { | ||||
// Step 3: Check the remaining files from the dmap. | // Step 3: Check the remaining files from the dmap. | ||||
// If a dmap file is not in results yet, it was either | // If a dmap file is not in results yet, it was either | ||||
// a) not matched b) ignored, c) missing, or d) under a | // a) not matched b) ignored, c) missing, or d) under a | ||||
// symlink directory. | // symlink directory. | ||||
if options.list_unknown { | if options.list_unknown { | ||||
let to_visit: Box<dyn Iterator<Item = (&HgPath, &DirstateEntry)>> = | handle_unknowns(dmap, matcher, root_dir, options, &mut results)?; | ||||
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), | |||||
)); | |||||
} | |||||
} | |||||
} else { | } else { | ||||
// We may not have walked the full directory tree above, so stat | // We may not have walked the full directory tree above, so stat | ||||
// and check everything we missed. | // and check everything we missed. | ||||
let stat_results = stat_dmap_entries(&dmap, root_dir, options); | let stat_results = stat_dmap_entries(&dmap, root_dir, options); | ||||
results.par_extend(stat_results.flatten().map( | results.par_extend(stat_results.flatten().map( | ||||
|(filename, dispatch)| (Cow::Borrowed(filename), dispatch), | |(filename, dispatch)| (Cow::Borrowed(filename), dispatch), | ||||
)); | )); | ||||
} | } | ||||
} | } | ||||
Ok((build_response(results), warnings)) | Ok((build_response(results), warnings)) | ||||
} | } |