##// END OF EJS Templates
perf: import newer modules separately for earlier Mercurial...
perf: import newer modules separately for earlier Mercurial demandimport of early Mercurial loads an imported module immediately, if a module is imported absolutely by "from a import b" style. Recent perf.py satisfies this condition, because it does: - have "from __future__ import absolute_import" line - use "from a import b" style for modules in "mercurial" package Before this patch, importing modules below prevents perf.py from being loaded by earlier Mercurial, because these aren't available in such Mercurial, even though there are some code paths for Mercurial earlier than 1.9. - branchmap 2.5 (or bcee63733aad) - repoview 2.5 (or 3a6ddacb7198) - obsolete 2.3 (or ad0d6c2b3279) - scmutil 1.9 (or 8b252e826c68) For example, setting "_prereadsize" attribute in perfindex() and perfnodelookup() is effective only with Mercurial earlier than 1.8 (or 61c9bc3da402). After this patch, "mercurial.error" is the only blocker in "from mercurial import" statement for loading perf.py with Mercurial earlier than 1.2. This patch ignores it, because just importing it separately isn't enough.

File last commit:

r28448:7108834c default
r29567:7e2b3894 default
Show More
fileset.py
551 lines | 16.7 KiB | text/x-python | PythonLexer
Matt Mackall
filesets: introduce basic fileset expression parser
r14511 # fileset.py - file set queries for mercurial
#
# Copyright 2010 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
Gregory Szorc
fileset: use absolute_import
r25938 from __future__ import absolute_import
Augie Fackler
cleanup: move stdlib imports to their own import statement...
r20034 import re
Gregory Szorc
fileset: use absolute_import
r25938
from .i18n import _
from . import (
error,
merge,
parser,
FUJIWARA Katsunori
fileset: replace predicate by filesetpredicate of registrar (API)...
r28448 registrar,
Gregory Szorc
fileset: use absolute_import
r25938 util,
)
Matt Mackall
filesets: introduce basic fileset expression parser
r14511
elements = {
Yuya Nishihara
parser: separate actions for primary expression and prefix operator...
r25815 # token-type: binding-strength, primary, prefix, infix, suffix
"(": (20, None, ("group", 1, ")"), ("func", 1, ")"), None),
"-": (5, None, ("negate", 19), ("minus", 5), None),
"not": (10, None, ("not", 10), None, None),
"!": (10, None, ("not", 10), None, None),
"and": (5, None, None, ("and", 5), None),
"&": (5, None, None, ("and", 5), None),
"or": (4, None, None, ("or", 4), None),
"|": (4, None, None, ("or", 4), None),
"+": (4, None, None, ("or", 4), None),
",": (2, None, None, ("list", 2), None),
")": (0, None, None, None, None),
"symbol": (0, "symbol", None, None, None),
"string": (0, "string", None, None, None),
"end": (0, None, None, None, None),
Matt Mackall
filesets: introduce basic fileset expression parser
r14511 }
keywords = set(['and', 'or', 'not'])
Matt Mackall
fileset: handle underbar in symbols...
r19470 globchars = ".*{}[]?/\\_"
Matt Mackall
fileset: basic pattern and boolean support...
r14551
Matt Mackall
filesets: introduce basic fileset expression parser
r14511 def tokenize(program):
pos, l = 0, len(program)
while pos < l:
c = program[pos]
if c.isspace(): # skip inter-token whitespace
pass
elif c in "(),-|&+!": # handle simple operators
yield (c, None, pos)
elif (c in '"\'' or c == 'r' and
program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
if c == 'r':
pos += 1
c = program[pos]
decode = lambda x: x
else:
Yuya Nishihara
fileset: handle error of string unescaping
r26233 decode = parser.unescapestr
Matt Mackall
filesets: introduce basic fileset expression parser
r14511 pos += 1
s = pos
while pos < l: # find closing quote
d = program[pos]
if d == '\\': # skip over escaped characters
pos += 2
continue
if d == c:
yield ('string', decode(program[s:pos]), s)
break
pos += 1
else:
raise error.ParseError(_("unterminated string"), s)
Matt Mackall
fileset: basic pattern and boolean support...
r14551 elif c.isalnum() or c in globchars or ord(c) > 127:
Matt Mackall
fileset: fix long line
r14513 # gather up a symbol/keyword
Matt Mackall
filesets: introduce basic fileset expression parser
r14511 s = pos
pos += 1
while pos < l: # find end of symbol
d = program[pos]
Matt Mackall
fileset: basic pattern and boolean support...
r14551 if not (d.isalnum() or d in globchars or ord(d) > 127):
Matt Mackall
filesets: introduce basic fileset expression parser
r14511 break
pos += 1
sym = program[s:pos]
if sym in keywords: # operator keywords
yield (sym, None, s)
else:
yield ('symbol', sym, s)
pos -= 1
else:
raise error.ParseError(_("syntax error"), pos)
pos += 1
yield ('end', None, pos)
Yuya Nishihara
fileset, revset: do not use global parser object for thread safety...
r20208 def parse(expr):
Yuya Nishihara
parser: accept iterator of tokens instead of tokenizer function and program...
r25654 p = parser.parser(elements)
tree, pos = p.parse(tokenize(expr))
Yuya Nishihara
fileset: move validation of incomplete parsing to parse() function...
r25252 if pos != len(expr):
raise error.ParseError(_("invalid token"), pos)
return tree
Matt Mackall
filesets: introduce basic fileset expression parser
r14511
Matt Mackall
fileset: basic pattern and boolean support...
r14551 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]
Patrick Mezard
fileset: actually implement 'minusset'...
r17363 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]
Matt Mackall
fileset: basic pattern and boolean support...
r14551 def listset(mctx, a, b):
timeless
fileset: add hint for list error to use or
r27518 raise error.ParseError(_("can't use a list in this context"),
hint=_('see hg help "filesets.x or y"'))
Matt Mackall
fileset: basic pattern and boolean support...
r14551
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 # symbols are callable like:
# fun(mctx, x)
# with:
# mctx - current matchctx instance
# x - argument in tree form
symbols = {}
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "status caller"...
r27461 # filesets using matchctx.status()
FUJIWARA Katsunori
fileset: use set instead of list to mark predicates for efficiency (API)...
r27463 _statuscallers = set()
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "status caller"...
r27461
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "existing caller"...
r27462 # filesets using matchctx.existing()
FUJIWARA Katsunori
fileset: use set instead of list to mark predicates for efficiency (API)...
r27463 _existingcallers = set()
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "existing caller"...
r27462
FUJIWARA Katsunori
fileset: replace predicate by filesetpredicate of registrar (API)...
r28448 predicate = registrar.filesetpredicate()
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "status caller"...
r27461 @predicate('modified()', callstatus=True)
Matt Mackall
fileset: add support for file status predicates...
r14677 def modified(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File that is modified according to :hg:`status`.
Matt Mackall
fileset: add some function help text
r14681 """
Wagner Bruna
fileset: add i18n hints for keywords
r14785 # i18n: "modified" is a keyword
Matt Mackall
fileset: add support for file status predicates...
r14677 getargs(x, 0, 0, _("modified takes no arguments"))
Martin von Zweigbergk
fileset: access status fields by name rather than index
r22924 s = mctx.status().modified
Matt Mackall
fileset: add support for file status predicates...
r14677 return [f for f in mctx.subset if f in s]
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "status caller"...
r27461 @predicate('added()', callstatus=True)
Matt Mackall
fileset: add support for file status predicates...
r14677 def added(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File that is added according to :hg:`status`.
Matt Mackall
fileset: add some function help text
r14681 """
Wagner Bruna
fileset: add i18n hints for keywords
r14785 # i18n: "added" is a keyword
Matt Mackall
fileset: add support for file status predicates...
r14677 getargs(x, 0, 0, _("added takes no arguments"))
Martin von Zweigbergk
fileset: access status fields by name rather than index
r22924 s = mctx.status().added
Matt Mackall
fileset: add support for file status predicates...
r14677 return [f for f in mctx.subset if f in s]
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "status caller"...
r27461 @predicate('removed()', callstatus=True)
Matt Mackall
fileset: add support for file status predicates...
r14677 def removed(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File that is removed according to :hg:`status`.
Matt Mackall
fileset: add some function help text
r14681 """
Wagner Bruna
fileset: add i18n hints for keywords
r14785 # i18n: "removed" is a keyword
Matt Mackall
fileset: add support for file status predicates...
r14677 getargs(x, 0, 0, _("removed takes no arguments"))
Martin von Zweigbergk
fileset: access status fields by name rather than index
r22924 s = mctx.status().removed
Matt Mackall
fileset: add support for file status predicates...
r14677 return [f for f in mctx.subset if f in s]
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "status caller"...
r27461 @predicate('deleted()', callstatus=True)
Matt Mackall
fileset: add support for file status predicates...
r14677 def deleted(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """Alias for ``missing()``.
Matt Mackall
fileset: add some function help text
r14681 """
Wagner Bruna
fileset: add i18n hints for keywords
r14785 # i18n: "deleted" is a keyword
Matt Mackall
fileset: add support for file status predicates...
r14677 getargs(x, 0, 0, _("deleted takes no arguments"))
Martin von Zweigbergk
fileset: access status fields by name rather than index
r22924 s = mctx.status().deleted
Matt Mackall
fileset: add support for file status predicates...
r14677 return [f for f in mctx.subset if f in s]
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "status caller"...
r27461 @predicate('missing()', callstatus=True)
liscju
fileset: add missing() predicate (issue4925)...
r27024 def missing(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File that is missing according to :hg:`status`.
liscju
fileset: add missing() predicate (issue4925)...
r27024 """
# i18n: "missing" is a keyword
getargs(x, 0, 0, _("missing takes no arguments"))
s = mctx.status().deleted
return [f for f in mctx.subset if f in s]
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "status caller"...
r27461 @predicate('unknown()', callstatus=True)
Matt Mackall
fileset: add support for file status predicates...
r14677 def unknown(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File that is unknown according to :hg:`status`. These files will only be
Matt Mackall
fileset: add some function help text
r14681 considered if this predicate is used.
"""
Wagner Bruna
fileset: add i18n hints for keywords
r14785 # i18n: "unknown" is a keyword
Matt Mackall
fileset: add support for file status predicates...
r14677 getargs(x, 0, 0, _("unknown takes no arguments"))
Martin von Zweigbergk
fileset: access status fields by name rather than index
r22924 s = mctx.status().unknown
Matt Mackall
fileset: add support for file status predicates...
r14677 return [f for f in mctx.subset if f in s]
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "status caller"...
r27461 @predicate('ignored()', callstatus=True)
Matt Mackall
fileset: add support for file status predicates...
r14677 def ignored(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File that is ignored according to :hg:`status`. These files will only be
Matt Mackall
fileset: add some function help text
r14681 considered if this predicate is used.
"""
Wagner Bruna
fileset: add i18n hints for keywords
r14785 # i18n: "ignored" is a keyword
Matt Mackall
fileset: add support for file status predicates...
r14677 getargs(x, 0, 0, _("ignored takes no arguments"))
Martin von Zweigbergk
fileset: access status fields by name rather than index
r22924 s = mctx.status().ignored
Matt Mackall
fileset: add support for file status predicates...
r14677 return [f for f in mctx.subset if f in s]
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "status caller"...
r27461 @predicate('clean()', callstatus=True)
Matt Mackall
fileset: add support for file status predicates...
r14677 def clean(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File that is clean according to :hg:`status`.
Matt Mackall
fileset: add some function help text
r14681 """
Wagner Bruna
fileset: add i18n hints for keywords
r14785 # i18n: "clean" is a keyword
Matt Mackall
fileset: add support for file status predicates...
r14677 getargs(x, 0, 0, _("clean takes no arguments"))
Martin von Zweigbergk
fileset: access status fields by name rather than index
r22924 s = mctx.status().clean
Matt Mackall
fileset: add support for file status predicates...
r14677 return [f for f in mctx.subset if f in s]
Matt Mackall
fileset: add some basic predicates
r14676 def func(mctx, a, b):
if a[0] == 'symbol' and a[1] in symbols:
FUJIWARA Katsunori
fileset: detect unintentional existing() invocation at runtime...
r27464 funcname = a[1]
enabled = mctx._existingenabled
mctx._existingenabled = funcname in _existingcallers
try:
return symbols[funcname](mctx, b)
finally:
mctx._existingenabled = enabled
Matt Harbison
fileset: don't suggest private or undocumented queries...
r25633
keep = lambda fn: getattr(fn, '__doc__', None) is not None
syms = [s for (s, fn) in symbols.items() if keep(fn)]
raise error.UnknownIdentifier(a[1], syms)
Matt Mackall
fileset: add some basic predicates
r14676
def getlist(x):
if not x:
return []
if x[0] == 'list':
return getlist(x[1]) + [x[2]]
return [x]
def getargs(x, min, max, err):
l = getlist(x)
if len(l) < min or len(l) > max:
raise error.ParseError(err)
return l
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "existing caller"...
r27462 @predicate('binary()', callexisting=True)
Matt Mackall
fileset: add some basic predicates
r14676 def binary(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File that appears to be binary (contains NUL bytes).
Matt Mackall
fileset: add some function help text
r14681 """
Wagner Bruna
fileset: add i18n hints for keywords
r14785 # i18n: "binary" is a keyword
Matt Mackall
fileset: add some basic predicates
r14676 getargs(x, 0, 0, _("binary takes no arguments"))
Matt Mackall
fileset: don't attempt to check data predicates against removed files
r15963 return [f for f in mctx.existing() if util.binary(mctx.ctx[f].data())]
Matt Mackall
fileset: add some basic predicates
r14676
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "existing caller"...
r27462 @predicate('exec()', callexisting=True)
Matt Mackall
fileset: add some basic predicates
r14676 def exec_(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File that is marked as executable.
Matt Mackall
fileset: add some function help text
r14681 """
Wagner Bruna
fileset: add i18n hints for keywords
r14785 # i18n: "exec" is a keyword
Matt Mackall
fileset: add some basic predicates
r14676 getargs(x, 0, 0, _("exec takes no arguments"))
Matt Mackall
fileset: don't attempt to check data predicates against removed files
r15963 return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'x']
Matt Mackall
fileset: add some basic predicates
r14676
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "existing caller"...
r27462 @predicate('symlink()', callexisting=True)
Matt Mackall
fileset: add some basic predicates
r14676 def symlink(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File that is marked as a symlink.
Matt Mackall
fileset: add some function help text
r14681 """
Wagner Bruna
fileset: add i18n hints for keywords
r14785 # i18n: "symlink" is a keyword
Matt Mackall
fileset: add some basic predicates
r14676 getargs(x, 0, 0, _("symlink takes no arguments"))
Matt Mackall
fileset: don't attempt to check data predicates against removed files
r15963 return [f for f in mctx.existing() if mctx.ctx.flags(f) == 'l']
Matt Mackall
fileset: add some basic predicates
r14676
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 @predicate('resolved()')
Matt Mackall
fileset: add resolved and unresolved predicates
r14679 def resolved(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File that is marked resolved according to :hg:`resolve -l`.
Matt Mackall
fileset: add some function help text
r14681 """
Wagner Bruna
fileset: add i18n hints for keywords
r14785 # i18n: "resolved" is a keyword
Matt Mackall
fileset: add resolved and unresolved predicates
r14679 getargs(x, 0, 0, _("resolved takes no arguments"))
if mctx.ctx.rev() is not None:
return []
Siddharth Agarwal
fileset: switch to mergestate.read()...
r26995 ms = merge.mergestate.read(mctx.ctx.repo())
Matt Mackall
fileset: add resolved and unresolved predicates
r14679 return [f for f in mctx.subset if f in ms and ms[f] == 'r']
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 @predicate('unresolved()')
Matt Mackall
fileset: add resolved and unresolved predicates
r14679 def unresolved(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File that is marked unresolved according to :hg:`resolve -l`.
Matt Mackall
fileset: add some function help text
r14681 """
Wagner Bruna
fileset: add i18n hints for keywords
r14785 # i18n: "unresolved" is a keyword
Matt Mackall
fileset: add resolved and unresolved predicates
r14679 getargs(x, 0, 0, _("unresolved takes no arguments"))
if mctx.ctx.rev() is not None:
return []
Siddharth Agarwal
fileset: switch to mergestate.read()...
r26995 ms = merge.mergestate.read(mctx.ctx.repo())
Matt Mackall
fileset: add resolved and unresolved predicates
r14679 return [f for f in mctx.subset if f in ms and ms[f] == 'u']
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 @predicate('hgignore()')
Matt Mackall
fileset: add hgignore
r14680 def hgignore(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File that matches the active .hgignore pattern.
Matt Mackall
fileset: add some function help text
r14681 """
FUJIWARA Katsunori
i18n: add i18n comment to error messages of filesets predicates
r23113 # i18n: "hgignore" is a keyword
Matt Mackall
fileset: add hgignore
r14680 getargs(x, 0, 0, _("hgignore takes no arguments"))
Matt Harbison
fileset: replace 'ctx._repo' with 'ctx.repo()'
r24334 ignore = mctx.ctx.repo().dirstate._ignore
Matt Mackall
fileset: add hgignore
r14680 return [f for f in mctx.subset if ignore(f)]
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 @predicate('portable()')
Siddharth Agarwal
fileset: add a fileset for portable filenames...
r24408 def portable(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File that has a portable name. (This doesn't include filenames with case
Siddharth Agarwal
fileset: add a fileset for portable filenames...
r24408 collisions.)
"""
# 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]
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "existing caller"...
r27462 @predicate('grep(regex)', callexisting=True)
Matt Mackall
fileset: add grep predicate
r14682 def grep(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File contains the given regular expression.
Matt Mackall
fileset: add grep predicate
r14682 """
Patrick Mezard
fileset: do not traceback on invalid grep pattern
r17368 try:
# i18n: "grep" is a keyword
r = re.compile(getstring(x, _("grep requires a pattern")))
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except re.error as e:
Patrick Mezard
fileset: do not traceback on invalid grep pattern
r17368 raise error.ParseError(_('invalid match pattern: %s') % e)
Matt Mackall
fileset: don't attempt to check data predicates against removed files
r15963 return [f for f in mctx.existing() if r.search(mctx.ctx[f].data())]
Matt Mackall
fileset: add grep predicate
r14682
Matt Mackall
fileset: add size() predicate
r14683 def _sizetomax(s):
try:
av6
filesets: ignore unit case in size() predicate for single value...
r25925 s = s.strip().lower()
Bryan O'Sullivan
util: migrate fileset._sizetoint to util.sizetoint...
r19194 for k, v in util._sizeunits:
Matt Mackall
fileset: add size() predicate
r14683 if s.endswith(k):
# max(4k) = 5k - 1, max(4.5k) = 4.6k - 1
n = s[:-len(k)]
inc = 1.0
if "." in n:
inc /= 10 ** len(n.split(".")[1])
return int((float(n) + inc) * v) - 1
# no extension, this is a precise value
return int(s)
except ValueError:
Mads Kiilerich
fileset: use ParseError pos field correctly...
r14716 raise error.ParseError(_("couldn't parse size: %s") % s)
Matt Mackall
fileset: add size() predicate
r14683
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "existing caller"...
r27462 @predicate('size(expression)', callexisting=True)
Matt Mackall
fileset: add size() predicate
r14683 def size(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File size matches the given expression. Examples:
Matt Mackall
fileset: add size() predicate
r14683
- 1k (files from 1024 to 2047 bytes)
- < 20k (files less than 20480 bytes)
Matt Mackall
fileset: drop backwards SI size units...
r14689 - >= .5MB (files at least 524288 bytes)
Matt Mackall
fileset: add size() predicate
r14683 - 4k - 1MB (files from 4096 bytes to 1048576 bytes)
"""
Wagner Bruna
fileset: add i18n hints for keywords
r14785 # i18n: "size" is a keyword
Mads Kiilerich
revset and fileset: fix typos in parser error messages
r14717 expr = getstring(x, _("size requires an expression")).strip()
Matt Mackall
fileset: add size() predicate
r14683 if '-' in expr: # do we have a range?
a, b = expr.split('-', 1)
Bryan O'Sullivan
util: migrate fileset._sizetoint to util.sizetoint...
r19194 a = util.sizetoint(a)
b = util.sizetoint(b)
Matt Mackall
fileset: add size() predicate
r14683 m = lambda x: x >= a and x <= b
elif expr.startswith("<="):
Bryan O'Sullivan
util: migrate fileset._sizetoint to util.sizetoint...
r19194 a = util.sizetoint(expr[2:])
Matt Mackall
fileset: add size() predicate
r14683 m = lambda x: x <= a
elif expr.startswith("<"):
Bryan O'Sullivan
util: migrate fileset._sizetoint to util.sizetoint...
r19194 a = util.sizetoint(expr[1:])
Matt Mackall
fileset: add size() predicate
r14683 m = lambda x: x < a
elif expr.startswith(">="):
Bryan O'Sullivan
util: migrate fileset._sizetoint to util.sizetoint...
r19194 a = util.sizetoint(expr[2:])
Matt Mackall
fileset: add size() predicate
r14683 m = lambda x: x >= a
elif expr.startswith(">"):
Bryan O'Sullivan
util: migrate fileset._sizetoint to util.sizetoint...
r19194 a = util.sizetoint(expr[1:])
Matt Mackall
fileset: add size() predicate
r14683 m = lambda x: x > a
elif expr[0].isdigit or expr[0] == '.':
Bryan O'Sullivan
util: migrate fileset._sizetoint to util.sizetoint...
r19194 a = util.sizetoint(expr)
Matt Mackall
fileset: add size() predicate
r14683 b = _sizetomax(expr)
Thomas Arendsen Hein
fileset: add missing whitespace around operator
r14690 m = lambda x: x >= a and x <= b
Matt Mackall
fileset: add size() predicate
r14683 else:
Mads Kiilerich
fileset: use ParseError pos field correctly...
r14716 raise error.ParseError(_("couldn't parse size: %s") % expr)
Matt Mackall
fileset: add size() predicate
r14683
Matt Mackall
fileset: don't attempt to check data predicates against removed files
r15963 return [f for f in mctx.existing() if m(mctx.ctx[f].size())]
Matt Mackall
fileset: add size() predicate
r14683
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "existing caller"...
r27462 @predicate('encoding(name)', callexisting=True)
Matt Mackall
fileset: add encoding() predicate
r14684 def encoding(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File can be successfully decoded with the given character
Matt Mackall
fileset: add encoding() predicate
r14684 encoding. May not be useful for encodings other than ASCII and
UTF-8.
"""
Wagner Bruna
fileset: add i18n hints for keywords
r14785 # i18n: "encoding" is a keyword
Matt Mackall
fileset: add encoding() predicate
r14684 enc = getstring(x, _("encoding requires an encoding name"))
s = []
Matt Mackall
fileset: don't attempt to check data predicates against removed files
r15963 for f in mctx.existing():
Matt Mackall
fileset: add encoding() predicate
r14684 d = mctx.ctx[f].data()
try:
d.decode(enc)
except LookupError:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("unknown encoding '%s'") % enc)
Matt Mackall
fileset: add encoding() predicate
r14684 except UnicodeDecodeError:
continue
s.append(f)
return s
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "existing caller"...
r27462 @predicate('eol(style)', callexisting=True)
Matt Mackall
filesets: add eol predicate
r18842 def eol(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File contains newlines of the given style (dos, unix, mac). Binary
Matt Mackall
filesets: add eol predicate
r18842 files are excluded, files with mixed line endings match multiple
styles.
"""
Matt Harbison
fileset: fix copy/paste in eol() error message
r28056 # i18n: "eol" is a keyword
enc = getstring(x, _("eol requires a style name"))
Matt Mackall
filesets: add eol predicate
r18842
s = []
for f in mctx.existing():
d = mctx.ctx[f].data()
if util.binary(d):
continue
if (enc == 'dos' or enc == 'win') and '\r\n' in d:
s.append(f)
elif enc == 'unix' and re.search('(?<!\r)\n', d):
s.append(f)
elif enc == 'mac' and re.search('\r(?!\n)', d):
s.append(f)
return s
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 @predicate('copied()')
Matt Mackall
fileset: add copied predicate
r14685 def copied(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """File that is recorded as being copied.
Matt Mackall
fileset: add copied predicate
r14685 """
Wagner Bruna
fileset: add i18n hints for keywords
r14785 # i18n: "copied" is a keyword
Mads Kiilerich
fileset: copied takes no arguments
r14718 getargs(x, 0, 0, _("copied takes no arguments"))
Matt Mackall
fileset: add copied predicate
r14685 s = []
for f in mctx.subset:
p = mctx.ctx[f].parents()
if p and p[0].path() != f:
s.append(f)
return s
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 @predicate('subrepo([pattern])')
Angel Ezquerra
fileset: add "subrepo" fileset symbol...
r16443 def subrepo(mctx, x):
FUJIWARA Katsunori
fileset: use decorator to mark a function as fileset predicate...
r27460 """Subrepositories whose paths match the given pattern.
Angel Ezquerra
fileset: add "subrepo" fileset symbol...
r16443 """
# i18n: "subrepo" is a keyword
getargs(x, 0, 1, _("subrepo takes at most one argument"))
ctx = mctx.ctx
Mads Kiilerich
subrepos: process subrepos in sorted order...
r18364 sstate = sorted(ctx.substate)
Angel Ezquerra
fileset: add "subrepo" fileset symbol...
r16443 if x:
FUJIWARA Katsunori
i18n: add i18n comment to error messages of filesets predicates
r23113 # i18n: "subrepo" is a keyword
Angel Ezquerra
fileset: add "subrepo" fileset symbol...
r16443 pat = getstring(x, _("subrepo requires a pattern or no arguments"))
Gregory Szorc
fileset: use absolute_import
r25938 from . import match as matchmod # avoid circular import issues
Angel Ezquerra
fileset: add "subrepo" fileset symbol...
r16443 fast = not matchmod.patkind(pat)
if fast:
def m(s):
return (s == pat)
else:
Matt Harbison
fileset: replace 'ctx._repo' with 'ctx.repo()'
r24334 m = matchmod.match(ctx.repo().root, '', [pat], ctx=ctx)
Angel Ezquerra
fileset: add "subrepo" fileset symbol...
r16443 return [sub for sub in sstate if m(sub)]
else:
return [sub for sub in sstate]
Matt Mackall
fileset: basic pattern and boolean support...
r14551 methods = {
'string': stringset,
'symbol': stringset,
'and': andset,
'or': orset,
Patrick Mezard
fileset: actually implement 'minusset'...
r17363 'minus': minusset,
Matt Mackall
fileset: basic pattern and boolean support...
r14551 'list': listset,
'group': getset,
Matt Mackall
fileset: add some basic predicates
r14676 'not': notset,
'func': func,
Matt Mackall
fileset: basic pattern and boolean support...
r14551 }
class matchctx(object):
Matt Mackall
fileset: add support for file status predicates...
r14677 def __init__(self, ctx, subset=None, status=None):
Matt Mackall
fileset: basic pattern and boolean support...
r14551 self.ctx = ctx
self.subset = subset
Matt Mackall
fileset: add support for file status predicates...
r14677 self._status = status
FUJIWARA Katsunori
fileset: detect unintentional existing() invocation at runtime...
r27464 self._existingenabled = False
Matt Mackall
fileset: add support for file status predicates...
r14677 def status(self):
return self._status
Matt Mackall
fileset: drop matchfn...
r14673 def matcher(self, patterns):
return self.ctx.match(patterns)
Matt Mackall
fileset: basic pattern and boolean support...
r14551 def filter(self, files):
return [f for f in files if f in self.subset]
Matt Mackall
fileset: don't attempt to check data predicates against removed files
r15963 def existing(self):
FUJIWARA Katsunori
fileset: detect unintentional existing() invocation at runtime...
r27464 assert self._existingenabled, 'unexpected existing() invocation'
Patrick Mezard
fileset: exclude deleted files from matchctx.existing()...
r17365 if self._status is not None:
removed = set(self._status[3])
Patrick Mezard
fileset: matchctx.existing() must consider ignored files...
r17367 unknown = set(self._status[4] + self._status[5])
Patrick Mezard
fileset: exclude deleted files from matchctx.existing()...
r17365 else:
removed = set()
Patrick Mezard
fileset: matchctx.existing() must consider unknown files...
r17366 unknown = set()
Patrick Mezard
fileset: exclude deleted files from matchctx.existing()...
r17365 return (f for f in self.subset
Patrick Mezard
fileset: matchctx.existing() must consider unknown files...
r17366 if (f in self.ctx and f not in removed) or f in unknown)
Matt Mackall
fileset: basic pattern and boolean support...
r14551 def narrow(self, files):
Matt Mackall
fileset: add support for file status predicates...
r14677 return matchctx(self.ctx, self.filter(files), self._status)
Matt Mackall
fileset: basic pattern and boolean support...
r14551
Matt Mackall
fileset: prescan parse tree to optimize status usage...
r14678 def _intree(funcs, tree):
if isinstance(tree, tuple):
if tree[0] == 'func' and tree[1][0] == 'symbol':
if tree[1][1] in funcs:
return True
for s in tree[1:]:
if _intree(funcs, s):
return True
return False
Matt Mackall
fileset: drop matchfn...
r14673 def getfileset(ctx, expr):
Yuya Nishihara
fileset: move validation of incomplete parsing to parse() function...
r25252 tree = parse(expr)
Matt Mackall
fileset: prescan parse tree to optimize status usage...
r14678
# do we need status info?
FUJIWARA Katsunori
fileset: use decorator to mark a predicate as "status caller"...
r27461 if (_intree(_statuscallers, tree) or
Patrick Mezard
fileset: exclude deleted files from matchctx.existing()...
r17365 # Using matchctx.existing() on a workingctx requires us to check
# for deleted files.
(ctx.rev() is None and _intree(_existingcallers, tree))):
Matt Mackall
fileset: prescan parse tree to optimize status usage...
r14678 unknown = _intree(['unknown'], tree)
ignored = _intree(['ignored'], tree)
Matt Harbison
fileset: replace 'ctx._repo' with 'ctx.repo()'
r24334 r = ctx.repo()
Matt Mackall
fileset: prescan parse tree to optimize status usage...
r14678 status = r.status(ctx.p1(), ctx,
unknown=unknown, ignored=ignored, clean=True)
subset = []
for c in status:
subset.extend(c)
else:
status = None
Patrick Mezard
fileset: fix generator vs list bug in fast path...
r17371 subset = list(ctx.walk(ctx.match([])))
Matt Mackall
fileset: prescan parse tree to optimize status usage...
r14678
return getset(matchctx(ctx, subset, status), tree)
Matt Mackall
fileset: add some function help text
r14681
Yuya Nishihara
fileset: pretty print syntax tree in debug output
r25255 def prettyformat(tree):
return parser.prettyformat(tree, ('string', 'symbol'))
FUJIWARA Katsunori
registrar: add filesetpredicate to mark a function as fileset predicate...
r28447 def loadpredicate(ui, extname, registrarobj):
"""Load fileset predicates from specified registrarobj
"""
for name, func in registrarobj._table.iteritems():
symbols[name] = func
if func._callstatus:
_statuscallers.add(name)
if func._callexisting:
_existingcallers.add(name)
FUJIWARA Katsunori
fileset: replace predicate by filesetpredicate of registrar (API)...
r28448 # load built-in predicates explicitly to setup _statuscallers/_existingcallers
loadpredicate(None, None, predicate)
Matt Mackall
fileset: add some function help text
r14681 # tell hggettext to extract docstrings from these functions:
i18nfunctions = symbols.values()