--- a/mercurial/fileset.py Fri Jun 10 16:50:45 2011 +0200
+++ b/mercurial/fileset.py Wed Jun 08 13:44:41 2011 -0500
@@ -5,7 +5,7 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
-import parser, error
+import parser, error, match
from i18n import _
elements = {
@@ -27,6 +27,8 @@
keywords = set(['and', 'or', 'not'])
+globchars = ".*{}[]?/\\"
+
def tokenize(program):
pos, l = 0, len(program)
while pos < l:
@@ -56,13 +58,13 @@
pos += 1
else:
raise error.ParseError(_("unterminated string"), s)
- elif c.isalnum() or c in '.*{}[]?' or ord(c) > 127:
+ elif c.isalnum() or c in globchars or ord(c) > 127:
# gather up a symbol/keyword
s = pos
pos += 1
while pos < l: # find end of symbol
d = program[pos]
- if not (d.isalnum() or d in ".*{}[]?," or ord(d) > 127):
+ if not (d.isalnum() or d in globchars or ord(d) > 127):
break
pos += 1
sym = program[s:pos]
@@ -78,3 +80,63 @@
parse = parser.parser(tokenize, elements).parse
+def getstring(x, err):
+ if x and (x[0] == 'string' or x[0] == 'symbol'):
+ return x[1]
+ raise error.ParseError(err)
+
+def getset(mctx, x):
+ if not x:
+ raise error.ParseError(_("missing argument"))
+ return methods[x[0]](mctx, *x[1:])
+
+def stringset(mctx, x):
+ m = mctx.matcher([x])
+ return [f for f in mctx.subset if m(f)]
+
+def andset(mctx, x, y):
+ return getset(mctx.narrow(getset(mctx, x)), y)
+
+def orset(mctx, x, y):
+ # needs optimizing
+ xl = getset(mctx, x)
+ yl = getset(mctx, y)
+ return xl + [f for f in yl if f not in xl]
+
+def notset(mctx, x):
+ s = set(getset(mctx, x))
+ return [r for r in mctx.subset if r not in s]
+
+def listset(mctx, a, b):
+ raise error.ParseError(_("can't use a list in this context"))
+
+methods = {
+ 'string': stringset,
+ 'symbol': stringset,
+ 'and': andset,
+ 'or': orset,
+ 'list': listset,
+ 'group': getset,
+ 'not': notset
+}
+
+class matchctx(object):
+ def __init__(self, ctx, matchfn, subset=None):
+ self.ctx = ctx
+ self.matchfn = matchfn
+ self.subset = subset
+ if subset is None:
+ self.subset = ctx.walk(matchfn([])) # optimize this later
+ def matcher(self, pattern):
+ return self.matchfn(pattern)
+ def filter(self, files):
+ return [f for f in files if f in self.subset]
+ def narrow(self, files):
+ return matchctx(self.ctx, self.matchfn,
+ self.filter(files))
+
+def getfileset(ctx, matchfn, expr):
+ tree, pos = parse(expr)
+ if (pos != len(expr)):
+ raise error.ParseError("invalid token", pos)
+ return getset(matchctx(ctx, matchfn), tree)