match: introduce basic fileset support
authorMatt Mackall <mpm@selenic.com>
Sat, 18 Jun 2011 16:53:44 -0500
changeset 14675 cfc89398f710
parent 14674 1c151b963254
child 14676 e80fa502b8cf
match: introduce basic fileset support
mercurial/match.py
--- a/mercurial/match.py	Sat Jun 18 16:52:51 2011 -0500
+++ b/mercurial/match.py	Sat Jun 18 16:53:44 2011 -0500
@@ -6,9 +6,24 @@
 # GNU General Public License version 2 or any later version.
 
 import re
-import scmutil, util
+import scmutil, util, fileset
 from i18n import _
 
+def _expandsets(pats, ctx):
+    '''convert set: patterns into a list of files in the given context'''
+    fset = set()
+    other = []
+
+    for kind, expr in pats:
+        if kind == 'set':
+            if not ctx:
+                raise util.Abort("fileset expression with no context")
+            s = fileset.getfileset(ctx, expr)
+            fset.update(s)
+            continue
+        other.append((kind, expr))
+    return fset, other
+
 class match(object):
     def __init__(self, root, cwd, patterns, include=[], exclude=[],
                  default='glob', exact=False, auditor=None, ctx=None):
@@ -30,9 +45,11 @@
         'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs)
         '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
         '<something>' - a pattern of the specified default type
         """
 
+        self._ctx = None
         self._root = root
         self._cwd = cwd
         self._files = []
@@ -41,10 +58,10 @@
 
         if include:
             pats = _normalize(include, 'glob', root, cwd, auditor)
-            self.includepat, im = _buildmatch(pats, '(?:/|$)')
+            self.includepat, im = _buildmatch(ctx, pats, '(?:/|$)')
         if exclude:
             pats = _normalize(exclude, 'glob', root, cwd, auditor)
-            self.excludepat, em = _buildmatch(pats, '(?:/|$)')
+            self.excludepat, em = _buildmatch(ctx, pats, '(?:/|$)')
         if exact:
             self._files = patterns
             pm = self.exact
@@ -52,7 +69,7 @@
             pats = _normalize(patterns, default, root, cwd, auditor)
             self._files = _roots(pats)
             self._anypats = self._anypats or _anypats(pats)
-            self.patternspat, pm = _buildmatch(pats, '$')
+            self.patternspat, pm = _buildmatch(ctx, pats, '$')
 
         if patterns or exact:
             if include:
@@ -163,7 +180,7 @@
     if ':' in pat:
         kind, val = pat.split(':', 1)
         if kind in ('re', 'glob', 'path', 'relglob', 'relpath', 'relre',
-                    'listfile', 'listfile0'):
+                    'listfile', 'listfile0', 'set'):
             return kind, val
     return default, pat
 
@@ -241,7 +258,17 @@
         return '.*' + name
     return _globre(name) + tail
 
-def _buildmatch(pats, tail):
+def _buildmatch(ctx, pats, tail):
+    fset, pats = _expandsets(pats, ctx)
+    if not pats:
+        return "", fset.__contains__
+
+    pat, mf = _buildregexmatch(pats, tail)
+    if fset:
+        return pat, lambda f: f in fset or mf(f)
+    return pat, mf
+
+def _buildregexmatch(pats, tail):
     """build a matching function from a set of patterns"""
     try:
         pat = '(?:%s)' % '|'.join([_regex(k, p, tail) for (k, p) in pats])