diff rust/hg-core/src/filepatterns.rs @ 52384:2ff004fb491c

hgignore: add a GlobSuffix type, instead of passing byte arrays I think this makes it easier to understand the purpose of this extra argument.
author Arseniy Alekseyev <aalekseyev@janestreet.com>
date Mon, 02 Dec 2024 11:25:26 +0000
parents f33b87b46135
children e2e49069eeb6
line wrap: on
line diff
--- a/rust/hg-core/src/filepatterns.rs	Fri Nov 29 19:43:39 2024 -0500
+++ b/rust/hg-core/src/filepatterns.rs	Mon Dec 02 11:25:26 2024 +0000
@@ -214,10 +214,33 @@
     static ref FLAG_RE: Regex = Regex::new(r"^\(\?[aiLmsux]+\)").unwrap();
 }
 
+/// Extra path components to match at the end of the pattern
+#[derive(Clone, Copy)]
+pub enum GlobSuffix {
+    /// `Empty` means the pattern only matches files, not directories,
+    /// so the path needs to match exactly.
+    Empty,
+    /// `MoreComponents` means the pattern matches directories as well,
+    /// so any path that has the pattern as a prefix, should match.
+    MoreComponents,
+}
+
+impl GlobSuffix {
+    fn to_re(self) -> &'static [u8] {
+        match self {
+            Self::Empty => b"$",
+            Self::MoreComponents => b"(?:/|$)",
+        }
+    }
+}
+
 /// Builds the regex that corresponds to the given pattern.
 /// If within a `syntax: regexp` context, returns the pattern,
 /// otherwise, returns the corresponding regex.
-fn _build_single_regex(entry: &IgnorePattern, glob_suffix: &[u8]) -> Vec<u8> {
+fn _build_single_regex(
+    entry: &IgnorePattern,
+    glob_suffix: GlobSuffix,
+) -> Vec<u8> {
     let IgnorePattern {
         syntax, pattern, ..
     } = entry;
@@ -264,7 +287,11 @@
             if pattern == b"." {
                 return vec![];
             }
-            [escape_pattern(pattern).as_slice(), b"(?:/|$)"].concat()
+            [
+                escape_pattern(pattern).as_slice(),
+                GlobSuffix::MoreComponents.to_re(),
+            ]
+            .concat()
         }
         PatternSyntax::RootFilesIn => {
             let mut res = if pattern == b"." {
@@ -281,13 +308,13 @@
         PatternSyntax::RelGlob => {
             let glob_re = glob_to_re(pattern);
             if let Some(rest) = glob_re.drop_prefix(b"[^/]*") {
-                [b".*", rest, glob_suffix].concat()
+                [b".*", rest, glob_suffix.to_re()].concat()
             } else {
-                [b"(?:.*/)?", glob_re.as_slice(), glob_suffix].concat()
+                [b"(?:.*/)?", glob_re.as_slice(), glob_suffix.to_re()].concat()
             }
         }
         PatternSyntax::Glob | PatternSyntax::RootGlob => {
-            [glob_to_re(pattern).as_slice(), glob_suffix].concat()
+            [glob_to_re(pattern).as_slice(), glob_suffix.to_re()].concat()
         }
         PatternSyntax::Include
         | PatternSyntax::SubInclude
@@ -345,7 +372,7 @@
 /// that don't need to be transformed into a regex.
 pub fn build_single_regex(
     entry: &IgnorePattern,
-    glob_suffix: &[u8],
+    glob_suffix: GlobSuffix,
 ) -> Result<Option<Vec<u8>>, PatternError> {
     let IgnorePattern {
         pattern, syntax, ..
@@ -800,7 +827,7 @@
                     b"rust/target/",
                     Path::new("")
                 ),
-                b"(?:/|$)"
+                GlobSuffix::MoreComponents
             )
             .unwrap(),
             Some(br"(?:.*/)?rust/target(?:/|$)".to_vec()),
@@ -812,7 +839,7 @@
                     br"rust/target/\d+",
                     Path::new("")
                 ),
-                b"(?:/|$)"
+                GlobSuffix::MoreComponents
             )
             .unwrap(),
             Some(br"rust/target/\d+".to_vec()),
@@ -828,7 +855,7 @@
                     b"",
                     Path::new("")
                 ),
-                b"(?:/|$)"
+                GlobSuffix::MoreComponents
             )
             .unwrap(),
             None,
@@ -840,7 +867,7 @@
                     b"whatever",
                     Path::new("")
                 ),
-                b"(?:/|$)"
+                GlobSuffix::MoreComponents
             )
             .unwrap(),
             None,
@@ -852,7 +879,7 @@
                     b"*.o",
                     Path::new("")
                 ),
-                b"(?:/|$)"
+                GlobSuffix::MoreComponents
             )
             .unwrap(),
             Some(br"[^/]*\.o(?:/|$)".to_vec()),
@@ -868,7 +895,7 @@
                     b"^ba{2}r",
                     Path::new("")
                 ),
-                b"(?:/|$)"
+                GlobSuffix::MoreComponents
             )
             .unwrap(),
             Some(b"^ba{2}r".to_vec()),
@@ -880,7 +907,7 @@
                     b"ba{2}r",
                     Path::new("")
                 ),
-                b"(?:/|$)"
+                GlobSuffix::MoreComponents
             )
             .unwrap(),
             Some(b".*ba{2}r".to_vec()),
@@ -892,7 +919,7 @@
                     b"(?ia)ba{2}r",
                     Path::new("")
                 ),
-                b"(?:/|$)"
+                GlobSuffix::MoreComponents
             )
             .unwrap(),
             Some(b"(?ia:.*ba{2}r)".to_vec()),
@@ -904,7 +931,7 @@
                     b"(?ia)^ba{2}r",
                     Path::new("")
                 ),
-                b"(?:/|$)"
+                GlobSuffix::MoreComponents
             )
             .unwrap(),
             Some(b"(?ia:^ba{2}r)".to_vec()),