##// END OF EJS Templates
sslutil: work around validator crash getting certificate on failed sockets...
sslutil: work around validator crash getting certificate on failed sockets The previous workaround for correct handling of wrapping of failing connections might be enough to prevent this from happening, but the check here makes this function more robust.

File last commit:

r15791:a814f8fc default
r15816:4bb59919 default
Show More
revset.py
1142 lines | 34.0 KiB | text/x-python | PythonLexer
Matt Mackall
revset: introduce revset core
r11275 # revset.py - revision 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.
import re
Pierre-Yves David
revset: disambiguous the node variable...
r15326 import parser, util, error, discovery, hbisect
import node as nodemod
Matt Mackall
bookmarks: move revset support to core
r13359 import bookmarks as bookmarksmod
Martin Geisler
Consistently import foo as foomod when foo to avoid shadowing...
r12085 import match as matchmod
Patrick Mezard
help: extract items doc generation function
r13593 from i18n import _
FUJIWARA Katsunori
i18n: use "encoding.lower()" to normalize specified string for revset...
r15726 import encoding
Matt Mackall
revset: introduce revset core
r11275
elements = {
"(": (20, ("group", 1, ")"), ("func", 1, ")")),
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 "~": (18, None, ("ancestor", 18)),
"^": (18, None, ("parent", 18), ("parentpost", 18)),
Matt Mackall
revset: lower precedence of minus infix (issue2361)
r12616 "-": (5, ("negate", 19), ("minus", 5)),
Matt Mackall
revset: add support for prefix and suffix versions of : and ::
r11278 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
("dagrangepost", 17)),
"..": (17, ("dagrangepre", 17), ("dagrange", 17),
("dagrangepost", 17)),
":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
Matt Mackall
revset: introduce revset core
r11275 "not": (10, ("not", 10)),
"!": (10, ("not", 10)),
"and": (5, None, ("and", 5)),
"&": (5, None, ("and", 5)),
"or": (4, None, ("or", 4)),
"|": (4, None, ("or", 4)),
"+": (4, None, ("or", 4)),
",": (2, None, ("list", 2)),
")": (0, None, None),
"symbol": (0, ("symbol",), None),
"string": (0, ("string",), None),
"end": (0, None, None),
}
keywords = set(['and', 'or', 'not'])
def tokenize(program):
pos, l = 0, len(program)
while pos < l:
c = program[pos]
if c.isspace(): # skip inter-token whitespace
pass
Matt Mackall
revset: add support for prefix and suffix versions of : and ::
r11278 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
Matt Mackall
revset: raise ParseError exceptions
r11289 yield ('::', None, pos)
Matt Mackall
revset: add support for prefix and suffix versions of : and ::
r11278 pos += 1 # skip ahead
Matt Mackall
revset: introduce revset core
r11275 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
Matt Mackall
revset: raise ParseError exceptions
r11289 yield ('..', None, pos)
Matt Mackall
revset: introduce revset core
r11275 pos += 1 # skip ahead
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 elif c in "():,-|&+!~^": # handle simple operators
Matt Mackall
revset: raise ParseError exceptions
r11289 yield (c, None, pos)
Brodie Rao
revset: support raw string literals...
r12408 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:
decode = lambda x: x.decode('string-escape')
Matt Mackall
revset: introduce revset core
r11275 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:
Brodie Rao
revset: support raw string literals...
r12408 yield ('string', decode(program[s:pos]), s)
Matt Mackall
revset: introduce revset core
r11275 break
pos += 1
else:
Martin Geisler
revset: all your error messages are belong to _
r11383 raise error.ParseError(_("unterminated string"), s)
Matt Mackall
revset: allow extended characters in symbols
r11404 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
Matt Mackall
revset: introduce revset core
r11275 s = pos
pos += 1
while pos < l: # find end of symbol
d = program[pos]
Matt Mackall
revset: allow extended characters in symbols
r11404 if not (d.isalnum() or d in "._" or ord(d) > 127):
Matt Mackall
revset: introduce revset core
r11275 break
if d == '.' and program[pos - 1] == '.': # special case for ..
pos -= 1
break
pos += 1
sym = program[s:pos]
if sym in keywords: # operator keywords
Matt Mackall
revset: raise ParseError exceptions
r11289 yield (sym, None, s)
Matt Mackall
revset: introduce revset core
r11275 else:
Matt Mackall
revset: raise ParseError exceptions
r11289 yield ('symbol', sym, s)
Matt Mackall
revset: introduce revset core
r11275 pos -= 1
else:
Martin Geisler
revset: all your error messages are belong to _
r11383 raise error.ParseError(_("syntax error"), pos)
Matt Mackall
revset: introduce revset core
r11275 pos += 1
Matt Mackall
revset: raise ParseError exceptions
r11289 yield ('end', None, pos)
Matt Mackall
revset: introduce revset core
r11275
# helpers
def getstring(x, err):
Matt Mackall
revset: fix up contains/getstring when no args passed
r11406 if x and (x[0] == 'string' or x[0] == 'symbol'):
Matt Mackall
revset: introduce revset core
r11275 return x[1]
Matt Mackall
revset: raise ParseError exceptions
r11289 raise error.ParseError(err)
Matt Mackall
revset: introduce revset core
r11275
def getlist(x):
if not x:
return []
if x[0] == 'list':
return getlist(x[1]) + [x[2]]
return [x]
Matt Mackall
revset: improve filter argument handling
r11339 def getargs(x, min, max, err):
Matt Mackall
revset: introduce revset core
r11275 l = getlist(x)
Matt Mackall
revset: improve filter argument handling
r11339 if len(l) < min or len(l) > max:
Matt Mackall
revset: raise ParseError exceptions
r11289 raise error.ParseError(err)
Matt Mackall
revset: introduce revset core
r11275 return l
def getset(repo, subset, x):
if not x:
Martin Geisler
revset: all your error messages are belong to _
r11383 raise error.ParseError(_("missing argument"))
Matt Mackall
revset: introduce revset core
r11275 return methods[x[0]](repo, subset, *x[1:])
# operator methods
def stringset(repo, subset, x):
x = repo[x].rev()
Matt Mackall
revset: fix up tests
r11282 if x == -1 and len(subset) == len(repo):
return [-1]
Idan Kamara
revset: optimize stringset when subset == entire repo...
r13938 if len(subset) == len(repo) or x in subset:
Matt Mackall
revset: introduce revset core
r11275 return [x]
return []
def symbolset(repo, subset, x):
if x in symbols:
Martin Geisler
revset: all your error messages are belong to _
r11383 raise error.ParseError(_("can't use %s here") % x)
Matt Mackall
revset: introduce revset core
r11275 return stringset(repo, subset, x)
def rangeset(repo, subset, x, y):
Matt Mackall
revset: deal with empty sets in range endpoints...
r11456 m = getset(repo, subset, x)
if not m:
m = getset(repo, range(len(repo)), x)
n = getset(repo, subset, y)
if not n:
n = getset(repo, range(len(repo)), y)
if not m or not n:
return []
m, n = m[0], n[-1]
Matt Mackall
revset: introduce revset core
r11275 if m < n:
Matt Mackall
revset: deal with empty sets in range endpoints...
r11456 r = range(m, n + 1)
else:
r = range(m, n - 1, -1)
s = set(subset)
return [x for x in r if x in s]
Matt Mackall
revset: introduce revset core
r11275
def andset(repo, subset, x, y):
return getset(repo, getset(repo, subset, x), y)
def orset(repo, subset, x, y):
Augie Fackler
revsets: preserve ordering with the or operator...
r13932 xl = getset(repo, subset, x)
s = set(xl)
yl = getset(repo, [r for r in subset if r not in s], y)
return xl + yl
Matt Mackall
revset: introduce revset core
r11275
def notset(repo, subset, x):
s = set(getset(repo, subset, x))
return [r for r in subset if r not in s]
def listset(repo, subset, a, b):
Martin Geisler
revset: all your error messages are belong to _
r11383 raise error.ParseError(_("can't use a list in this context"))
Matt Mackall
revset: introduce revset core
r11275
def func(repo, subset, a, b):
if a[0] == 'symbol' and a[1] in symbols:
return symbols[a[1]](repo, subset, b)
Martin Geisler
revset: all your error messages are belong to _
r11383 raise error.ParseError(_("not a function: %s") % a[1])
Matt Mackall
revset: introduce revset core
r11275
# functions
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def adds(repo, subset, x):
"""``adds(pattern)``
Changesets that add a file matching pattern.
"""
# i18n: "adds" is a keyword
pat = getstring(x, _("adds requires a pattern"))
return checkstatus(repo, subset, pat, 1)
def ancestor(repo, subset, x):
"""``ancestor(single, single)``
Greatest common ancestor of the two changesets.
"""
# i18n: "ancestor" is a keyword
l = getargs(x, 2, 2, _("ancestor requires two arguments"))
r = range(len(repo))
a = getset(repo, r, l[0])
b = getset(repo, r, l[1])
if len(a) != 1 or len(b) != 1:
# i18n: "ancestor" is a keyword
raise error.ParseError(_("ancestor arguments must be single revisions"))
an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
return [r for r in an if r in subset]
def ancestors(repo, subset, x):
"""``ancestors(set)``
Changesets that are ancestors of a changeset in set.
"""
args = getset(repo, range(len(repo)), x)
if not args:
return []
s = set(repo.changelog.ancestors(*args)) | set(args)
return [r for r in subset if r in s]
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 def ancestorspec(repo, subset, x, n):
"""``set~n``
Changesets that are the Nth ancestor (first parents only) of a changeset in set.
"""
try:
n = int(n[1])
Matt Mackall
revsets: actually catch type error on tip^p1(tip) (issue2884)...
r14851 except (TypeError, ValueError):
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 raise error.ParseError(_("~ expects a number"))
ps = set()
cl = repo.changelog
for r in getset(repo, subset, x):
for i in range(n):
r = cl.parentrevs(r)[0]
ps.add(r)
return [r for r in subset if r in ps]
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def author(repo, subset, x):
"""``author(string)``
Alias for ``user(string)``.
"""
# i18n: "author" is a keyword
FUJIWARA Katsunori
i18n: use "encoding.lower()" to normalize specified string for revset...
r15726 n = encoding.lower(getstring(x, _("author requires a string")))
return [r for r in subset if n in encoding.lower(repo[r].user())]
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
"Yann E. MORIN"
revset: rename bisected() to bisect()...
r15134 def bisect(repo, subset, x):
"""``bisect(string)``
"Yann E. MORIN"
hbisect: add two new revset descriptions: 'goods' and 'bads'...
r15153 Changesets marked in the specified bisect status:
"Yann E. MORIN"
revset.bisect: add new 'range' set to the bisect keyword...
r15136
"Yann E. MORIN"
hbisect: add two new revset descriptions: 'goods' and 'bads'...
r15153 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
- ``goods``, ``bads`` : csets topologicaly good/bad
- ``range`` : csets taking part in the bisection
- ``pruned`` : csets that are goods, bads or skipped
- ``untested`` : csets whose fate is yet unknown
- ``ignored`` : csets ignored due to DAG topology
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
"Yann E. MORIN"
revset.bisect: move bisect() code to hbisect.py...
r15135 status = getstring(x, _("bisect requires a string")).lower()
return [r for r in subset if r in hbisect.get(repo, status)]
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
"Yann E. MORIN"
revset: rename bisected() to bisect()...
r15134 # Backward-compatibility
# - no help entry so that we do not advertise it any more
def bisected(repo, subset, x):
return bisect(repo, subset, x)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def bookmark(repo, subset, x):
"""``bookmark([name])``
The named bookmark or all bookmarks.
"""
# i18n: "bookmark" is a keyword
args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
if args:
bm = getstring(args[0],
# i18n: "bookmark" is a keyword
_('the argument to bookmark must be a string'))
bmrev = bookmarksmod.listbookmarks(repo).get(bm, None)
if not bmrev:
raise util.Abort(_("bookmark '%s' does not exist") % bm)
bmrev = repo[bmrev].rev()
return [r for r in subset if r == bmrev]
bms = set([repo[r].rev()
for r in bookmarksmod.listbookmarks(repo).values()])
return [r for r in subset if r in bms]
def branch(repo, subset, x):
"""``branch(string or set)``
All changesets belonging to the given branch or the branches of the given
changesets.
"""
try:
b = getstring(x, '')
if b in repo.branchmap():
return [r for r in subset if repo[r].branch() == b]
except error.ParseError:
# not a string, but another revspec, e.g. tip()
pass
s = getset(repo, range(len(repo)), x)
b = set()
for r in s:
b.add(repo[r].branch())
s = set(s)
return [r for r in subset if r in s or repo[r].branch() in b]
def checkstatus(repo, subset, pat, field):
m = matchmod.match(repo.root, repo.getcwd(), [pat])
s = []
fast = (m.files() == [pat])
for r in subset:
c = repo[r]
if fast:
if pat not in c.files():
continue
else:
for f in c.files():
if m(f):
break
else:
continue
files = repo.status(c.p1().node(), c.node())[field]
if fast:
if pat in files:
s.append(r)
else:
for f in files:
if m(f):
s.append(r)
break
return s
def children(repo, subset, x):
"""``children(set)``
Child changesets of changesets in set.
"""
cs = set()
cl = repo.changelog
s = set(getset(repo, range(len(repo)), x))
for r in xrange(0, len(repo)):
for p in cl.parentrevs(r):
if p in s:
cs.add(r)
return [r for r in subset if r in cs]
def closed(repo, subset, x):
"""``closed()``
Changeset is closed.
"""
# i18n: "closed" is a keyword
getargs(x, 0, 0, _("closed takes no arguments"))
return [r for r in subset if repo[r].extra().get('close')]
def contains(repo, subset, x):
"""``contains(pattern)``
Martin Geisler
merge with stable
r14357 Revision contains a file matching pattern. See :hg:`help patterns`
for information about file patterns.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# i18n: "contains" is a keyword
pat = getstring(x, _("contains requires a pattern"))
m = matchmod.match(repo.root, repo.getcwd(), [pat])
s = []
if m.files() == [pat]:
for r in subset:
if pat in repo[r]:
s.append(r)
else:
for r in subset:
for f in repo[r].manifest():
if m(f):
s.append(r)
break
return s
def date(repo, subset, x):
"""``date(interval)``
Changesets within the interval, see :hg:`help dates`.
"""
# i18n: "date" is a keyword
ds = getstring(x, _("date requires a string"))
dm = util.matchdate(ds)
return [r for r in subset if dm(repo[r].date()[0])]
Thomas Arendsen Hein
revset: add desc(string) to search in commit messages...
r14650 def desc(repo, subset, x):
"""``desc(string)``
Search commit message for string. The match is case-insensitive.
"""
# i18n: "desc" is a keyword
FUJIWARA Katsunori
i18n: use "encoding.lower()" to normalize specified string for revset...
r15726 ds = encoding.lower(getstring(x, _("desc requires a string")))
Thomas Arendsen Hein
revset: add desc(string) to search in commit messages...
r14650 l = []
for r in subset:
c = repo[r]
FUJIWARA Katsunori
i18n: use "encoding.lower()" to normalize specified string for revset...
r15726 if ds in encoding.lower(c.description()):
Thomas Arendsen Hein
revset: add desc(string) to search in commit messages...
r14650 l.append(r)
return l
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def descendants(repo, subset, x):
"""``descendants(set)``
Changesets which are descendants of changesets in set.
"""
args = getset(repo, range(len(repo)), x)
if not args:
return []
s = set(repo.changelog.descendants(*args)) | set(args)
return [r for r in subset if r in s]
Matt Mackall
revset: introduce filelog() to emulate log's fast path...
r14342 def filelog(repo, subset, x):
"""``filelog(pattern)``
Changesets connected to the specified filelog.
"""
pat = getstring(x, _("filelog requires a pattern"))
m = matchmod.match(repo.root, repo.getcwd(), [pat], default='relpath')
s = set()
if not m.anypats():
for f in m.files():
fl = repo.file(f)
for fr in fl:
s.add(fl.linkrev(fr))
else:
for f in repo[None]:
if m(f):
fl = repo.file(f)
for fr in fl:
s.add(fl.linkrev(fr))
return [r for r in subset if r in s]
Matt Mackall
revsets: add first alias for last
r15117 def first(repo, subset, x):
"""``first(set, [n])``
An alias for limit().
"""
return limit(repo, subset, x)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def follow(repo, subset, x):
Matt Mackall
revset: add follow(filename) to follow a filename's history across copies
r14343 """``follow([file])``
An alias for ``::.`` (ancestors of the working copy's first parent).
If a filename is specified, the history of the given file is followed,
including copies.
"""
# i18n: "follow" is a keyword
l = getargs(x, 0, 1, _("follow takes no arguments or a filename"))
p = repo['.'].rev()
if l:
Mads Kiilerich
revset and fileset: fix typos in parser error messages
r14717 x = getstring(l[0], _("follow expected a filename"))
Matt Mackall
revset: follow(nosuchfile) should give an empty set (issue3114)
r15532 if x in repo['.']:
s = set(ctx.rev() for ctx in repo['.'][x].ancestors())
else:
return []
Matt Mackall
revset: add follow(filename) to follow a filename's history across copies
r14343 else:
s = set(repo.changelog.ancestors(p))
s |= set([p])
return [r for r in subset if r in s]
Mads Kiilerich
revset: fix parameter name in implementation of follow()
r14715 def followfile(repo, subset, x):
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """``follow()``
An alias for ``::.`` (ancestors of the working copy's first parent).
"""
# i18n: "follow" is a keyword
getargs(x, 0, 0, _("follow takes no arguments"))
p = repo['.'].rev()
s = set(repo.changelog.ancestors(p)) | set([p])
return [r for r in subset if r in s]
def getall(repo, subset, x):
"""``all()``
All changesets, the same as ``0:tip``.
"""
# i18n: "all" is a keyword
getargs(x, 0, 0, _("all takes no arguments"))
return subset
def grep(repo, subset, x):
"""``grep(regex)``
Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
Martin Geisler
merge with stable
r14357 to ensure special escape characters are handled correctly. Unlike
``keyword(string)``, the match is case-sensitive.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
try:
# i18n: "grep" is a keyword
gr = re.compile(getstring(x, _("grep requires a string")))
except re.error, e:
raise error.ParseError(_('invalid match pattern: %s') % e)
l = []
for r in subset:
c = repo[r]
for e in c.files() + [c.user(), c.description()]:
if gr.search(e):
l.append(r)
break
return l
def hasfile(repo, subset, x):
"""``file(pattern)``
Changesets affecting files matched by pattern.
"""
# i18n: "file" is a keyword
pat = getstring(x, _("file requires a pattern"))
m = matchmod.match(repo.root, repo.getcwd(), [pat])
s = []
for r in subset:
for f in repo[r].files():
if m(f):
s.append(r)
break
return s
def head(repo, subset, x):
"""``head()``
Changeset is a named branch head.
"""
# i18n: "head" is a keyword
getargs(x, 0, 0, _("head takes no arguments"))
hs = set()
for b, ls in repo.branchmap().iteritems():
hs.update(repo[h].rev() for h in ls)
return [r for r in subset if r in hs]
def heads(repo, subset, x):
"""``heads(set)``
Members of set with no children in set.
"""
s = getset(repo, subset, x)
ps = set(parents(repo, subset, x))
return [r for r in s if r not in ps]
def keyword(repo, subset, x):
"""``keyword(string)``
Search commit message, user name, and names of changed files for
Martin Geisler
merge with stable
r14357 string. The match is case-insensitive.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# i18n: "keyword" is a keyword
FUJIWARA Katsunori
i18n: use "encoding.lower()" to normalize specified string for revset...
r15726 kw = encoding.lower(getstring(x, _("keyword requires a string")))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 l = []
for r in subset:
c = repo[r]
t = " ".join(c.files() + [c.user(), c.description()])
FUJIWARA Katsunori
i18n: use "encoding.lower()" to normalize specified string for revset...
r15726 if kw in encoding.lower(t):
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 l.append(r)
return l
def limit(repo, subset, x):
Matt Mackall
revset: add default of 1 to limit and last functions
r15116 """``limit(set, [n])``
First n members of set, defaulting to 1.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# i18n: "limit" is a keyword
Matt Mackall
revset: add default of 1 to limit and last functions
r15116 l = getargs(x, 1, 2, _("limit requires one or two arguments"))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 try:
Matt Mackall
revset: add default of 1 to limit and last functions
r15116 lim = 1
if len(l) == 2:
# i18n: "limit" is a keyword
lim = int(getstring(l[1], _("limit requires a number")))
Matt Mackall
revsets: actually catch type error on tip^p1(tip) (issue2884)...
r14851 except (TypeError, ValueError):
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 # i18n: "limit" is a keyword
raise error.ParseError(_("limit expects a number"))
Mads Kiilerich
revset: avoid over-aggresive optimizations of non-filtering functions (issue2549)...
r14153 ss = set(subset)
os = getset(repo, range(len(repo)), l[0])[:lim]
return [r for r in os if r in ss]
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Matt Mackall
revsets: add a last function...
r14061 def last(repo, subset, x):
Matt Mackall
revset: add default of 1 to limit and last functions
r15116 """``last(set, [n])``
Last n members of set, defaulting to 1.
Matt Mackall
revsets: add a last function...
r14061 """
# i18n: "last" is a keyword
Matt Mackall
revset: add default of 1 to limit and last functions
r15116 l = getargs(x, 1, 2, _("last requires one or two arguments"))
Matt Mackall
revsets: add a last function...
r14061 try:
Matt Mackall
revset: add default of 1 to limit and last functions
r15116 lim = 1
if len(l) == 2:
# i18n: "last" is a keyword
lim = int(getstring(l[1], _("last requires a number")))
Matt Mackall
revsets: actually catch type error on tip^p1(tip) (issue2884)...
r14851 except (TypeError, ValueError):
Matt Mackall
revsets: add a last function...
r14061 # i18n: "last" is a keyword
raise error.ParseError(_("last expects a number"))
Mads Kiilerich
revset: avoid over-aggresive optimizations of non-filtering functions (issue2549)...
r14153 ss = set(subset)
os = getset(repo, range(len(repo)), l[0])[-lim:]
return [r for r in os if r in ss]
Matt Mackall
revsets: add a last function...
r14061
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def maxrev(repo, subset, x):
"""``max(set)``
Changeset with highest revision number in set.
"""
Mads Kiilerich
revset: avoid over-aggresive optimizations of non-filtering functions (issue2549)...
r14153 os = getset(repo, range(len(repo)), x)
if os:
m = max(os)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 if m in subset:
return [m]
return []
def merge(repo, subset, x):
"""``merge()``
Changeset is a merge changeset.
"""
# i18n: "merge" is a keyword
getargs(x, 0, 0, _("merge takes no arguments"))
cl = repo.changelog
return [r for r in subset if cl.parentrevs(r)[1] != -1]
def minrev(repo, subset, x):
"""``min(set)``
Changeset with lowest revision number in set.
"""
Mads Kiilerich
revset: avoid over-aggresive optimizations of non-filtering functions (issue2549)...
r14153 os = getset(repo, range(len(repo)), x)
if os:
m = min(os)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 if m in subset:
return [m]
return []
def modifies(repo, subset, x):
"""``modifies(pattern)``
Changesets modifying files matched by pattern.
"""
# i18n: "modifies" is a keyword
pat = getstring(x, _("modifies requires a pattern"))
return checkstatus(repo, subset, pat, 0)
Augie Fackler
revset: add id() and rev() to allow explicitly referring to changes by hash or rev
r12716 def node(repo, subset, x):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``id(string)``
Wagner Bruna
revset: fix missing dot in docstring
r12859 Revision non-ambiguously specified by the given hex string prefix.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "id" is a keyword
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 l = getargs(x, 1, 1, _("id requires one argument"))
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "id" is a keyword
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 n = getstring(l[0], _("id requires a string"))
Augie Fackler
revset: add id() and rev() to allow explicitly referring to changes by hash or rev
r12716 if len(n) == 40:
rn = repo[n].rev()
else:
rn = repo.changelog.rev(repo.changelog._partialmatch(n))
return [r for r in subset if r == rn]
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def outgoing(repo, subset, x):
"""``outgoing([path])``
Changesets not found in the specified destination repository, or the
default push location.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 import hg # avoid start-up nasties
# i18n: "outgoing" is a keyword
Mads Kiilerich
revset and fileset: fix typos in parser error messages
r14717 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 # i18n: "outgoing" is a keyword
dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
dest, branches = hg.parseurl(dest)
revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
if revs:
revs = [repo.lookup(rev) for rev in revs]
Matt Mackall
hg: change various repository() users to use peer() where appropriate...
r14556 other = hg.peer(repo, {}, dest)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 repo.ui.pushbuffer()
Peter Arrenbrecht
discovery: resurrect findoutgoing as findcommonoutgoing for extension hooks...
r14213 common, outheads = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 repo.ui.popbuffer()
cl = repo.changelog
Peter Arrenbrecht
discovery: resurrect findoutgoing as findcommonoutgoing for extension hooks...
r14213 o = set([cl.rev(r) for r in repo.changelog.findmissing(common, outheads)])
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 return [r for r in subset if r in o]
Augie Fackler
revset: add id() and rev() to allow explicitly referring to changes by hash or rev
r12716
Matt Mackall
revset: introduce revset core
r11275 def p1(repo, subset, x):
Kevin Bullock
revsets: let p1() and p2() return parents of working dir...
r12928 """``p1([set])``
First parent of changesets in set, or the working directory.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Kevin Bullock
revsets: let p1() and p2() return parents of working dir...
r12928 if x is None:
Matt Mackall
misc: replace .parents()[0] with p1()
r13878 p = repo[x].p1().rev()
Patrick Mezard
revset: fix p1, p2 and parents in dirstate case (a5f7f1e9340e)...
r12935 return [r for r in subset if r == p]
Kevin Bullock
revsets: let p1() and p2() return parents of working dir...
r12928
Matt Mackall
revset: introduce revset core
r11275 ps = set()
cl = repo.changelog
Wagner Bruna
revset: disable subset optimization for parents() and children() (issue2437)...
r12786 for r in getset(repo, range(len(repo)), x):
Matt Mackall
revset: introduce revset core
r11275 ps.add(cl.parentrevs(r)[0])
return [r for r in subset if r in ps]
def p2(repo, subset, x):
Kevin Bullock
revsets: let p1() and p2() return parents of working dir...
r12928 """``p2([set])``
Second parent of changesets in set, or the working directory.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Kevin Bullock
revsets: let p1() and p2() return parents of working dir...
r12928 if x is None:
ps = repo[x].parents()
try:
Patrick Mezard
revset: fix p1, p2 and parents in dirstate case (a5f7f1e9340e)...
r12935 p = ps[1].rev()
return [r for r in subset if r == p]
Kevin Bullock
revsets: let p1() and p2() return parents of working dir...
r12928 except IndexError:
return []
Matt Mackall
revset: introduce revset core
r11275 ps = set()
cl = repo.changelog
Wagner Bruna
revset: disable subset optimization for parents() and children() (issue2437)...
r12786 for r in getset(repo, range(len(repo)), x):
Matt Mackall
revset: introduce revset core
r11275 ps.add(cl.parentrevs(r)[1])
return [r for r in subset if r in ps]
def parents(repo, subset, x):
Kevin Bullock
revsets: let parents() return parents of working dir...
r12929 """``parents([set])``
The set of all parents for all changesets in set, or the working directory.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Kevin Bullock
revsets: let parents() return parents of working dir...
r12929 if x is None:
Patrick Mezard
revset: fix p1, p2 and parents in dirstate case (a5f7f1e9340e)...
r12935 ps = tuple(p.rev() for p in repo[x].parents())
return [r for r in subset if r in ps]
Kevin Bullock
revsets: let parents() return parents of working dir...
r12929
Matt Mackall
revset: introduce revset core
r11275 ps = set()
cl = repo.changelog
Wagner Bruna
revset: disable subset optimization for parents() and children() (issue2437)...
r12786 for r in getset(repo, range(len(repo)), x):
Matt Mackall
revset: introduce revset core
r11275 ps.update(cl.parentrevs(r))
return [r for r in subset if r in ps]
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 def parentspec(repo, subset, x, n):
"""``set^0``
The set.
``set^1`` (or ``set^``), ``set^2``
First or second parent, respectively, of all changesets in set.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Brodie Rao
revset: handle re.compile() errors in grep()...
r12320 try:
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 n = int(n[1])
Kevin Gessner
revset: add missing whitespace
r14072 if n not in (0, 1, 2):
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 raise ValueError
Matt Mackall
revsets: actually catch type error on tip^p1(tip) (issue2884)...
r14851 except (TypeError, ValueError):
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
ps = set()
Matt Mackall
revset: introduce revset core
r11275 cl = repo.changelog
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 for r in getset(repo, subset, x):
if n == 0:
ps.add(r)
elif n == 1:
ps.add(cl.parentrevs(r)[0])
elif n == 2:
parents = cl.parentrevs(r)
if len(parents) > 1:
ps.add(parents[1])
return [r for r in subset if r in ps]
Matt Mackall
revset: introduce revset core
r11275
Wagner Bruna
revset: predicate to avoid lookup errors...
r11944 def present(repo, subset, x):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``present(set)``
An empty set, if any revision in set isn't found; otherwise,
all revisions in set.
"""
Wagner Bruna
revset: predicate to avoid lookup errors...
r11944 try:
return getset(repo, subset, x)
except error.RepoLookupError:
return []
Matt Mackall
revset: introduce revset core
r11275 def removes(repo, subset, x):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``removes(pattern)``
Changesets which remove files matching pattern.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "removes" is a keyword
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 pat = getstring(x, _("removes requires a pattern"))
Matt Mackall
revset: introduce revset core
r11275 return checkstatus(repo, subset, pat, 2)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def rev(repo, subset, x):
"""``rev(number)``
Revision with the given numeric identifier.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 # i18n: "rev" is a keyword
l = getargs(x, 1, 1, _("rev requires one argument"))
try:
# i18n: "rev" is a keyword
l = int(getstring(l[0], _("rev requires a number")))
Matt Mackall
revsets: actually catch type error on tip^p1(tip) (issue2884)...
r14851 except (TypeError, ValueError):
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 # i18n: "rev" is a keyword
raise error.ParseError(_("rev expects a number"))
return [r for r in subset if r == l]
Matt Mackall
revset: introduce revset core
r11275
def reverse(repo, subset, x):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``reverse(set)``
Reverse order of set.
"""
Matt Mackall
revset: introduce revset core
r11275 l = getset(repo, subset, x)
l.reverse()
return l
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def roots(repo, subset, x):
"""``roots(set)``
Changesets with no parent changeset in set.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 s = getset(repo, subset, x)
cs = set(children(repo, subset, x))
return [r for r in s if r not in cs]
Wagner Bruna
revset: predicate to avoid lookup errors...
r11944
Matt Mackall
revset: introduce revset core
r11275 def sort(repo, subset, x):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``sort(set[, [-]key...])``
Sort set by keys. The default sort order is ascending, specify a key
as ``-key`` to sort in descending order.
The keys can be:
- ``rev`` for the revision number,
- ``branch`` for the branch name,
- ``desc`` for the commit message (description),
- ``user`` for user name (``author`` can be used as an alias),
- ``date`` for the commit date
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "sort" is a keyword
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
Matt Mackall
revset: introduce revset core
r11275 keys = "rev"
if len(l) == 2:
Martin Geisler
revset: all your error messages are belong to _
r11383 keys = getstring(l[1], _("sort spec must be a string"))
Matt Mackall
revset: introduce revset core
r11275
s = l[0]
keys = keys.split()
l = []
def invert(s):
return "".join(chr(255 - ord(c)) for c in s)
for r in getset(repo, subset, s):
c = repo[r]
e = []
for k in keys:
if k == 'rev':
e.append(r)
elif k == '-rev':
e.append(-r)
elif k == 'branch':
e.append(c.branch())
elif k == '-branch':
e.append(invert(c.branch()))
elif k == 'desc':
e.append(c.description())
elif k == '-desc':
e.append(invert(c.description()))
elif k in 'user author':
e.append(c.user())
elif k in '-user -author':
e.append(invert(c.user()))
elif k == 'date':
e.append(c.date()[0])
elif k == '-date':
e.append(-c.date()[0])
else:
Martin Geisler
revset: all your error messages are belong to _
r11383 raise error.ParseError(_("unknown sort key %r") % k)
Matt Mackall
revset: introduce revset core
r11275 e.append(r)
l.append(e)
l.sort()
return [e[-1] for e in l]
Augie Fackler
revset: rename tagged() to tag() and allow it to take an optional tag name
r12715 def tag(repo, subset, x):
Martin Geisler
revset: the name is optional for the tag predicate
r14356 """``tag([name])``
Patrick Mezard
revsets: generate predicate help dynamically
r12821 The specified tag by name, or all tagged revisions if no name is given.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "tag" is a keyword
Augie Fackler
revset: rename tagged() to tag() and allow it to take an optional tag name
r12715 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
Matt Mackall
revset: add tagged predicate
r11280 cl = repo.changelog
Augie Fackler
revset: rename tagged() to tag() and allow it to take an optional tag name
r12715 if args:
tn = getstring(args[0],
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "tag" is a keyword
Augie Fackler
revset: rename tagged() to tag() and allow it to take an optional tag name
r12715 _('the argument to tag must be a string'))
Idan Kamara
revset: abort when tag or bookmark doesn't exist
r13914 if not repo.tags().get(tn, None):
raise util.Abort(_("tag '%s' does not exist") % tn)
Augie Fackler
revset: rename tagged() to tag() and allow it to take an optional tag name
r12715 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
else:
s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
Matt Mackall
revset: add tagged predicate
r11280 return [r for r in subset if r in s]
Patrick Mezard
revsets: generate predicate help dynamically
r12821 def tagged(repo, subset, x):
return tag(repo, subset, x)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def user(repo, subset, x):
"""``user(string)``
Martin Geisler
merge with stable
r14357 User name contains string. The match is case-insensitive.
Matt Mackall
bookmarks: move revset support to core
r13359 """
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 return author(repo, subset, x)
Matt Mackall
bookmarks: move revset support to core
r13359
Matt Mackall
revset: introduce revset core
r11275 symbols = {
Matt Mackall
revset: sort the predicate list
r11284 "adds": adds,
"all": getall,
Matt Mackall
revset: introduce revset core
r11275 "ancestor": ancestor,
"ancestors": ancestors,
Matt Mackall
revset: sort the predicate list
r11284 "author": author,
"Yann E. MORIN"
revset: rename bisected() to bisect()...
r15134 "bisect": bisect,
Benoit Boissinot
revset: add a revset command to get bisect state.
r13602 "bisected": bisected,
Matt Mackall
bookmarks: move revset support to core
r13359 "bookmark": bookmark,
Matt Mackall
revset: introduce revset core
r11275 "branch": branch,
Matt Mackall
revset: sort the predicate list
r11284 "children": children,
"closed": closed,
"contains": contains,
"date": date,
Thomas Arendsen Hein
revset: add desc(string) to search in commit messages...
r14650 "desc": desc,
Matt Mackall
revset: sort the predicate list
r11284 "descendants": descendants,
"file": hasfile,
Matt Mackall
revset: introduce filelog() to emulate log's fast path...
r14342 "filelog": filelog,
Matt Mackall
revsets: add first alias for last
r15117 "first": first,
Matt Mackall
revset: sort the predicate list
r11284 "follow": follow,
"grep": grep,
"head": head,
"heads": heads,
Thomas Arendsen Hein
revset: update sorting of symbols
r14649 "id": node,
Matt Mackall
revset: introduce revset core
r11275 "keyword": keyword,
Matt Mackall
revsets: add a last function...
r14061 "last": last,
Matt Mackall
revset: sort the predicate list
r11284 "limit": limit,
"max": maxrev,
Thomas Arendsen Hein
revset: update sorting of symbols
r14649 "merge": merge,
Nicolas Dumazet
revset: add min function
r11708 "min": minrev,
Matt Mackall
revset: sort the predicate list
r11284 "modifies": modifies,
"outgoing": outgoing,
Matt Mackall
revset: introduce revset core
r11275 "p1": p1,
"p2": p2,
"parents": parents,
Wagner Bruna
revset: predicate to avoid lookup errors...
r11944 "present": present,
Matt Mackall
revset: sort the predicate list
r11284 "removes": removes,
Thomas Arendsen Hein
revset: update sorting of symbols
r14649 "rev": rev,
Matt Mackall
revset: sort the predicate list
r11284 "reverse": reverse,
Matt Mackall
revset: introduce revset core
r11275 "roots": roots,
Matt Mackall
revset: sort the predicate list
r11284 "sort": sort,
Augie Fackler
revset: rename tagged() to tag() and allow it to take an optional tag name
r12715 "tag": tag,
Patrick Mezard
revsets: generate predicate help dynamically
r12821 "tagged": tagged,
"user": user,
Matt Mackall
revset: introduce revset core
r11275 }
methods = {
"range": rangeset,
"string": stringset,
"symbol": symbolset,
"and": andset,
"or": orset,
"not": notset,
"list": listset,
"func": func,
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 "ancestor": ancestorspec,
"parent": parentspec,
"parentpost": p1,
Matt Mackall
revset: introduce revset core
r11275 }
Matt Mackall
revset: optimize the parse tree directly...
r11279 def optimize(x, small):
Martin Geisler
code style: prefer 'is' and 'is not' tests with singletons
r13031 if x is None:
Matt Mackall
revset: optimize the parse tree directly...
r11279 return 0, x
Matt Mackall
revset: introduce revset core
r11275 smallbonus = 1
if small:
smallbonus = .5
op = x[0]
Matt Mackall
revset: fix - handling in the optimizer
r11283 if op == 'minus':
Matt Mackall
revset: optimize the parse tree directly...
r11279 return optimize(('and', x[1], ('not', x[2])), small)
elif op == 'dagrange':
return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
('func', ('symbol', 'ancestors'), x[2])), small)
elif op == 'dagrangepre':
return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
elif op == 'dagrangepost':
return optimize(('func', ('symbol', 'descendants'), x[1]), small)
elif op == 'rangepre':
return optimize(('range', ('string', '0'), x[1]), small)
elif op == 'rangepost':
return optimize(('range', x[1], ('string', 'tip')), small)
Matt Mackall
revset: make negate work for sort specs
r11467 elif op == 'negate':
return optimize(('string',
'-' + getstring(x[1], _("can't negate that"))), small)
Matt Mackall
revset: optimize the parse tree directly...
r11279 elif op in 'string symbol negate':
return smallbonus, x # single revisions are small
Matt Mackall
revset: introduce revset core
r11275 elif op == 'and' or op == 'dagrange':
Matt Mackall
revset: optimize the parse tree directly...
r11279 wa, ta = optimize(x[1], True)
wb, tb = optimize(x[2], True)
w = min(wa, wb)
if wa > wb:
return w, (op, tb, ta)
return w, (op, ta, tb)
elif op == 'or':
wa, ta = optimize(x[1], False)
wb, tb = optimize(x[2], False)
if wb < wa:
wb, wa = wa, wb
return max(wa, wb), (op, ta, tb)
Matt Mackall
revset: introduce revset core
r11275 elif op == 'not':
Matt Mackall
revset: optimize the parse tree directly...
r11279 o = optimize(x[1], not small)
return o[0], (op, o[1])
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 elif op == 'parentpost':
o = optimize(x[1], small)
return o[0], (op, o[1])
Matt Mackall
revset: introduce revset core
r11275 elif op == 'group':
Matt Mackall
revset: optimize the parse tree directly...
r11279 return optimize(x[1], small)
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 elif op in 'range list parent ancestorspec':
Matt Mackall
revsets: do the right thing with x^:y (issue2884)...
r14842 if op == 'parent':
# x^:y means (x^) : y, not x ^ (:y)
post = ('parentpost', x[1])
if x[2][0] == 'dagrangepre':
return optimize(('dagrange', post, x[2][1]), small)
elif x[2][0] == 'rangepre':
return optimize(('range', post, x[2][1]), small)
Matt Mackall
revset: optimize the parse tree directly...
r11279 wa, ta = optimize(x[1], small)
wb, tb = optimize(x[2], small)
return wa + wb, (op, ta, tb)
Matt Mackall
revset: introduce revset core
r11275 elif op == 'func':
Martin Geisler
revset: all your error messages are belong to _
r11383 f = getstring(x[1], _("not a symbol"))
Matt Mackall
revset: optimize the parse tree directly...
r11279 wa, ta = optimize(x[2], small)
Thomas Arendsen Hein
revset: add desc(string) to search in commit messages...
r14650 if f in ("author branch closed date desc file grep keyword "
"outgoing user"):
Matt Mackall
revset: optimize the parse tree directly...
r11279 w = 10 # slow
Matt Mackall
revsets: reduce cost of outgoing in the optimizer
r12351 elif f in "modifies adds removes":
Matt Mackall
revset: optimize the parse tree directly...
r11279 w = 30 # slower
Matt Mackall
revset: introduce revset core
r11275 elif f == "contains":
Matt Mackall
revset: optimize the parse tree directly...
r11279 w = 100 # very slow
Matt Mackall
revset: introduce revset core
r11275 elif f == "ancestor":
Matt Mackall
revset: optimize the parse tree directly...
r11279 w = 1 * smallbonus
Matt Mackall
revsets: add first alias for last
r15117 elif f in "reverse limit first":
Matt Mackall
revset: optimize the parse tree directly...
r11279 w = 0
Matt Mackall
revset: introduce revset core
r11275 elif f in "sort":
Matt Mackall
revset: optimize the parse tree directly...
r11279 w = 10 # assume most sorts look at changelog
Matt Mackall
revset: introduce revset core
r11275 else:
Matt Mackall
revset: optimize the parse tree directly...
r11279 w = 1
return w + wa, (op, x[1], ta)
return 1, x
Matt Mackall
revset: introduce revset core
r11275
Alexander Solovyov
revset aliases
r14098 class revsetalias(object):
funcre = re.compile('^([^(]+)\(([^)]+)\)$')
Mads Kiilerich
revset: fix aliases with 0 or more than 2 parameters...
r14723 args = None
Alexander Solovyov
revset aliases
r14098
Mads Kiilerich
revset: fix aliases with 0 or more than 2 parameters...
r14723 def __init__(self, name, value):
Alexander Solovyov
revset aliases
r14098 '''Aliases like:
h = heads(default)
b($1) = ancestors($1) - ancestors(default)
'''
Mads Kiilerich
revset: fix aliases with 0 or more than 2 parameters...
r14723 if isinstance(name, tuple): # parameter substitution
self.tree = name
self.replacement = value
else: # alias definition
m = self.funcre.search(name)
Alexander Solovyov
revset aliases
r14098 if m:
Mads Kiilerich
revset: fix aliases with 0 or more than 2 parameters...
r14723 self.tree = ('func', ('symbol', m.group(1)))
Alexander Solovyov
revset aliases
r14098 self.args = [x.strip() for x in m.group(2).split(',')]
Mads Kiilerich
revset: fix aliases with 0 or more than 2 parameters...
r14723 for arg in self.args:
value = value.replace(arg, repr(arg))
Alexander Solovyov
revset aliases
r14098 else:
Mads Kiilerich
revset: fix aliases with 0 or more than 2 parameters...
r14723 self.tree = ('symbol', name)
Alexander Solovyov
revset aliases
r14098
self.replacement, pos = parse(value)
if pos != len(value):
Mads Kiilerich
parsers: fix localization markup of parser errors
r14701 raise error.ParseError(_('invalid token'), pos)
Alexander Solovyov
revset aliases
r14098
def process(self, tree):
if isinstance(tree, tuple):
Mads Kiilerich
revset: fix aliases with 0 or more than 2 parameters...
r14723 if self.args is None:
if tree == self.tree:
return self.replacement
elif tree[:2] == self.tree:
l = getlist(tree[2])
if len(l) != len(self.args):
raise error.ParseError(
_('invalid number of arguments: %s') % len(l))
result = self.replacement
for a, v in zip(self.args, l):
valalias = revsetalias(('string', a), v)
result = valalias.process(result)
return result
Alexander Solovyov
revset aliases
r14098 return tuple(map(self.process, tree))
return tree
def findaliases(ui, tree):
for k, v in ui.configitems('revsetalias'):
alias = revsetalias(k, v)
tree = alias.process(tree)
return tree
Matt Mackall
revset: introduce revset core
r11275 parse = parser.parser(tokenize, elements).parse
Alexander Solovyov
revset aliases
r14098 def match(ui, spec):
Matt Mackall
revset: nicer exception for empty queries
r11385 if not spec:
raise error.ParseError(_("empty query"))
Bernhard Leiner
revset: report a parse error if a revset is not parsed completely (issue2654)
r14496 tree, pos = parse(spec)
if (pos != len(spec)):
Mads Kiilerich
parsers: fix localization markup of parser errors
r14701 raise error.ParseError(_("invalid token"), pos)
Matt Mackall
revset: allow bypassing alias expansion...
r14900 if ui:
tree = findaliases(ui, tree)
Matt Mackall
revset: optimize the parse tree directly...
r11279 weight, tree = optimize(tree, True)
Matt Mackall
revset: introduce revset core
r11275 def mfunc(repo, subset):
return getset(repo, subset, tree)
return mfunc
Patrick Mezard
revsets: generate predicate help dynamically
r12821
Matt Mackall
revset: add formatspec convenience query builder
r14901 def formatspec(expr, *args):
'''
This is a convenience function for using revsets internally, and
escapes arguments appropriately. Aliases are intentionally ignored
so that intended expression behavior isn't accidentally subverted.
Supported arguments:
Matt Mackall
revset: add %r for embedded revset support to formatspec...
r15266 %r = revset expression, parenthesized
Matt Mackall
revset: add formatspec convenience query builder
r14901 %d = int(arg), no quoting
%s = string(arg), escaped and single-quoted
%b = arg.branch(), escaped and single-quoted
%n = hex(arg), single-quoted
%% = a literal '%'
Matt Mackall
revset: add %r for embedded revset support to formatspec...
r15266 Prefixing the type with 'l' specifies a parenthesized list of that type.
Matt Mackall
revset: add 'l' flag to formatspec for args...
r15140
Matt Mackall
revset: fix %r handling in formatspec
r15268 >>> formatspec('%r:: and %lr', '10 or 11', ("this()", "that()"))
'(10 or 11):: and ((this()) or (that()))'
Matt Mackall
revset: add formatspec convenience query builder
r14901 >>> formatspec('%d:: and not %d::', 10, 20)
'10:: and not 20::'
Matt Mackall
revset: deal with empty lists in formatspec
r15325 >>> formatspec('%ld or %ld', [], [1])
Matt Mackall
revset: balance %l or-expressions (issue3129)
r15595 '(0-0) or 1'
Matt Mackall
revset: add formatspec convenience query builder
r14901 >>> formatspec('keyword(%s)', 'foo\\xe9')
"keyword('foo\\\\xe9')"
>>> b = lambda: 'default'
>>> b.branch = b
>>> formatspec('branch(%b)', b)
"branch('default')"
Matt Mackall
revset: add 'l' flag to formatspec for args...
r15140 >>> formatspec('root(%ls)', ['a', 'b', 'c', 'd'])
Matt Mackall
revset: balance %l or-expressions (issue3129)
r15595 "root((('a' or 'b') or ('c' or 'd')))"
Matt Mackall
revset: add formatspec convenience query builder
r14901 '''
def quote(s):
return repr(str(s))
Matt Mackall
revset: add 'l' flag to formatspec for args...
r15140 def argtype(c, arg):
if c == 'd':
return str(int(arg))
elif c == 's':
return quote(arg)
Matt Mackall
revset: add %r for embedded revset support to formatspec...
r15266 elif c == 'r':
parse(arg) # make sure syntax errors are confined
return '(%s)' % arg
Matt Mackall
revset: add 'l' flag to formatspec for args...
r15140 elif c == 'n':
Pierre-Yves David
revset: disambiguous the node variable...
r15326 return quote(nodemod.hex(arg))
Matt Mackall
revset: add 'l' flag to formatspec for args...
r15140 elif c == 'b':
return quote(arg.branch())
Matt Mackall
revset: balance %l or-expressions (issue3129)
r15595 def listexp(s, t):
"balance a list s of type t to limit parse tree depth"
l = len(s)
if l == 0:
return '(0-0)' # a minimal way to represent an empty set
if l == 1:
return argtype(t, s[0])
Martin Geisler
Use explicit integer division...
r15791 m = l // 2
Matt Mackall
revset: balance %l or-expressions (issue3129)
r15595 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t))
Matt Mackall
revset: add formatspec convenience query builder
r14901 ret = ''
pos = 0
arg = 0
while pos < len(expr):
c = expr[pos]
if c == '%':
pos += 1
d = expr[pos]
if d == '%':
ret += d
Matt Mackall
revset: fix %r handling in formatspec
r15268 elif d in 'dsnbr':
Matt Mackall
revset: add 'l' flag to formatspec for args...
r15140 ret += argtype(d, args[arg])
Matt Mackall
revset: add formatspec convenience query builder
r14901 arg += 1
Matt Mackall
revset: add 'l' flag to formatspec for args...
r15140 elif d == 'l':
# a list of some type
pos += 1
d = expr[pos]
Matt Mackall
merge with stable
r15596 ret += listexp(list(args[arg]), d)
Matt Mackall
revset: add formatspec convenience query builder
r14901 arg += 1
else:
raise util.Abort('unexpected revspec format character %s' % d)
else:
ret += c
pos += 1
return ret
Patrick Mezard
hggettext: handle i18nfunctions declaration for docstrings translations
r12823 # tell hggettext to extract docstrings from these functions:
i18nfunctions = symbols.values()