##// END OF EJS Templates
gitweb: add link to graph...
gitweb: add link to graph error.tmpl wasn't consistent with other templates in gitweb in that it was missing a "graph" link. This commit makes it consistent.

File last commit:

r38714:3700564c default
r38769:0f948d82 @91 stable
Show More
fileset.py
671 lines | 21.0 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
Yuya Nishihara
fileset: add helpers to make predicatematcher and nevermatcher...
r38706 import errno
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,
Yuya Nishihara
fileset: move import of match module to top...
r35757 match as matchmod,
Gregory Szorc
fileset: use absolute_import
r25938 merge,
parser,
Pulkit Goyal
py3: use pycompat.bytestr so that we don't get ascii values...
r32523 pycompat,
FUJIWARA Katsunori
fileset: replace predicate by filesetpredicate of registrar (API)...
r28448 registrar,
Pierre-Yves David
fileset: add revs(revs, fileset) to evaluate set in working directory...
r31193 scmutil,
Gregory Szorc
fileset: use absolute_import
r25938 util,
)
Yuya Nishihara
stringutil: bulk-replace call sites to point to new module...
r37102 from .utils import (
stringutil,
)
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),
Yuya Nishihara
fileset: add kind:pat operator...
r35759 ":": (15, None, None, ("kindpat", 15), None),
Yuya Nishihara
parser: separate actions for primary expression and prefix operator...
r25815 "-": (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 }
Martin von Zweigbergk
cleanup: use set literals...
r32291 keywords = {'and', 'or', 'not'}
Matt Mackall
filesets: introduce basic fileset expression parser
r14511
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)
Pulkit Goyal
py3: use pycompat.bytestr so that we don't get ascii values...
r32523 program = pycompat.bytestr(program)
Matt Mackall
filesets: introduce basic fileset expression parser
r14511 while pos < l:
c = program[pos]
if c.isspace(): # skip inter-token whitespace
pass
Yuya Nishihara
fileset: add kind:pat operator...
r35759 elif c in "(),-:|&+!": # handle simple operators
Matt Mackall
filesets: introduce basic fileset expression parser
r14511 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
Yuya Nishihara
fileset: make it robust for bad function calls...
r35709 def getsymbol(x):
if x and x[0] == 'symbol':
return x[1]
raise error.ParseError(_('not a symbol'))
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)
Yuya Nishihara
fileset: add kind:pat operator...
r35759 def _getkindpat(x, y, allkinds, err):
kind = getsymbol(x)
pat = getstring(y, err)
if kind not in allkinds:
raise error.ParseError(_("invalid pattern kind: %s") % kind)
return '%s:%s' % (kind, pat)
def getpattern(x, allkinds, err):
if x and x[0] == 'kindpat':
return _getkindpat(x[1], x[2], allkinds, err)
return getstring(x, err)
Yuya Nishihara
fileset: move helper functions to top
r38617 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
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 def getmatch(mctx, x):
Matt Mackall
fileset: basic pattern and boolean support...
r14551 if not x:
raise error.ParseError(_("missing argument"))
return methods[x[0]](mctx, *x[1:])
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 def stringmatch(mctx, x):
return mctx.matcher([x])
Matt Mackall
fileset: basic pattern and boolean support...
r14551
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 def kindpatmatch(mctx, x, y):
return stringmatch(mctx, _getkindpat(x, y, matchmod.allpatternkinds,
_("pattern must be a string")))
Yuya Nishihara
fileset: add kind:pat operator...
r35759
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 def andmatch(mctx, x, y):
xm = getmatch(mctx, x)
ym = getmatch(mctx, y)
return matchmod.intersectmatchers(xm, ym)
Matt Mackall
fileset: basic pattern and boolean support...
r14551
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 def ormatch(mctx, x, y):
xm = getmatch(mctx, x)
ym = getmatch(mctx, y)
return matchmod.unionmatcher([xm, ym])
Matt Mackall
fileset: basic pattern and boolean support...
r14551
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 def notmatch(mctx, x):
m = getmatch(mctx, x)
return mctx.predicate(lambda f: not m(f), predrepr=('<not %r>', m))
Matt Mackall
fileset: basic pattern and boolean support...
r14551
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 def minusmatch(mctx, x, y):
xm = getmatch(mctx, x)
ym = getmatch(mctx, y)
return matchmod.differencematcher(xm, ym)
Patrick Mezard
fileset: actually implement 'minusset'...
r17363
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 def negatematch(mctx, x):
Yuya Nishihara
fileset: do not crash by unary negate operation...
r35710 raise error.ParseError(_("can't use negate operator in this context"))
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 def listmatch(mctx, x, y):
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
Yuya Nishihara
fileset: move helper functions to top
r38617 def func(mctx, a, b):
funcname = getsymbol(a)
if funcname in symbols:
Yuya Nishihara
fileset: remove callexisting flag and mctx.existing() (API)...
r38712 return symbols[funcname](mctx, b)
Yuya Nishihara
fileset: move helper functions to top
r38617
keep = lambda fn: getattr(fn, '__doc__', None) is not None
syms = [s for (s, fn) in symbols.items() if keep(fn)]
raise error.UnknownIdentifier(funcname, syms)
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: 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"))
Gregory Szorc
fileset: perform membership test against set for status queries...
r31697 s = set(mctx.status().modified)
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.predicate(s.__contains__, predrepr='modified')
Matt Mackall
fileset: add support for file status predicates...
r14677
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"))
Gregory Szorc
fileset: perform membership test against set for status queries...
r31697 s = set(mctx.status().added)
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.predicate(s.__contains__, predrepr='added')
Matt Mackall
fileset: add support for file status predicates...
r14677
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"))
Gregory Szorc
fileset: perform membership test against set for status queries...
r31697 s = set(mctx.status().removed)
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.predicate(s.__contains__, predrepr='removed')
Matt Mackall
fileset: add support for file status predicates...
r14677
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"))
Gregory Szorc
fileset: perform membership test against set for status queries...
r31697 s = set(mctx.status().deleted)
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.predicate(s.__contains__, predrepr='deleted')
Matt Mackall
fileset: add support for file status predicates...
r14677
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"))
Gregory Szorc
fileset: perform membership test against set for status queries...
r31697 s = set(mctx.status().deleted)
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.predicate(s.__contains__, predrepr='deleted')
liscju
fileset: add missing() predicate (issue4925)...
r27024
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):
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 """File that is unknown according to :hg:`status`."""
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"))
Gregory Szorc
fileset: perform membership test against set for status queries...
r31697 s = set(mctx.status().unknown)
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.predicate(s.__contains__, predrepr='unknown')
Matt Mackall
fileset: add support for file status predicates...
r14677
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):
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 """File that is ignored according to :hg:`status`."""
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"))
Gregory Szorc
fileset: perform membership test against set for status queries...
r31697 s = set(mctx.status().ignored)
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.predicate(s.__contains__, predrepr='ignored')
Matt Mackall
fileset: add support for file status predicates...
r14677
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"))
Gregory Szorc
fileset: perform membership test against set for status queries...
r31697 s = set(mctx.status().clean)
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.predicate(s.__contains__, predrepr='clean')
Matt Mackall
fileset: add support for file status predicates...
r14677
Yuya Nishihara
fileset: add "tracked()" to explicitly select files in the revision...
r38708 @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"))
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.predicate(mctx.ctx.__contains__, predrepr='tracked')
Yuya Nishihara
fileset: add "tracked()" to explicitly select files in the revision...
r38708
Yuya Nishihara
fileset: remove callexisting flag and mctx.existing() (API)...
r38712 @predicate('binary()')
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"))
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.fpredicate(lambda fctx: fctx.isbinary(),
predrepr='binary', cache=True)
Matt Mackall
fileset: add some basic predicates
r14676
Yuya Nishihara
fileset: remove callexisting flag and mctx.existing() (API)...
r38712 @predicate('exec()')
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"))
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 ctx = mctx.ctx
return mctx.predicate(lambda f: ctx.flags(f) == 'x', predrepr='exec')
Matt Mackall
fileset: add some basic predicates
r14676
Yuya Nishihara
fileset: remove callexisting flag and mctx.existing() (API)...
r38712 @predicate('symlink()')
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"))
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 ctx = mctx.ctx
return mctx.predicate(lambda f: ctx.flags(f) == 'l', predrepr='symlink')
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:
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.never()
Siddharth Agarwal
fileset: switch to mergestate.read()...
r26995 ms = merge.mergestate.read(mctx.ctx.repo())
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.predicate(lambda f: f in ms and ms[f] == 'r',
predrepr='resolved')
Matt Mackall
fileset: add resolved and unresolved predicates
r14679
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:
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.never()
Siddharth Agarwal
fileset: switch to mergestate.read()...
r26995 ms = merge.mergestate.read(mctx.ctx.repo())
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.predicate(lambda f: f in ms and ms[f] == 'u',
predrepr='unresolved')
Matt Mackall
fileset: add resolved and unresolved predicates
r14679
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"))
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.ctx.repo().dirstate._ignore
Matt Mackall
fileset: add hgignore
r14680
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"))
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.predicate(lambda f: util.checkwinfilename(f) is None,
predrepr='portable')
Siddharth Agarwal
fileset: add a fileset for portable filenames...
r24408
Yuya Nishihara
fileset: remove callexisting flag and mctx.existing() (API)...
r38712 @predicate('grep(regex)')
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:
Pulkit Goyal
py3: use utils.stringutil.forcebytestr to convert error to bytes...
r38094 raise error.ParseError(_('invalid match pattern: %s') %
stringutil.forcebytestr(e))
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.fpredicate(lambda fctx: r.search(fctx.data()),
predrepr=('grep(%r)', r.pattern), cache=True)
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
Yuya Nishihara
fileset: parse argument of size() by predicate function...
r38709 def sizematcher(expr):
Matt Harbison
fileset: split the logic for matching a size expression to a separate method...
r35633 """Return a function(size) -> bool from the ``size()`` expression"""
Yuya Nishihara
fileset: parse argument of size() by predicate function...
r38709 expr = expr.strip()
Matt Harbison
fileset: split the logic for matching a size expression to a separate method...
r35633 if '-' in expr: # do we have a range?
a, b = expr.split('-', 1)
a = util.sizetoint(a)
b = util.sizetoint(b)
return lambda x: x >= a and x <= b
elif expr.startswith("<="):
a = util.sizetoint(expr[2:])
return lambda x: x <= a
elif expr.startswith("<"):
a = util.sizetoint(expr[1:])
return lambda x: x < a
elif expr.startswith(">="):
a = util.sizetoint(expr[2:])
return lambda x: x >= a
elif expr.startswith(">"):
a = util.sizetoint(expr[1:])
return lambda x: x > a
Yuya Nishihara
fileset: drop bad "elif:" trying to check invalid size expression...
r36523 else:
Matt Harbison
fileset: split the logic for matching a size expression to a separate method...
r35633 a = util.sizetoint(expr)
b = _sizetomax(expr)
return lambda x: x >= a and x <= b
Yuya Nishihara
fileset: remove callexisting flag and mctx.existing() (API)...
r38712 @predicate('size(expression)')
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
timeless
help: clarify quotes are needed for filesets.size expressions
r29987 - size('1k') - files from 1024 to 2047 bytes
- size('< 20k') - files less than 20480 bytes
- size('>= .5MB') - files at least 524288 bytes
- size('4k - 1MB') - files from 4096 bytes to 1048576 bytes
Matt Mackall
fileset: add size() predicate
r14683 """
Yuya Nishihara
fileset: parse argument of size() by predicate function...
r38709 # i18n: "size" is a keyword
expr = getstring(x, _("size requires an expression"))
m = sizematcher(expr)
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.fpredicate(lambda fctx: m(fctx.size()),
predrepr=('size(%r)', expr), cache=True)
Matt Mackall
fileset: add size() predicate
r14683
Yuya Nishihara
fileset: remove callexisting flag and mctx.existing() (API)...
r38712 @predicate('encoding(name)')
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"))
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 def encp(fctx):
d = fctx.data()
Matt Mackall
fileset: add encoding() predicate
r14684 try:
Yuya Nishihara
py3: cast bytes encoding name to str in fileset.py
r38347 d.decode(pycompat.sysstr(enc))
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return True
Matt Mackall
fileset: add encoding() predicate
r14684 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:
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return False
Matt Mackall
fileset: add encoding() predicate
r14684
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.fpredicate(encp, predrepr=('encoding(%r)', enc), cache=True)
Matt Mackall
fileset: add encoding() predicate
r14684
Yuya Nishihara
fileset: remove callexisting flag and mctx.existing() (API)...
r38712 @predicate('eol(style)')
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
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 def eolp(fctx):
Matt Harbison
fileset: use filectx.isbinary() to filter out binaries in eol()...
r38433 if fctx.isbinary():
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return False
Matt Harbison
fileset: use filectx.isbinary() to filter out binaries in eol()...
r38433 d = fctx.data()
Matt Mackall
filesets: add eol predicate
r18842 if (enc == 'dos' or enc == 'win') and '\r\n' in d:
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return True
Matt Mackall
filesets: add eol predicate
r18842 elif enc == 'unix' and re.search('(?<!\r)\n', d):
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return True
Matt Mackall
filesets: add eol predicate
r18842 elif enc == 'mac' and re.search('\r(?!\n)', d):
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return True
return False
return mctx.fpredicate(eolp, predrepr=('eol(%r)', enc), cache=True)
Matt Mackall
filesets: add eol predicate
r18842
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"))
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 def copiedp(fctx):
p = fctx.parents()
return p and p[0].path() != fctx.path()
return mctx.fpredicate(copiedp, predrepr='copied', cache=True)
Matt Mackall
fileset: add copied predicate
r14685
Pierre-Yves David
fileset: add revs(revs, fileset) to evaluate set in working directory...
r31193 @predicate('revs(revs, pattern)')
def revs(mctx, x):
Yuya Nishihara
fileset: drop false function signatures from revs() and status() docs...
r31254 """Evaluate set in the specified revisions. If the revset match multiple
revs, this will return file matching pattern in any of the revision.
Pierre-Yves David
fileset: add revs(revs, fileset) to evaluate set in working directory...
r31193 """
# i18n: "revs" is a keyword
r, x = getargs(x, 2, 2, _("revs takes two arguments"))
# i18n: "revs" is a keyword
revspec = getstring(r, _("first argument to revs must be a revision"))
repo = mctx.ctx.repo()
revs = scmutil.revrange(repo, [revspec])
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 matchers = []
Pierre-Yves David
fileset: add revs(revs, fileset) to evaluate set in working directory...
r31193 for r in revs:
ctx = repo[r]
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 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)
Pierre-Yves David
fileset: add revs(revs, fileset) to evaluate set in working directory...
r31193
Pierre-Yves David
fileset: add a 'status(...)' predicate to control evaluation context...
r31195 @predicate('status(base, rev, pattern)')
def status(mctx, x):
Yuya Nishihara
fileset: drop false function signatures from revs() and status() docs...
r31254 """Evaluate predicate using status change between ``base`` and
Pierre-Yves David
fileset: add a 'status(...)' predicate to control evaluation context...
r31195 ``rev``. Examples:
- ``status(3, 7, added())`` - matches files added from "3" to "7"
"""
repo = mctx.ctx.repo()
# i18n: "status" is a keyword
b, r, x = getargs(x, 3, 3, _("status takes three arguments"))
# i18n: "status" is a keyword
baseerr = _("first argument to status must be a revision")
baserevspec = getstring(b, baseerr)
if not baserevspec:
raise error.ParseError(baseerr)
reverr = _("second argument to status must be a revision")
revspec = getstring(r, reverr)
if not revspec:
raise error.ParseError(reverr)
Martin von Zweigbergk
fileset: use context-returning revpair()...
r37274 basectx, ctx = scmutil.revpair(repo, [baserevspec, revspec])
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return getmatch(mctx.switch(ctx, _buildstatus(ctx, x, basectx=basectx)), x)
Pierre-Yves David
fileset: add a 'status(...)' predicate to control evaluation context...
r31195
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
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 sstate = ctx.substate
Angel Ezquerra
fileset: add "subrepo" fileset symbol...
r16443 if x:
Yuya Nishihara
fileset: add kind:pat operator...
r35759 pat = getpattern(x, matchmod.allpatternkinds,
# i18n: "subrepo" is a keyword
_("subrepo requires a pattern or no arguments"))
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)
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.predicate(lambda f: f in sstate and m(f),
predrepr=('subrepo(%r)', pat))
Angel Ezquerra
fileset: add "subrepo" fileset symbol...
r16443 else:
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return mctx.predicate(sstate.__contains__, predrepr='subrepo')
Angel Ezquerra
fileset: add "subrepo" fileset symbol...
r16443
Matt Mackall
fileset: basic pattern and boolean support...
r14551 methods = {
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 'string': stringmatch,
'symbol': stringmatch,
'kindpat': kindpatmatch,
'and': andmatch,
'or': ormatch,
'minus': minusmatch,
'negate': negatematch,
'list': listmatch,
'group': getmatch,
'not': notmatch,
Matt Mackall
fileset: add some basic predicates
r14676 'func': func,
Matt Mackall
fileset: basic pattern and boolean support...
r14551 }
class matchctx(object):
Yuya Nishihara
fileset: remove subset and unused filtering functions from matchctx
r38713 def __init__(self, ctx, status=None, badfn=None):
Matt Mackall
fileset: basic pattern and boolean support...
r14551 self.ctx = ctx
Matt Mackall
fileset: add support for file status predicates...
r14677 self._status = status
Yuya Nishihara
fileset: pass in badfn to inner matchers...
r38632 self._badfn = badfn
Yuya Nishihara
fileset: remove callexisting flag and mctx.existing() (API)...
r38712
Matt Mackall
fileset: add support for file status predicates...
r14677 def status(self):
return self._status
Yuya Nishihara
fileset: add helpers to make predicatematcher and nevermatcher...
r38706
Matt Mackall
fileset: drop matchfn...
r14673 def matcher(self, patterns):
Yuya Nishihara
fileset: pass in badfn to inner matchers...
r38632 return self.ctx.match(patterns, badfn=self._badfn)
Yuya Nishihara
fileset: add helpers to make predicatematcher and nevermatcher...
r38706
def predicate(self, predfn, predrepr=None, cache=False):
"""Create a matcher to select files by predfn(filename)"""
if cache:
predfn = util.cachefunc(predfn)
repo = self.ctx.repo()
return matchmod.predicatematcher(repo.root, repo.getcwd(), predfn,
predrepr=predrepr, badfn=self._badfn)
def fpredicate(self, predfn, predrepr=None, cache=False):
"""Create a matcher to select files by predfn(fctx) at the current
revision
Missing files are ignored.
"""
ctx = self.ctx
if ctx.rev() is None:
def fctxpredfn(f):
try:
fctx = ctx[f]
except error.LookupError:
return False
try:
fctx.audit()
except error.Abort:
return False
try:
return predfn(fctx)
except (IOError, OSError) as e:
if e.errno in (errno.ENOENT, errno.ENOTDIR, errno.EISDIR):
return False
raise
else:
def fctxpredfn(f):
try:
fctx = ctx[f]
except error.LookupError:
return False
return predfn(fctx)
return self.predicate(fctxpredfn, predrepr=predrepr, cache=cache)
def never(self):
"""Create a matcher to select nothing"""
repo = self.ctx.repo()
return matchmod.nevermatcher(repo.root, repo.getcwd(),
badfn=self._badfn)
Yuya Nishihara
fileset: add function to switch revision where fileset will be evaluated...
r31192 def switch(self, ctx, status=None):
Yuya Nishihara
fileset: remove subset and unused filtering functions from matchctx
r38713 return matchctx(ctx, status, self._badfn)
Matt Mackall
fileset: basic pattern and boolean support...
r14551
Yuya Nishihara
fileset: add function to switch revision where fileset will be evaluated...
r31192 # filesets using matchctx.switch()
_switchcallers = [
Pierre-Yves David
fileset: add revs(revs, fileset) to evaluate set in working directory...
r31193 'revs',
Pierre-Yves David
fileset: add a 'status(...)' predicate to control evaluation context...
r31195 'status',
Yuya Nishihara
fileset: add function to switch revision where fileset will be evaluated...
r31192 ]
Yuya Nishihara
fileset: add class to host special handling of initial subset...
r31188
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
Yuya Nishihara
fileset: add function to switch revision where fileset will be evaluated...
r31192 if tree[1][1] in _switchcallers:
# arguments won't be evaluated in the current context
return False
Matt Mackall
fileset: prescan parse tree to optimize status usage...
r14678 for s in tree[1:]:
if _intree(funcs, s):
return True
return False
Yuya Nishihara
fileset: restrict getfileset() to not return a computed set (API)...
r38631 def match(ctx, expr, badfn=None):
"""Create a matcher for a single fileset expression"""
Yuya Nishihara
fileset: move validation of incomplete parsing to parse() function...
r25252 tree = parse(expr)
Yuya Nishihara
fileset: remove fullmatchctx class...
r38714 mctx = matchctx(ctx, _buildstatus(ctx, tree), badfn=badfn)
Yuya Nishihara
fileset: rewrite predicates to return matcher not closed to subset (API) (BC)...
r38711 return getmatch(mctx, tree)
Matt Mackall
fileset: prescan parse tree to optimize status usage...
r14678
Pierre-Yves David
fileset: allow to specify a basectx for status...
r31194 def _buildstatus(ctx, tree, basectx=None):
Matt Mackall
fileset: prescan parse tree to optimize status usage...
r14678 # do we need status info?
Pierre-Yves David
fileset: allow to specify a basectx for status...
r31194
Yuya Nishihara
fileset: remove callexisting flag and mctx.existing() (API)...
r38712 if _intree(_statuscallers, 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()
Pierre-Yves David
fileset: allow to specify a basectx for status...
r31194 if basectx is None:
basectx = ctx.p1()
return r.status(basectx, ctx,
Yuya Nishihara
fileset: extract function that builds status tuple only if necessary...
r31191 unknown=unknown, ignored=ignored, clean=True)
Matt Mackall
fileset: prescan parse tree to optimize status usage...
r14678 else:
Yuya Nishihara
fileset: extract function that builds status tuple only if necessary...
r31191 return None
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)
Yuya Nishihara
fileset: remove callexisting flag and mctx.existing() (API)...
r38712 # load built-in predicates explicitly to setup _statuscallers
FUJIWARA Katsunori
fileset: replace predicate by filesetpredicate of registrar (API)...
r28448 loadpredicate(None, None, predicate)
Matt Mackall
fileset: add some function help text
r14681 # tell hggettext to extract docstrings from these functions:
i18nfunctions = symbols.values()