matcher: do not prepend '.*' to pattern using ^ after flags stable
authorPierre-Yves David <pierre-yves.david@octobus.net>
Wed, 16 Nov 2022 15:39:10 +0100
branchstable
changeset 49605 b3480822a251
parent 49604 086b0c4f8663
child 49606 4092db99541a
matcher: do not prepend '.*' to pattern using ^ after flags Since the previous commit (fixing wider issue), the code generated strange regex. This is now fixed and tested.
mercurial/match.py
rust/hg-core/src/filepatterns.rs
tests/test-hgignore.t
--- a/mercurial/match.py	Wed Nov 16 16:38:42 2022 +0100
+++ b/mercurial/match.py	Wed Nov 16 15:39:10 2022 +0100
@@ -1323,7 +1323,7 @@
     return res
 
 
-FLAG_RE = util.re.compile(b'^\(\?([aiLmsux]+)\)')
+FLAG_RE = util.re.compile(b'^\(\?([aiLmsux]+)\)(.*)')
 
 
 def _regex(kind, pat, globsuffix):
@@ -1354,11 +1354,15 @@
             return b'.*' + globre[len(b'[^/]*') :] + globsuffix
         return b'(?:|.*/)' + globre + globsuffix
     if kind == b'relre':
-        if pat.startswith(b'^'):
-            return pat
-        if FLAG_RE.match(pat):
-            return FLAG_RE.sub(br'(?\1:.*', pat) + b')'
-        return b'.*' + pat
+        flag = None
+        m = FLAG_RE.match(pat)
+        if m:
+            flag, pat = m.groups()
+        if not pat.startswith(b'^'):
+            pat = b'.*' + pat
+        if flag is not None:
+            pat = br'(?%s:%s)' % (flag, pat)
+        return pat
     if kind in (b'glob', b'rootglob'):
         return _globre(pat) + globsuffix
     raise error.ProgrammingError(b'not a regex pattern: %s:%s' % (kind, pat))
--- a/rust/hg-core/src/filepatterns.rs	Wed Nov 16 16:38:42 2022 +0100
+++ b/rust/hg-core/src/filepatterns.rs	Wed Nov 16 15:39:10 2022 +0100
@@ -205,7 +205,14 @@
                         &b"(?"[..],
                         &pattern[s + 2..e - 1],
                         &b":"[..],
-                        &b".*"[..],
+                        if pattern[e] == b'^'
+                            || pattern[e] == b'*'
+                            || pattern[e..].starts_with(b".*")
+                        {
+                            &b""[..]
+                        } else {
+                            &b".*"[..]
+                        },
                         &pattern[e..],
                         &b")"[..],
                     ]
@@ -752,5 +759,14 @@
             .unwrap(),
             Some(b"(?ia:.*ba{2}r)".to_vec()),
         );
+        assert_eq!(
+            build_single_regex(&IgnorePattern::new(
+                PatternSyntax::RelRegexp,
+                b"(?ia)^ba{2}r",
+                Path::new("")
+            ))
+            .unwrap(),
+            Some(b"(?ia:^ba{2}r)".to_vec()),
+        );
     }
 }
--- a/tests/test-hgignore.t	Wed Nov 16 16:38:42 2022 +0100
+++ b/tests/test-hgignore.t	Wed Nov 16 15:39:10 2022 +0100
@@ -74,6 +74,8 @@
   A dir/b.o
   ? a.c
   ? syntax
+  $ hg debugignore
+  <includematcher includes='(?i:.*\\.O$)|.*.hgignore'>
 
 regex with flag is not the first one
 
@@ -83,6 +85,8 @@
   A dir/b.o
   ? a.c
   ? syntax
+  $ hg debugignore
+  <includematcher includes='.*.hgignore|(?i:.*\\.O$)'>
 
 flag in a pattern should affect that pattern only
 
@@ -93,6 +97,8 @@
   ? .hgignore
   ? a.c
   ? syntax
+  $ hg debugignore
+  <includematcher includes='(?i:.*\\.O$)|.*.HGIGNORE'>
 
   $ echo 're:.HGIGNORE' > .hgignore
   $ echo 're:(?i)\.O$' >> .hgignore
@@ -101,6 +107,32 @@
   ? .hgignore
   ? a.c
   ? syntax
+  $ hg debugignore
+  <includematcher includes='.*.HGIGNORE|(?i:.*\\.O$)'>
+
+Check that '^' after flag is properly detected.
+
+  $ echo 're:(?i)^[^a].*\.O$' > .hgignore
+  $ echo 're:.HGIGNORE' >> .hgignore
+  $ hg status
+  A dir/b.o
+  ? .hgignore
+  ? a.c
+  ? a.o
+  ? syntax
+  $ hg debugignore
+  <includematcher includes='(?i:^[^a].*\\.O$)|.*.HGIGNORE'>
+
+  $ echo 're:.HGIGNORE' > .hgignore
+  $ echo 're:(?i)^[^a].*\.O$' >> .hgignore
+  $ hg status
+  A dir/b.o
+  ? .hgignore
+  ? a.c
+  ? a.o
+  ? syntax
+  $ hg debugignore
+  <includematcher includes='.*.HGIGNORE|(?i:^[^a].*\\.O$)'>
 
 
 further testing