Patchwork [3,of,4] match: add 'include:' syntax

login
register
mail settings
Submitter Durham Goode
Date May 19, 2015, 12:23 a.m.
Message ID <b7160d16c7b38d38236b.1431995000@dev2000.prn2.facebook.com>
Download mbox | patch
Permalink /patch/9153/
State Accepted
Headers show

Comments

Durham Goode - May 19, 2015, 12:23 a.m.
# HG changeset patch
# User Durham Goode <durham@fb.com>
# Date 1431817012 25200
#      Sat May 16 15:56:52 2015 -0700
# Node ID b7160d16c7b38d38236bbfb2ec075909e361f515
# Parent  b629687156cd44334c09ce5e158038c21039b0fd
match: add 'include:' syntax

This allows the matcher to understand 'include:path/to/file' style rules.  The
files support the standard hgignore syntax and any rules read from the file are
included in the matcher without regard to the files location in the repository
(i.e. if the included file is in somedir/otherdir, all of it's rules will still
apply to the entire repository).

Patch

diff --git a/mercurial/match.py b/mercurial/match.py
--- a/mercurial/match.py
+++ b/mercurial/match.py
@@ -75,6 +75,7 @@  class match(object):
         'relpath:<path>' - a path relative to cwd
         'relre:<regexp>' - a regexp that needn't match the start of a name
         'set:<fileset>' - a fileset expression
+        'include:<path>' - a file of patterns to read and include
         '<something>' - a pattern of the specified default type
         """
 
@@ -232,6 +233,19 @@  class match(object):
                                                     auditor):
                     kindpats.append((k, p, pat))
                 continue
+            elif kind == 'include':
+                try:
+                    includepats = readpatternfile(pat, self._warn)
+                    for k, p, source in self._normalize(includepats, default,
+                                                        root, cwd, auditor):
+                        kindpats.append((k, p, source or pat))
+                except util.Abort, inst:
+                    raise util.Abort('%s: %s' % (pat, inst[0]))
+                except IOError, inst:
+                    if self._warn:
+                        self._warn(_("skipping unreadable pattern file "
+                                     "'%s': %s\n") % (pat, inst.strerror))
+                continue
             # else: re or relre - which cannot be normalized
             kindpats.append((kind, pat, ''))
         return kindpats
@@ -333,7 +347,7 @@  def _patsplit(pattern, default):
     if ':' in pattern:
         kind, pat = pattern.split(':', 1)
         if kind in ('re', 'glob', 'path', 'relglob', 'relpath', 'relre',
-                    'listfile', 'listfile0', 'set'):
+                    'listfile', 'listfile0', 'set', 'include'):
             return kind, pat
     return default, pattern
 
@@ -513,7 +527,8 @@  def readpatternfile(filepath, warn):
     '''parse a pattern file, returning a list of
     patterns. These patterns should be given to compile()
     to be validated and converted into a match function.'''
-    syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:'}
+    syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:',
+                'include': 'include'}
     syntax = 'relre:'
     patterns = []
 
diff --git a/tests/test-hgignore.t b/tests/test-hgignore.t
--- a/tests/test-hgignore.t
+++ b/tests/test-hgignore.t
@@ -167,3 +167,25 @@  Check recursive glob pattern matches no 
   ? a.c
   ? a.o
   ? syntax
+
+Check using 'include:' in ignore file
+
+  $ hg purge --all --config extensions.purge=
+  $ touch foo.included
+
+  $ echo ".*.included" > otherignore
+  $ hg status -I "include:otherignore"
+  ? foo.included
+
+  $ echo "include:otherignore" >> .hgignore
+  $ hg status
+  A dir/b.o
+  ? .hgignore
+  ? otherignore
+
+Check recursive uses of 'include:'
+
+  $ echo "include:nestedignore" >> otherignore
+  $ echo "glob:*ignore" > nestedignore
+  $ hg status
+  A dir/b.o