<div dir="ltr"><br><br><div class="gmail_quote">On Wed, May 20, 2015 at 3:01 PM Durham Goode <<a href="mailto:durham@fb.com">durham@fb.com</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"># HG changeset patch<br>
# User Durham Goode <<a href="mailto:durham@fb.com" target="_blank">durham@fb.com</a>><br>
# Date 1431818705 25200<br>
#      Sat May 16 16:25:05 2015 -0700<br>
# Node ID 3bbfdda372e8e4204a5440009bfbc9e81f2a93e9<br>
# Parent  28ac58249dbc906622e368357daadd4814f9c71c<br>
match: enable 'relinclude:' syntax<br>
<br>
This adds a new rule syntax that allows the user to include a pattern file, but<br>
only have those patterns match against files underneath the subdirectory of the<br>
pattern file.<br>
<br>
This is useful when you have nested projects in a repository and the inner<br>
projects wants to set up ignore rules that won't affect other projects in the<br>
repository. It is also useful in high commit rate repositories for removing the<br>
root .hgignore as a point of contention.<br>
<br>
diff --git a/mercurial/match.py b/mercurial/match.py<br>
--- a/mercurial/match.py<br>
+++ b/mercurial/match.py<br>
@@ -5,7 +5,7 @@<br>
 # This software may be used and distributed according to the terms of the<br>
 # GNU General Public License version 2 or any later version.<br>
<br>
-import re<br>
+import os, re<br>
 import util, pathutil<br>
 from i18n import _<br>
<br>
@@ -42,6 +42,25 @@ def _expandsets(kindpats, ctx, listsubre<br>
         other.append((kind, pat, source))<br>
     return fset, other<br>
<br>
+def _expandsubinclude(kindpats, root):<br>
+    '''Returns the list of subinclude matchers and the kindpats without the<br>
+    subincludes in it.'''<br>
+    relmatchers = []<br>
+    other = []<br>
+<br>
+    for kind, pat, source in kindpats:<br>
+        if kind == 'subinclude':<br>
+            sourceroot = os.path.dirname(source)<br>
+            path = os.path.join(sourceroot, pat)<br>
+            newroot = os.path.dirname(path)<br>
+            relmatcher = match(newroot, '', [], ['include:%s' % path])<br>
+            prefix = os.path.relpath(newroot, root) + '/'<br>
+            relmatchers.append((prefix, relmatcher))<br>
+        else:<br>
+            other.append((kind, pat, source))<br>
+<br>
+    return relmatchers, other<br>
+<br>
 def _kindpatsalwaysmatch(kindpats):<br>
     """"Checks whether the kindspats match everything, as e.g.<br>
     'relpath:.' does.<br>
@@ -76,6 +95,8 @@ class match(object):<br>
         'relre:<regexp>' - a regexp that needn't match the start of a name<br>
         'set:<fileset>' - a fileset expression<br>
         'include:<path>' - a file of patterns to read and include<br>
+        'subinclude:<path>' - a file of patterns to match against files under<br>
+                              the same directory<br>
         '<something>' - a pattern of the specified default type<br>
         """<br>
<br>
@@ -349,7 +370,7 @@ def _patsplit(pattern, default):<br>
     if ':' in pattern:<br>
         kind, pat = pattern.split(':', 1)<br>
         if kind in ('re', 'glob', 'path', 'relglob', 'relpath', 'relre',<br>
-                    'listfile', 'listfile0', 'set', 'include'):<br>
+                    'listfile', 'listfile0', 'set', 'include', 'subinclude'):<br>
             return kind, pat<br>
     return default, pattern<br>
<br>
@@ -455,6 +476,15 @@ def _buildmatch(ctx, kindpats, globsuffi<br>
     globsuffix is appended to the regexp of globs.'''<br>
     matchfuncs = []<br>
<br>
+    subincludes, kindpats = _expandsubinclude(kindpats, root)<br>
+    if subincludes:<br>
+        def matchsubinclude(f):<br>
+            for prefix, mf in subincludes:<br>
+                if f.startswith(prefix) and mf(f[len(prefix):]):<br>
+                    return True<br>
+            return False<br>
+        matchfuncs.append(matchsubinclude)<br>
+<br>
     fset, kindpats = _expandsets(kindpats, ctx, listsubrepos)<br>
     if fset:<br>
         matchfuncs.append(fset.__contains__)<br>
@@ -551,7 +581,7 @@ def readpatternfile(filepath, warn):<br>
     pattern        # pattern of the current default type'''<br>
<br>
     syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:',<br>
-                'include': 'include'}<br>
+                'include': 'include', 'subinclude': 'subinclude'}<br>
     syntax = 'relre:'<br>
     patterns = []<br>
<br>
diff --git a/tests/test-hgignore.t b/tests/test-hgignore.t<br>
--- a/tests/test-hgignore.t<br>
+++ b/tests/test-hgignore.t<br>
@@ -190,7 +190,45 @@ Check recursive uses of 'include:'<br>
   $ hg status<br>
   A dir/b.o<br>
<br>
+  $ cp otherignore goodignore<br>
   $ echo "include:badignore" >> otherignore<br>
   $ hg status<br>
   skipping unreadable pattern file 'badignore': No such file or directory<br>
   A dir/b.o<br>
+<br>
+  $ mv goodignore otherignore<br>
+<br>
+Check including subincludes<br></blockquote><div><br></div><div>Should we also have a test with "subinclude:foo" (i.e. in the current directory)?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+<br>
+  $ hg revert -q --all<br>
+  $ hg purge --all --config extensions.purge=<br>
+  $ echo ".hgignore" > .hgignore<br>
+  $ mkdir dir1 dir2<br>
+  $ touch dir1/file1 dir1/file2 dir2/file1 dir2/file2<br>
+  $ echo "subinclude:dir2/.hgignore" >> .hgignore<br>
+  $ echo "glob:file*2" > dir2/.hgignore<br>
+  $ hg status<br>
+  ? dir1/file1<br>
+  ? dir1/file2<br>
+  ? dir2/file1<br>
+<br>
+Check including subincludes with regexs<br>
+<br>
+  $ echo "subinclude:dir1/.hgignore" >> .hgignore<br>
+  $ echo "regexp:f.le1" > dir1/.hgignore<br>
+<br>
+  $ hg status<br>
+  ? dir1/file2<br>
+  ? dir2/file1<br>
+<br>
+Check multiple levels of sub-ignores<br>
+<br>
+  $ mkdir dir1/subdir<br>
+  $ touch dir1/subdir/subfile1 dir1/subdir/subfile3 dir1/subdir/subfile4<br>
+  $ echo "subinclude:subdir/.hgignore" >> dir1/.hgignore<br>
+  $ echo "glob:subfil*3" >> dir1/subdir/.hgignore<br>
+<br>
+  $ hg status<br>
+  ? dir1/file2<br>
+  ? dir1/subdir/subfile4<br>
+  ? dir2/file1<br>
_______________________________________________<br>
Mercurial-devel mailing list<br>
<a href="mailto:Mercurial-devel@selenic.com" target="_blank">Mercurial-devel@selenic.com</a><br>
<a href="http://selenic.com/mailman/listinfo/mercurial-devel" target="_blank">http://selenic.com/mailman/listinfo/mercurial-devel</a><br>
</blockquote></div></div>