diff --git a/rust/hg-core/src/matchers.rs b/rust/hg-core/src/matchers.rs --- a/rust/hg-core/src/matchers.rs +++ b/rust/hg-core/src/matchers.rs @@ -29,6 +29,7 @@ use std::iter::FromIterator; use std::ops::Deref; use std::path::{Path, PathBuf}; +use crate::dirstate::status::IgnoreFnType; use micro_timer::timed; @@ -246,7 +247,7 @@ /// ``` pub struct IncludeMatcher<'a> { patterns: Vec, - match_fn: Box Fn(&'r HgPath) -> bool + 'a + Sync>, + match_fn: IgnoreFnType<'a>, /// Whether all the patterns match a prefix (i.e. recursively) prefix: bool, roots: HashSet, @@ -341,9 +342,9 @@ /// Returns the regex pattern and a function that matches an `HgPath` against /// said regex formed by the given ignore patterns. -fn build_regex_match( - ignore_patterns: &[IgnorePattern], -) -> PatternResult<(Vec, Box bool + Sync>)> { +fn build_regex_match<'a, 'b>( + ignore_patterns: &'a[IgnorePattern], +) -> PatternResult<(Vec, IgnoreFnType<'b>)> { let mut regexps = vec![]; let mut exact_set = HashSet::new(); @@ -365,10 +366,10 @@ let func = move |filename: &HgPath| { exact_set.contains(filename) || matcher(filename) }; - Box::new(func) as Box bool + Sync> + Box::new(func) as IgnoreFnType } else { let func = move |filename: &HgPath| exact_set.contains(filename); - Box::new(func) as Box bool + Sync> + Box::new(func) as IgnoreFnType }; Ok((full_regex, func)) @@ -479,8 +480,8 @@ /// should be matched. fn build_match<'a, 'b>( ignore_patterns: Vec, -) -> PatternResult<(Vec, Box bool + 'b + Sync>)> { - let mut match_funcs: Vec bool + Sync>> = vec![]; +) -> PatternResult<(Vec, IgnoreFnType<'b>)> { + let mut match_funcs: Vec> = vec![]; // For debugging and printing let mut patterns = vec![]; @@ -563,14 +564,11 @@ /// Parses all "ignore" files with their recursive includes and returns a /// function that checks whether a given file (in the general sense) should be /// ignored. -pub fn get_ignore_function<'a>( +pub fn get_ignore_matcher<'a>( mut all_pattern_files: Vec, root_dir: &Path, inspect_pattern_bytes: &mut impl FnMut(&[u8]), -) -> PatternResult<( - Box Fn(&'r HgPath) -> bool + Sync + 'a>, - Vec, -)> { +) -> PatternResult<(IncludeMatcher<'a>, Vec)> { let mut all_patterns = vec![]; let mut all_warnings = vec![]; @@ -593,10 +591,28 @@ all_warnings.extend(warnings); } let matcher = IncludeMatcher::new(all_patterns)?; - Ok(( - Box::new(move |path: &HgPath| matcher.matches(path)), - all_warnings, - )) + Ok((matcher, all_warnings)) +} + +/// Parses all "ignore" files with their recursive includes and returns a +/// function that checks whether a given file (in the general sense) should be +/// ignored. +pub fn get_ignore_function<'a>( + all_pattern_files: Vec, + root_dir: &Path, + inspect_pattern_bytes: &mut impl FnMut(&[u8]), +) -> PatternResult<( + IgnoreFnType<'a>, + Vec, +)> { + let res = + get_ignore_matcher(all_pattern_files, root_dir, inspect_pattern_bytes); + res.map(|(matcher, all_warnings)| { + let res: IgnoreFnType<'a> = + Box::new(move |path: &HgPath| matcher.matches(path)); + + (res, all_warnings) + }) } impl<'a> IncludeMatcher<'a> { @@ -631,6 +647,10 @@ .chain(self.parents.iter()); DirsChildrenMultiset::new(thing, Some(&self.parents)) } + + pub fn debug_get_patterns(&self) -> &[u8] { + self.patterns.as_ref() + } } impl<'a> Display for IncludeMatcher<'a> { diff --git a/rust/rhg/src/commands/debugignorerhg.rs b/rust/rhg/src/commands/debugignorerhg.rs new file mode 100644 --- /dev/null +++ b/rust/rhg/src/commands/debugignorerhg.rs @@ -0,0 +1,39 @@ +use crate::error::CommandError; +use clap::SubCommand; +use hg; +use hg::matchers::get_ignore_matcher; +use hg::StatusError; +use log::warn; + +pub const HELP_TEXT: &str = " +Show effective hgignore patterns used by rhg. + +This is a pure Rust version of `hg debugignore`. + +Some options might be missing, check the list below. +"; + +pub fn args() -> clap::App<'static, 'static> { + SubCommand::with_name("debugignorerhg").about(HELP_TEXT) +} + +pub fn run(invocation: &crate::CliInvocation) -> Result<(), CommandError> { + let repo = invocation.repo?; + + let ignore_file = repo.working_directory_vfs().join(".hgignore"); // TODO hardcoded + + let (ignore_matcher, warnings) = get_ignore_matcher( + vec![ignore_file], + &repo.working_directory_path().to_owned(), + &mut |_pattern_bytes| (), + ) + .map_err(|e| StatusError::from(e))?; + + if !warnings.is_empty() { + warn!("Pattern warnings: {:?}", &warnings); + } + + let patterns = ignore_matcher.debug_get_patterns(); + println!("{}", String::from_utf8_lossy(patterns)); + Ok(()) +} diff --git a/rust/rhg/src/main.rs b/rust/rhg/src/main.rs --- a/rust/rhg/src/main.rs +++ b/rust/rhg/src/main.rs @@ -465,6 +465,7 @@ cat debugdata debugrequirements + debugignorerhg files root config