diff --git a/rust/hg-core/src/dirstate/status.rs b/rust/hg-core/src/dirstate/status.rs --- a/rust/hg-core/src/dirstate/status.rs +++ b/rust/hg-core/src/dirstate/status.rs @@ -33,7 +33,7 @@ use std::{ fs::{read_dir, DirEntry}, io::ErrorKind, ops::Deref, - path::Path, + path::{Path, PathBuf}, }; /// Wrong type of file from a `BadMatch` @@ -94,6 +94,9 @@ enum Dispatch { } type IoResult = std::io::Result; +/// `Box` is syntactic sugar for `Box`, so add +/// an explicit lifetime here to not fight `'static` bounds "out of nowhere". +type IgnoreFnType<'a> = Box Fn(&'r HgPath) -> bool + Sync + 'a>; /// Dates and times that are outside the 31-bit signed range are compared /// modulo 2^31. This should prevent hg from behaving badly with very large @@ -312,8 +315,8 @@ fn handle_traversed_entry<'a>( root_dir: impl AsRef + Sync + Send + Copy + 'a, dmap: &'a DirstateMap, old_results: &'a FastHashMap, Dispatch>, - ignore_fn: &'a (impl for<'r> Fn(&'r HgPath) -> bool + Sync), - dir_ignore_fn: &'a (impl for<'r> Fn(&'r HgPath) -> bool + Sync), + ignore_fn: &'a IgnoreFnType, + dir_ignore_fn: &'a IgnoreFnType, options: StatusOptions, filename: HgPathBuf, dir_entry: DirEntry, @@ -393,8 +396,8 @@ fn handle_traversed_dir<'a>( root_dir: impl AsRef + Sync + Send + Copy + 'a, dmap: &'a DirstateMap, old_results: &'a FastHashMap, Dispatch>, - ignore_fn: &'a (impl for<'r> Fn(&'r HgPath) -> bool + Sync), - dir_ignore_fn: &'a (impl for<'r> Fn(&'r HgPath) -> bool + Sync), + ignore_fn: &'a IgnoreFnType, + dir_ignore_fn: &'a IgnoreFnType, options: StatusOptions, entry_option: Option<&'a DirstateEntry>, directory: HgPathBuf, @@ -439,8 +442,8 @@ fn traverse_dir<'a>( dmap: &'a DirstateMap, directory: impl AsRef, old_results: &FastHashMap, Dispatch>, - ignore_fn: &(impl for<'r> Fn(&'r HgPath) -> bool + Sync), - dir_ignore_fn: &(impl for<'r> Fn(&'r HgPath) -> bool + Sync), + ignore_fn: &IgnoreFnType, + dir_ignore_fn: &IgnoreFnType, options: StatusOptions, ) -> IoResult<()> { let directory = directory.as_ref(); @@ -522,8 +525,8 @@ fn traverse<'a>( dmap: &'a DirstateMap, path: impl AsRef, old_results: &FastHashMap, Dispatch>, - ignore_fn: &(impl for<'r> Fn(&'r HgPath) -> bool + Sync), - dir_ignore_fn: &(impl for<'r> Fn(&'r HgPath) -> bool + Sync), + ignore_fn: &IgnoreFnType, + dir_ignore_fn: &IgnoreFnType, options: StatusOptions, results: &mut Vec<(Cow<'a, HgPath>, Dispatch)>, ) -> IoResult<()> { @@ -805,26 +808,39 @@ pub fn status<'a: 'c, 'b: 'c, 'c>( dmap: &'a DirstateMap, matcher: &'b (impl Matcher + Sync), root_dir: impl AsRef + Sync + Send + Copy + 'c, - ignore_files: &[impl AsRef + 'c], + ignore_files: Vec, options: StatusOptions, ) -> StatusResult<( (Vec>, DirstateStatus<'c>), Vec, )> { - let (ignore_fn, warnings) = get_ignore_function(&ignore_files, root_dir)?; + // Needs to outlive `dir_ignore_fn` since it's captured. + let mut ignore_fn: IgnoreFnType; + + // Only involve real ignore mechanism if we're listing unknowns or ignored. + let (dir_ignore_fn, warnings): (IgnoreFnType, _) = if options.list_ignored + || options.list_unknown + { + let (ignore, warnings) = get_ignore_function(ignore_files, root_dir)?; - // Is the path or one of its ancestors ignored? - let dir_ignore_fn = |dir: &_| { - if ignore_fn(dir) { - true - } else { - for p in find_dirs(dir) { - if ignore_fn(p) { - return true; + ignore_fn = ignore; + let dir_ignore_fn = Box::new(|dir: &_| { + // Is the path or one of its ancestors ignored? + if ignore_fn(dir) { + true + } else { + for p in find_dirs(dir) { + if ignore_fn(p) { + return true; + } } + false } - false - } + }); + (dir_ignore_fn, warnings) + } else { + ignore_fn = Box::new(|&_| true); + (Box::new(|&_| true), vec![]) }; let files = matcher.file_set(); 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 @@ -24,12 +24,12 @@ use crate::{ PatternSyntax, }; -use micro_timer::timed; +use std::borrow::ToOwned; use std::collections::HashSet; use std::fmt::{Display, Error, Formatter}; use std::iter::FromIterator; use std::ops::Deref; -use std::path::Path; +use std::path::{Path, PathBuf}; #[derive(Debug, PartialEq)] pub enum VisitChildrenSet<'a> { @@ -507,7 +507,8 @@ fn build_match<'a, 'b>( let mut prefixes = vec![]; for SubInclude { prefix, root, path } in subincludes.into_iter() { - let (match_fn, warnings) = get_ignore_function(&[path], root)?; + let (match_fn, warnings) = + get_ignore_function(vec![path.to_path_buf()], root)?; all_warnings.extend(warnings); prefixes.push(prefix.to_owned()); submatchers.insert(prefix.to_owned(), match_fn); @@ -578,12 +579,11 @@ fn build_match<'a, 'b>( /// 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. -#[timed] pub fn get_ignore_function<'a>( - all_pattern_files: &[impl AsRef], + all_pattern_files: Vec, root_dir: impl AsRef, ) -> PatternResult<( - impl for<'r> Fn(&'r HgPath) -> bool + Sync, + Box Fn(&'r HgPath) -> bool + Sync + 'a>, Vec, )> { let mut all_patterns = vec![]; @@ -593,12 +593,15 @@ pub fn get_ignore_function<'a>( let (patterns, warnings) = get_patterns_from_file(pattern_file, &root_dir)?; - all_patterns.extend(patterns); + all_patterns.extend(patterns.to_owned()); all_warnings.extend(warnings); } let (matcher, warnings) = IncludeMatcher::new(all_patterns, root_dir)?; all_warnings.extend(warnings); - Ok((move |path: &HgPath| matcher.matches(path), all_warnings)) + Ok(( + Box::new(move |path: &HgPath| matcher.matches(path)), + all_warnings, + )) } impl<'a> IncludeMatcher<'a> { diff --git a/rust/hg-cpython/src/dirstate/status.rs b/rust/hg-cpython/src/dirstate/status.rs --- a/rust/hg-cpython/src/dirstate/status.rs +++ b/rust/hg-cpython/src/dirstate/status.rs @@ -127,7 +127,7 @@ pub fn status_wrapper( &dmap, &matcher, &root_dir, - &ignore_files, + ignore_files, StatusOptions { check_exec, last_normal_time, @@ -163,7 +163,7 @@ pub fn status_wrapper( &dmap, &matcher, &root_dir, - &ignore_files, + ignore_files, StatusOptions { check_exec, last_normal_time, @@ -217,7 +217,7 @@ pub fn status_wrapper( &dmap, &matcher, &root_dir, - &ignore_files, + ignore_files, StatusOptions { check_exec, last_normal_time,