--- a/mercurial/fileset.py Tue Jul 10 23:49:48 2018 +0900
+++ b/mercurial/fileset.py Sat Jun 09 19:55:10 2018 +0900
@@ -140,43 +140,41 @@
raise error.ParseError(err)
return l
-def getset(mctx, x):
+def getmatch(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 stringmatch(mctx, x):
+ return mctx.matcher([x])
-def kindpatset(mctx, x, y):
- return stringset(mctx, _getkindpat(x, y, matchmod.allpatternkinds,
- _("pattern must be a string")))
+def kindpatmatch(mctx, x, y):
+ return stringmatch(mctx, _getkindpat(x, y, matchmod.allpatternkinds,
+ _("pattern must be a string")))
-def andset(mctx, x, y):
- xl = set(getset(mctx, x))
- yl = getset(mctx, y)
- return [f for f in yl if f in xl]
+def andmatch(mctx, x, y):
+ xm = getmatch(mctx, x)
+ ym = getmatch(mctx, y)
+ return matchmod.intersectmatchers(xm, ym)
-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 ormatch(mctx, x, y):
+ xm = getmatch(mctx, x)
+ ym = getmatch(mctx, y)
+ return matchmod.unionmatcher([xm, ym])
-def notset(mctx, x):
- s = set(getset(mctx, x))
- return [r for r in mctx.subset if r not in s]
+def notmatch(mctx, x):
+ m = getmatch(mctx, x)
+ return mctx.predicate(lambda f: not m(f), predrepr=('<not %r>', m))
-def minusset(mctx, x, y):
- xl = getset(mctx, x)
- yl = set(getset(mctx, y))
- return [f for f in xl if f not in yl]
+def minusmatch(mctx, x, y):
+ xm = getmatch(mctx, x)
+ ym = getmatch(mctx, y)
+ return matchmod.differencematcher(xm, ym)
-def negateset(mctx, x):
+def negatematch(mctx, x):
raise error.ParseError(_("can't use negate operator in this context"))
-def listset(mctx, a, b):
+def listmatch(mctx, x, y):
raise error.ParseError(_("can't use a list in this context"),
hint=_('see hg help "filesets.x or y"'))
@@ -217,7 +215,7 @@
# i18n: "modified" is a keyword
getargs(x, 0, 0, _("modified takes no arguments"))
s = set(mctx.status().modified)
- return [f for f in mctx.subset if f in s]
+ return mctx.predicate(s.__contains__, predrepr='modified')
@predicate('added()', callstatus=True)
def added(mctx, x):
@@ -226,7 +224,7 @@
# i18n: "added" is a keyword
getargs(x, 0, 0, _("added takes no arguments"))
s = set(mctx.status().added)
- return [f for f in mctx.subset if f in s]
+ return mctx.predicate(s.__contains__, predrepr='added')
@predicate('removed()', callstatus=True)
def removed(mctx, x):
@@ -235,7 +233,7 @@
# i18n: "removed" is a keyword
getargs(x, 0, 0, _("removed takes no arguments"))
s = set(mctx.status().removed)
- return [f for f in mctx.subset if f in s]
+ return mctx.predicate(s.__contains__, predrepr='removed')
@predicate('deleted()', callstatus=True)
def deleted(mctx, x):
@@ -244,7 +242,7 @@
# i18n: "deleted" is a keyword
getargs(x, 0, 0, _("deleted takes no arguments"))
s = set(mctx.status().deleted)
- return [f for f in mctx.subset if f in s]
+ return mctx.predicate(s.__contains__, predrepr='deleted')
@predicate('missing()', callstatus=True)
def missing(mctx, x):
@@ -253,27 +251,23 @@
# i18n: "missing" is a keyword
getargs(x, 0, 0, _("missing takes no arguments"))
s = set(mctx.status().deleted)
- return [f for f in mctx.subset if f in s]
+ return mctx.predicate(s.__contains__, predrepr='deleted')
@predicate('unknown()', callstatus=True)
def unknown(mctx, x):
- """File that is unknown according to :hg:`status`. These files will only be
- considered if this predicate is used.
- """
+ """File that is unknown according to :hg:`status`."""
# i18n: "unknown" is a keyword
getargs(x, 0, 0, _("unknown takes no arguments"))
s = set(mctx.status().unknown)
- return [f for f in mctx.subset if f in s]
+ return mctx.predicate(s.__contains__, predrepr='unknown')
@predicate('ignored()', callstatus=True)
def ignored(mctx, x):
- """File that is ignored according to :hg:`status`. These files will only be
- considered if this predicate is used.
- """
+ """File that is ignored according to :hg:`status`."""
# i18n: "ignored" is a keyword
getargs(x, 0, 0, _("ignored takes no arguments"))
s = set(mctx.status().ignored)
- return [f for f in mctx.subset if f in s]
+ return mctx.predicate(s.__contains__, predrepr='ignored')
@predicate('clean()', callstatus=True)
def clean(mctx, x):
@@ -282,14 +276,14 @@
# i18n: "clean" is a keyword
getargs(x, 0, 0, _("clean takes no arguments"))
s = set(mctx.status().clean)
- return [f for f in mctx.subset if f in s]
+ return mctx.predicate(s.__contains__, predrepr='clean')
@predicate('tracked()')
def tracked(mctx, x):
"""File that is under Mercurial control."""
# i18n: "tracked" is a keyword
getargs(x, 0, 0, _("tracked takes no arguments"))
- return [f for f in mctx.subset if f in mctx.ctx]
+ return mctx.predicate(mctx.ctx.__contains__, predrepr='tracked')
@predicate('binary()', callexisting=True)
def binary(mctx, x):
@@ -297,7 +291,8 @@
"""
# i18n: "binary" is a keyword
getargs(x, 0, 0, _("binary takes no arguments"))
- return [f for f in mctx.existing() if mctx.ctx[f].isbinary()]
+ return mctx.fpredicate(lambda fctx: fctx.isbinary(),
+ predrepr='binary', cache=True)
@predicate('exec()', callexisting=True)
def exec_(mctx, x):
@@ -305,7 +300,8 @@
"""
# i18n: "exec" is a keyword
getargs(x, 0, 0, _("exec takes no arguments"))
- return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'x']
+ ctx = mctx.ctx
+ return mctx.predicate(lambda f: ctx.flags(f) == 'x', predrepr='exec')
@predicate('symlink()', callexisting=True)
def symlink(mctx, x):
@@ -313,7 +309,8 @@
"""
# i18n: "symlink" is a keyword
getargs(x, 0, 0, _("symlink takes no arguments"))
- return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'l']
+ ctx = mctx.ctx
+ return mctx.predicate(lambda f: ctx.flags(f) == 'l', predrepr='symlink')
@predicate('resolved()')
def resolved(mctx, x):
@@ -322,9 +319,10 @@
# i18n: "resolved" is a keyword
getargs(x, 0, 0, _("resolved takes no arguments"))
if mctx.ctx.rev() is not None:
- return []
+ return mctx.never()
ms = merge.mergestate.read(mctx.ctx.repo())
- return [f for f in mctx.subset if f in ms and ms[f] == 'r']
+ return mctx.predicate(lambda f: f in ms and ms[f] == 'r',
+ predrepr='resolved')
@predicate('unresolved()')
def unresolved(mctx, x):
@@ -333,9 +331,10 @@
# i18n: "unresolved" is a keyword
getargs(x, 0, 0, _("unresolved takes no arguments"))
if mctx.ctx.rev() is not None:
- return []
+ return mctx.never()
ms = merge.mergestate.read(mctx.ctx.repo())
- return [f for f in mctx.subset if f in ms and ms[f] == 'u']
+ return mctx.predicate(lambda f: f in ms and ms[f] == 'u',
+ predrepr='unresolved')
@predicate('hgignore()')
def hgignore(mctx, x):
@@ -343,8 +342,7 @@
"""
# i18n: "hgignore" is a keyword
getargs(x, 0, 0, _("hgignore takes no arguments"))
- ignore = mctx.ctx.repo().dirstate._ignore
- return [f for f in mctx.subset if ignore(f)]
+ return mctx.ctx.repo().dirstate._ignore
@predicate('portable()')
def portable(mctx, x):
@@ -353,8 +351,8 @@
"""
# i18n: "portable" is a keyword
getargs(x, 0, 0, _("portable takes no arguments"))
- checkwinfilename = util.checkwinfilename
- return [f for f in mctx.subset if checkwinfilename(f) is None]
+ return mctx.predicate(lambda f: util.checkwinfilename(f) is None,
+ predrepr='portable')
@predicate('grep(regex)', callexisting=True)
def grep(mctx, x):
@@ -366,7 +364,8 @@
except re.error as e:
raise error.ParseError(_('invalid match pattern: %s') %
stringutil.forcebytestr(e))
- return [f for f in mctx.existing() if r.search(mctx.ctx[f].data())]
+ return mctx.fpredicate(lambda fctx: r.search(fctx.data()),
+ predrepr=('grep(%r)', r.pattern), cache=True)
def _sizetomax(s):
try:
@@ -421,7 +420,8 @@
# i18n: "size" is a keyword
expr = getstring(x, _("size requires an expression"))
m = sizematcher(expr)
- return [f for f in mctx.existing() if m(mctx.ctx[f].size())]
+ return mctx.fpredicate(lambda fctx: m(fctx.size()),
+ predrepr=('size(%r)', expr), cache=True)
@predicate('encoding(name)', callexisting=True)
def encoding(mctx, x):
@@ -433,18 +433,17 @@
# i18n: "encoding" is a keyword
enc = getstring(x, _("encoding requires an encoding name"))
- s = []
- for f in mctx.existing():
- d = mctx.ctx[f].data()
+ def encp(fctx):
+ d = fctx.data()
try:
d.decode(pycompat.sysstr(enc))
+ return True
except LookupError:
raise error.Abort(_("unknown encoding '%s'") % enc)
except UnicodeDecodeError:
- continue
- s.append(f)
+ return False
- return s
+ return mctx.fpredicate(encp, predrepr=('encoding(%r)', enc), cache=True)
@predicate('eol(style)', callexisting=True)
def eol(mctx, x):
@@ -456,19 +455,18 @@
# i18n: "eol" is a keyword
enc = getstring(x, _("eol requires a style name"))
- s = []
- for f in mctx.existing():
- fctx = mctx.ctx[f]
+ def eolp(fctx):
if fctx.isbinary():
- continue
+ return False
d = fctx.data()
if (enc == 'dos' or enc == 'win') and '\r\n' in d:
- s.append(f)
+ return True
elif enc == 'unix' and re.search('(?<!\r)\n', d):
- s.append(f)
+ return True
elif enc == 'mac' and re.search('\r(?!\n)', d):
- s.append(f)
- return s
+ return True
+ return False
+ return mctx.fpredicate(eolp, predrepr=('eol(%r)', enc), cache=True)
@predicate('copied()')
def copied(mctx, x):
@@ -476,13 +474,10 @@
"""
# i18n: "copied" is a keyword
getargs(x, 0, 0, _("copied takes no arguments"))
- s = []
- for f in mctx.subset:
- if f in mctx.ctx:
- p = mctx.ctx[f].parents()
- if p and p[0].path() != f:
- s.append(f)
- return s
+ def copiedp(fctx):
+ p = fctx.parents()
+ return p and p[0].path() != fctx.path()
+ return mctx.fpredicate(copiedp, predrepr='copied', cache=True)
@predicate('revs(revs, pattern)')
def revs(mctx, x):
@@ -496,15 +491,15 @@
repo = mctx.ctx.repo()
revs = scmutil.revrange(repo, [revspec])
- found = set()
- result = []
+ matchers = []
for r in revs:
ctx = repo[r]
- for f in getset(mctx.switch(ctx, _buildstatus(ctx, x)), x):
- if f not in found:
- found.add(f)
- result.append(f)
- return result
+ matchers.append(getmatch(mctx.switch(ctx, _buildstatus(ctx, x)), x))
+ if not matchers:
+ return mctx.never()
+ if len(matchers) == 1:
+ return matchers[0]
+ return matchmod.unionmatcher(matchers)
@predicate('status(base, rev, pattern)')
def status(mctx, x):
@@ -526,7 +521,7 @@
if not revspec:
raise error.ParseError(reverr)
basectx, ctx = scmutil.revpair(repo, [baserevspec, revspec])
- return getset(mctx.switch(ctx, _buildstatus(ctx, x, basectx=basectx)), x)
+ return getmatch(mctx.switch(ctx, _buildstatus(ctx, x, basectx=basectx)), x)
@predicate('subrepo([pattern])')
def subrepo(mctx, x):
@@ -535,7 +530,7 @@
# i18n: "subrepo" is a keyword
getargs(x, 0, 1, _("subrepo takes at most one argument"))
ctx = mctx.ctx
- sstate = sorted(ctx.substate)
+ sstate = ctx.substate
if x:
pat = getpattern(x, matchmod.allpatternkinds,
# i18n: "subrepo" is a keyword
@@ -546,21 +541,22 @@
return (s == pat)
else:
m = matchmod.match(ctx.repo().root, '', [pat], ctx=ctx)
- return [sub for sub in sstate if m(sub)]
+ return mctx.predicate(lambda f: f in sstate and m(f),
+ predrepr=('subrepo(%r)', pat))
else:
- return [sub for sub in sstate]
+ return mctx.predicate(sstate.__contains__, predrepr='subrepo')
methods = {
- 'string': stringset,
- 'symbol': stringset,
- 'kindpat': kindpatset,
- 'and': andset,
- 'or': orset,
- 'minus': minusset,
- 'negate': negateset,
- 'list': listset,
- 'group': getset,
- 'not': notset,
+ 'string': stringmatch,
+ 'symbol': stringmatch,
+ 'kindpat': kindpatmatch,
+ 'and': andmatch,
+ 'or': ormatch,
+ 'minus': minusmatch,
+ 'negate': negatematch,
+ 'list': listmatch,
+ 'group': getmatch,
+ 'not': notmatch,
'func': func,
}
@@ -680,12 +676,9 @@
def match(ctx, expr, badfn=None):
"""Create a matcher for a single fileset expression"""
- repo = ctx.repo()
tree = parse(expr)
- fset = getset(fullmatchctx(ctx, _buildstatus(ctx, tree), badfn=badfn), tree)
- return matchmod.predicatematcher(repo.root, repo.getcwd(),
- fset.__contains__,
- predrepr='fileset', badfn=badfn)
+ mctx = fullmatchctx(ctx, _buildstatus(ctx, tree), badfn=badfn)
+ return getmatch(mctx, tree)
def _buildstatus(ctx, tree, basectx=None):
# do we need status info?