##// END OF EJS Templates
rust-filepatterns: match exact `rootglob`s with a `HashSet`, not in the regex...
Raphaël Gomès -
r45311:e0414fcd default
parent child Browse files
Show More
@@ -271,7 +271,7 b' pub fn normalize_path_bytes(bytes: &[u8]'
271 /// that don't need to be transformed into a regex.
271 /// that don't need to be transformed into a regex.
272 pub fn build_single_regex(
272 pub fn build_single_regex(
273 entry: &IgnorePattern,
273 entry: &IgnorePattern,
274 ) -> Result<Vec<u8>, PatternError> {
274 ) -> Result<Option<Vec<u8>>, PatternError> {
275 let IgnorePattern {
275 let IgnorePattern {
276 pattern, syntax, ..
276 pattern, syntax, ..
277 } = entry;
277 } = entry;
@@ -288,16 +288,11 b' pub fn build_single_regex('
288 if *syntax == PatternSyntax::RootGlob
288 if *syntax == PatternSyntax::RootGlob
289 && !pattern.iter().any(|b| GLOB_SPECIAL_CHARACTERS.contains(b))
289 && !pattern.iter().any(|b| GLOB_SPECIAL_CHARACTERS.contains(b))
290 {
290 {
291 // The `regex` crate adds `.*` to the start and end of expressions
291 Ok(None)
292 // if there are no anchors, so add the start anchor.
293 let mut escaped = vec![b'^'];
294 escaped.extend(escape_pattern(&pattern));
295 escaped.extend(GLOB_SUFFIX);
296 Ok(escaped)
297 } else {
292 } else {
298 let mut entry = entry.clone();
293 let mut entry = entry.clone();
299 entry.pattern = pattern;
294 entry.pattern = pattern;
300 Ok(_build_single_regex(&entry))
295 Ok(Some(_build_single_regex(&entry)))
301 }
296 }
302 }
297 }
303
298
@@ -628,7 +623,7 b' mod tests {'
628 Path::new("")
623 Path::new("")
629 ))
624 ))
630 .unwrap(),
625 .unwrap(),
631 br"(?:.*/)?rust/target(?:/|$)".to_vec(),
626 Some(br"(?:.*/)?rust/target(?:/|$)".to_vec()),
632 );
627 );
633 }
628 }
634
629
@@ -641,7 +636,7 b' mod tests {'
641 Path::new("")
636 Path::new("")
642 ))
637 ))
643 .unwrap(),
638 .unwrap(),
644 br"^\.(?:/|$)".to_vec(),
639 None,
645 );
640 );
646 assert_eq!(
641 assert_eq!(
647 build_single_regex(&IgnorePattern::new(
642 build_single_regex(&IgnorePattern::new(
@@ -650,7 +645,7 b' mod tests {'
650 Path::new("")
645 Path::new("")
651 ))
646 ))
652 .unwrap(),
647 .unwrap(),
653 br"^whatever(?:/|$)".to_vec(),
648 None,
654 );
649 );
655 assert_eq!(
650 assert_eq!(
656 build_single_regex(&IgnorePattern::new(
651 build_single_regex(&IgnorePattern::new(
@@ -659,7 +654,7 b' mod tests {'
659 Path::new("")
654 Path::new("")
660 ))
655 ))
661 .unwrap(),
656 .unwrap(),
662 br"^[^/]*\.o(?:/|$)".to_vec(),
657 Some(br"^[^/]*\.o(?:/|$)".to_vec()),
663 );
658 );
664 }
659 }
665 }
660 }
@@ -24,6 +24,7 b' use crate::{'
24 PatternSyntax,
24 PatternSyntax,
25 };
25 };
26
26
27 use crate::filepatterns::normalize_path_bytes;
27 use std::borrow::ToOwned;
28 use std::borrow::ToOwned;
28 use std::collections::HashSet;
29 use std::collections::HashSet;
29 use std::fmt::{Display, Error, Formatter};
30 use std::fmt::{Display, Error, Formatter};
@@ -373,15 +374,32 b' fn re_matcher('
373 fn build_regex_match<'a>(
374 fn build_regex_match<'a>(
374 ignore_patterns: &'a [&'a IgnorePattern],
375 ignore_patterns: &'a [&'a IgnorePattern],
375 ) -> PatternResult<(Vec<u8>, Box<dyn Fn(&HgPath) -> bool + Sync>)> {
376 ) -> PatternResult<(Vec<u8>, Box<dyn Fn(&HgPath) -> bool + Sync>)> {
376 let regexps: Result<Vec<_>, PatternError> = ignore_patterns
377 let mut regexps = vec![];
377 .into_iter()
378 let mut exact_set = HashSet::new();
378 .map(|k| build_single_regex(*k))
379
379 .collect();
380 for pattern in ignore_patterns {
380 let regexps = regexps?;
381 if let Some(re) = build_single_regex(pattern)? {
382 regexps.push(re);
383 } else {
384 let exact = normalize_path_bytes(&pattern.pattern);
385 exact_set.insert(HgPathBuf::from_bytes(&exact));
386 }
387 }
388
381 let full_regex = regexps.join(&b'|');
389 let full_regex = regexps.join(&b'|');
382
390
383 let matcher = re_matcher(&full_regex)?;
391 // An empty pattern would cause the regex engine to incorrectly match the
384 let func = Box::new(move |filename: &HgPath| matcher(filename));
392 // (empty) root directory
393 let func = if !(regexps.is_empty()) {
394 let matcher = re_matcher(&full_regex)?;
395 let func = move |filename: &HgPath| {
396 exact_set.contains(filename) || matcher(filename)
397 };
398 Box::new(func) as Box<dyn Fn(&HgPath) -> bool + Sync>
399 } else {
400 let func = move |filename: &HgPath| exact_set.contains(filename);
401 Box::new(func) as Box<dyn Fn(&HgPath) -> bool + Sync>
402 };
385
403
386 Ok((full_regex, func))
404 Ok((full_regex, func))
387 }
405 }
General Comments 0
You need to be logged in to leave comments. Login now