comparison rust/hg-core/src/filepatterns.rs @ 52385:e2e49069eeb6

rust-ignore: make `debugignorerhg` command show a full regex, with exact files
author Arseniy Alekseyev <aalekseyev@janestreet.com>
date Tue, 03 Dec 2024 13:51:51 +0000
parents 2ff004fb491c
children 1866119cbad7
comparison
equal deleted inserted replaced
52384:2ff004fb491c 52385:e2e49069eeb6
366 } else { 366 } else {
367 new_bytes 367 new_bytes
368 } 368 }
369 } 369 }
370 370
371 /// Controls whether we want the emitted regex to cover all cases
372 /// or just the cases that are not covered by optimized code paths.
373 #[derive(Debug, Clone, Copy)]
374 pub enum RegexCompleteness {
375 /// `Complete` emits a regex that handles all files, including the ones
376 /// that are typically handled by a different code path.
377 /// This is used in `hg debugignorerhg -a` to avoid missing some rules.
378 Complete,
379 /// `ExcludeExactFiles` excludes the patterns that correspond to exact
380 /// file matches. This is the normal behavior, and gives a potentially
381 /// much smaller regex.
382 ExcludeExactFiles,
383 }
384
385 impl RegexCompleteness {
386 fn may_exclude_exact_files(self) -> bool {
387 match self {
388 Self::Complete => false,
389 Self::ExcludeExactFiles => true,
390 }
391 }
392 }
393
371 /// Wrapper function to `_build_single_regex` that short-circuits 'exact' globs 394 /// Wrapper function to `_build_single_regex` that short-circuits 'exact' globs
372 /// that don't need to be transformed into a regex. 395 /// that don't need to be transformed into a regex.
373 pub fn build_single_regex( 396 pub fn build_single_regex(
374 entry: &IgnorePattern, 397 entry: &IgnorePattern,
375 glob_suffix: GlobSuffix, 398 glob_suffix: GlobSuffix,
399 regex_config: RegexCompleteness,
376 ) -> Result<Option<Vec<u8>>, PatternError> { 400 ) -> Result<Option<Vec<u8>>, PatternError> {
377 let IgnorePattern { 401 let IgnorePattern {
378 pattern, syntax, .. 402 pattern, syntax, ..
379 } = entry; 403 } = entry;
380 let pattern = match syntax { 404 let pattern = match syntax {
388 } 412 }
389 _ => pattern.to_owned(), 413 _ => pattern.to_owned(),
390 }; 414 };
391 let is_simple_rootglob = *syntax == PatternSyntax::RootGlob 415 let is_simple_rootglob = *syntax == PatternSyntax::RootGlob
392 && !pattern.iter().any(|b| GLOB_SPECIAL_CHARACTERS.contains(b)); 416 && !pattern.iter().any(|b| GLOB_SPECIAL_CHARACTERS.contains(b));
393 if is_simple_rootglob || syntax == &PatternSyntax::FilePath { 417 if regex_config.may_exclude_exact_files()
418 && (is_simple_rootglob || syntax == &PatternSyntax::FilePath)
419 {
394 Ok(None) 420 Ok(None)
395 } else { 421 } else {
396 let mut entry = entry.clone(); 422 let mut entry = entry.clone();
397 entry.pattern = pattern; 423 entry.pattern = pattern;
398 Ok(Some(_build_single_regex(&entry, glob_suffix))) 424 Ok(Some(_build_single_regex(&entry, glob_suffix)))
816 Path::new("file_path") 842 Path::new("file_path")
817 )] 843 )]
818 ); 844 );
819 } 845 }
820 846
847 pub fn build_single_regex(
848 entry: &IgnorePattern,
849 glob_suffix: GlobSuffix,
850 ) -> Result<Option<Vec<u8>>, PatternError> {
851 super::build_single_regex(
852 entry,
853 glob_suffix,
854 RegexCompleteness::ExcludeExactFiles,
855 )
856 }
857
821 #[test] 858 #[test]
822 fn test_build_single_regex() { 859 fn test_build_single_regex() {
823 assert_eq!( 860 assert_eq!(
824 build_single_regex( 861 build_single_regex(
825 &IgnorePattern::new( 862 &IgnorePattern::new(