Patchwork [8,of,8] ignore: allow regex sub-ignores via a config

login
register
mail settings
Submitter Durham Goode
Date May 13, 2015, 3:13 p.m.
Message ID <1c775dc497a533542a23.1431530002@dev2000.prn2.facebook.com>
Download mbox | patch
Permalink /patch/9042/
State Changes Requested
Headers show

Comments

Durham Goode - May 13, 2015, 3:13 p.m.
# HG changeset patch
# User Durham Goode <durham@fb.com>
# Date 1431469591 25200
#      Tue May 12 15:26:31 2015 -0700
# Node ID 1c775dc497a533542a23382f68ce0c3710601f7a
# Parent  42bafc92b436181ba5d6568967577a214198648d
ignore: allow regex sub-ignores via a config

Normally we don't allow sub-ignores to have regex rules in them, since we can't
reliably build the correct regular expression to represent the prefixed rule.

Let's add a config option that allows a user to opt-in to regular expresion
sub-ignores if they're certain their rules can be composed in the correct
manner.

The alternative to this strategy is to redo the ignore matcher builder to be
a tree of matchers then manually trim the prefix and apply the sub-ignore
matcher. This could be expensive for repos with large hgignores in python, so I
choose to go with this limited-but-opt-in-able strategy for now.

Patch

diff --git a/mercurial/ignore.py b/mercurial/ignore.py
--- a/mercurial/ignore.py
+++ b/mercurial/ignore.py
@@ -77,9 +77,17 @@  def ignorepats(ui, root, filepath):
             # The ignore file is inside the repo, so make its patterns
             # relative to its location.
             if linesyntax == 'relre:':
-                message = _('cannot use sub-ignore files that use regular '
-                            'expressions')
-                raise util.Abort(message)
+                if ui.configbool('ui', 'allowregexsubignores'):
+                    if line[0] == '^':
+                        line = '^%s\/(?:%s)' % (re.escape(subdir), line[1:])
+                    else:
+                        line = '^%s\/.*(?:%s)' % (re.escape(subdir), line)
+                else:
+                    message = _('cannot use sub-ignore files that use regular '
+                                'expressions')
+                    hint = _('set ui.allowregexsubignores=True if you know '
+                             'your regexs can be wrapped as "^subdir\/(?:XXX)"')
+                    raise util.Abort(message, hint=hint)
             elif linesyntax == 'relglob:':
                 line = '%s/*%s' % (subdir, line)
         patterns.append(linesyntax + line)
diff --git a/tests/test-hgignore.t b/tests/test-hgignore.t
--- a/tests/test-hgignore.t
+++ b/tests/test-hgignore.t
@@ -189,12 +189,20 @@  Check including sub-ignores with regexs
   $ echo "regexp:f.le1" > dir1/.hgignore
   $ hg debugignore
   abort: cannot use sub-ignore files that use regular expressions
+  (set ui.allowregexsubignores=True if you know your regexs can be wrapped as "^subdir\/(?:XXX)")
   [255]
 
-  $ echo "" > dir1/.hgignore
+  $ cat >> .hg/hgrc <<EOF
+  > [ui]
+  > allowregexsubignores=True
+  > EOF
 
   $ hg debugignore
-  (?:(?:|.*/)dir2\/[^/]*file[^/]*2(?:/|$))
+  (?:^dir1\/.*(?:f.le1)|(?:|.*/)dir2\/[^/]*file[^/]*2(?:/|$))
+
+  $ hg status | grep -v hgignore
+  ? dir1/file2
+  ? dir2/file1
 
 Check multiple levels of sub-ignores
 
@@ -204,11 +212,9 @@  Check multiple levels of sub-ignores
   $ echo "glob:fil*3" >> dir1/subdir/.hgignore
 
   $ hg debugignore
-  (?:(?:|.*/)dir1\/subdir\/[^/]*fil[^/]*3(?:/|$)|(?:|.*/)dir2\/[^/]*file[^/]*2(?:/|$))
+  (?:^dir1\/.*(?:f.le1)|(?:|.*/)dir1\/subdir\/[^/]*fil[^/]*3(?:/|$)|(?:|.*/)dir2\/[^/]*file[^/]*2(?:/|$))
 
   $ hg status | grep -v hgignore
-  ? dir1/file1
   ? dir1/file2
-  ? dir1/subdir/subfile1
   ? dir1/subdir/subfile4
   ? dir2/file1