##// END OF EJS Templates
revset: use 'requires' instead of 'wants' in error message
revset: use 'requires' instead of 'wants' in error message

File last commit:

r12736:7e14e67e default
r12736:7e14e67e default
Show More
revset.py
626 lines | 18.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
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301 import parser, util, error, discovery
Martin Geisler
Consistently import foo as foomod when foo to avoid shadowing...
r12085 import match as matchmod
Martin Geisler
revset: all your error messages are belong to _
r11383 from i18n import _
Matt Mackall
revset: introduce revset core
r11275
elements = {
"(": (20, ("group", 1, ")"), ("func", 1, ")")),
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
Matt Mackall
revset: add support for prefix and suffix versions of : and ::
r11278 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]
Matt Mackall
revset: introduce revset core
r11275 if x in subset:
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):
s = set(getset(repo, subset, x))
s |= set(getset(repo, [r for r in subset if r not in s], y))
return [r for r in subset if r in s]
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
Augie Fackler
revset: add id() and rev() to allow explicitly referring to changes by hash or rev
r12716 def node(repo, subset, x):
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 l = getargs(x, 1, 1, _("id requires one argument"))
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]
def rev(repo, subset, x):
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 l = getargs(x, 1, 1, _("rev requires one argument"))
Augie Fackler
revset: add id() and rev() to allow explicitly referring to changes by hash or rev
r12716 try:
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 l = int(getstring(l[0], _("rev requires a number")))
Augie Fackler
revset: add id() and rev() to allow explicitly referring to changes by hash or rev
r12716 except ValueError:
raise error.ParseError(_("rev expects a number"))
return [r for r in subset if r == l]
Matt Mackall
revset: introduce revset core
r11275 def p1(repo, subset, x):
ps = set()
cl = repo.changelog
for r in getset(repo, subset, x):
ps.add(cl.parentrevs(r)[0])
return [r for r in subset if r in ps]
def p2(repo, subset, x):
ps = set()
cl = repo.changelog
for r in getset(repo, subset, x):
ps.add(cl.parentrevs(r)[1])
return [r for r in subset if r in ps]
def parents(repo, subset, x):
ps = set()
cl = repo.changelog
for r in getset(repo, subset, x):
ps.update(cl.parentrevs(r))
return [r for r in subset if r in ps]
def maxrev(repo, subset, x):
s = getset(repo, subset, x)
if s:
m = max(s)
if m in subset:
return [m]
return []
Nicolas Dumazet
revset: add min function
r11708 def minrev(repo, subset, x):
s = getset(repo, subset, x)
if s:
m = min(s)
if m in subset:
return [m]
return []
Matt Mackall
revset: introduce revset core
r11275 def limit(repo, subset, x):
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 l = getargs(x, 2, 2, _("limit requires two arguments"))
Matt Mackall
revset: introduce revset core
r11275 try:
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 lim = int(getstring(l[1], _("limit requires a number")))
Matt Mackall
revset: introduce revset core
r11275 except ValueError:
Martin Geisler
revset: all your error messages are belong to _
r11383 raise error.ParseError(_("limit expects a number"))
Matt Mackall
revset: introduce revset core
r11275 return getset(repo, subset, l[0])[:lim]
def children(repo, subset, x):
cs = set()
cl = repo.changelog
s = set(getset(repo, subset, 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 branch(repo, subset, x):
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 ancestor(repo, subset, x):
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
Matt Mackall
revset: fix ancestor subset handling (issue2298)
r11650 r = range(len(repo))
a = getset(repo, r, l[0])
b = getset(repo, r, l[1])
if len(a) != 1 or len(b) != 1:
Martin Geisler
revset: all your error messages are belong to _
r11383 raise error.ParseError(_("ancestor arguments must be single revisions"))
Matt Mackall
revset: fix ancestor subset handling (issue2298)
r11650 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
return [r for r in an if r in subset]
Matt Mackall
revset: introduce revset core
r11275
def ancestors(repo, subset, x):
args = getset(repo, range(len(repo)), x)
Matt Mackall
revset: deal with empty sets in range endpoints...
r11456 if not args:
return []
Matt Mackall
revset: introduce revset core
r11275 s = set(repo.changelog.ancestors(*args)) | set(args)
return [r for r in subset if r in s]
def descendants(repo, subset, x):
args = getset(repo, range(len(repo)), x)
Matt Mackall
revset: deal with empty sets in range endpoints...
r11456 if not args:
return []
Matt Mackall
revset: introduce revset core
r11275 s = set(repo.changelog.descendants(*args)) | set(args)
return [r for r in subset if r in s]
def follow(repo, subset, x):
Martin Geisler
revset: all your error messages are belong to _
r11383 getargs(x, 0, 0, _("follow takes no arguments"))
Matt Mackall
revset: introduce revset core
r11275 p = repo['.'].rev()
s = set(repo.changelog.ancestors(p)) | set([p])
return [r for r in subset if r in s]
def date(repo, subset, x):
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 ds = getstring(x, _("date requires a string"))
Matt Mackall
revset: introduce revset core
r11275 dm = util.matchdate(ds)
return [r for r in subset if dm(repo[r].date()[0])]
def keyword(repo, subset, x):
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 kw = getstring(x, _("keyword requires a string")).lower()
Matt Mackall
revset: introduce revset core
r11275 l = []
for r in subset:
c = repo[r]
t = " ".join(c.files() + [c.user(), c.description()])
if kw in t.lower():
l.append(r)
return l
def grep(repo, subset, x):
Brodie Rao
revset: handle re.compile() errors in grep()...
r12320 try:
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 gr = re.compile(getstring(x, _("grep requires a string")))
Brodie Rao
revset: handle re.compile() errors in grep()...
r12320 except re.error, e:
raise error.ParseError(_('invalid match pattern: %s') % e)
Matt Mackall
revset: introduce revset core
r11275 l = []
for r in subset:
c = repo[r]
for e in c.files() + [c.user(), c.description()]:
if gr.search(e):
l.append(r)
continue
return l
def author(repo, subset, x):
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 n = getstring(x, _("author requires a string")).lower()
Matt Mackall
revset: introduce revset core
r11275 return [r for r in subset if n in repo[r].user().lower()]
def hasfile(repo, subset, x):
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 pat = getstring(x, _("file requires a pattern"))
Martin Geisler
Consistently import foo as foomod when foo to avoid shadowing...
r12085 m = matchmod.match(repo.root, repo.getcwd(), [pat])
Matt Mackall
revset: introduce revset core
r11275 s = []
for r in subset:
for f in repo[r].files():
if m(f):
s.append(r)
continue
return s
def contains(repo, subset, x):
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 pat = getstring(x, _("contains requires a pattern"))
Martin Geisler
Consistently import foo as foomod when foo to avoid shadowing...
r12085 m = matchmod.match(repo.root, repo.getcwd(), [pat])
Matt Mackall
revset: introduce revset core
r11275 s = []
if m.files() == [pat]:
for r in subset:
if pat in repo[r]:
s.append(r)
continue
else:
for r in subset:
for f in repo[r].manifest():
if m(f):
s.append(r)
continue
return s
def checkstatus(repo, subset, pat, field):
Martin Geisler
Consistently import foo as foomod when foo to avoid shadowing...
r12085 m = matchmod.match(repo.root, repo.getcwd(), [pat])
Matt Mackall
revset: introduce revset core
r11275 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)
continue
else:
for f in files:
if m(f):
s.append(r)
continue
return s
def modifies(repo, subset, x):
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 pat = getstring(x, _("modifies requires a pattern"))
Matt Mackall
revset: introduce revset core
r11275 return checkstatus(repo, subset, pat, 0)
def adds(repo, subset, x):
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 pat = getstring(x, _("adds requires a pattern"))
Matt Mackall
revset: introduce revset core
r11275 return checkstatus(repo, subset, pat, 1)
def removes(repo, subset, x):
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)
def merge(repo, subset, x):
Martin Geisler
revset: all your error messages are belong to _
r11383 getargs(x, 0, 0, _("merge takes no arguments"))
Matt Mackall
revset: introduce revset core
r11275 cl = repo.changelog
return [r for r in subset if cl.parentrevs(r)[1] != -1]
def closed(repo, subset, x):
Martin Geisler
revset: all your error messages are belong to _
r11383 getargs(x, 0, 0, _("closed takes no arguments"))
Georg Brandl
revset: fix call to ctx.extra() in closed()
r11349 return [r for r in subset if repo[r].extra().get('close')]
Matt Mackall
revset: introduce revset core
r11275
def head(repo, subset, x):
Martin Geisler
revset: all your error messages are belong to _
r11383 getargs(x, 0, 0, _("head takes no arguments"))
Matt Mackall
revset: introduce revset core
r11275 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 reverse(repo, subset, x):
l = getset(repo, subset, x)
l.reverse()
return l
Wagner Bruna
revset: predicate to avoid lookup errors...
r11944 def present(repo, subset, x):
try:
return getset(repo, subset, x)
except error.RepoLookupError:
return []
Matt Mackall
revset: introduce revset core
r11275 def sort(repo, subset, x):
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]
def getall(repo, subset, x):
Martin Geisler
revset: all your error messages are belong to _
r11383 getargs(x, 0, 0, _("all takes no arguments"))
Matt Mackall
revset: introduce revset core
r11275 return subset
def heads(repo, subset, x):
s = getset(repo, subset, x)
ps = set(parents(repo, subset, x))
return [r for r in s if r not in ps]
def roots(repo, subset, x):
s = getset(repo, subset, x)
cs = set(children(repo, subset, x))
return [r for r in s if r not in cs]
def outgoing(repo, subset, x):
Matt Mackall
revset: delay import of hg to avoid start-up import loops
r11293 import hg # avoid start-up nasties
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
Matt Mackall
revset: introduce revset core
r11275 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
dest, branches = hg.parseurl(dest)
Adrian Buehlmann
revset: fix #branch in urls for outgoing()...
r12614 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
if revs:
revs = [repo.lookup(rev) for rev in revs]
Matt Mackall
revset: introduce revset core
r11275 other = hg.repository(hg.remoteui(repo, {}), dest)
repo.ui.pushbuffer()
Dirkjan Ochtman
move discovery methods from localrepo into new discovery module
r11301 o = discovery.findoutgoing(repo, other)
Matt Mackall
revset: introduce revset core
r11275 repo.ui.popbuffer()
cl = repo.changelog
Adrian Buehlmann
revset: fix #branch in urls for outgoing()...
r12614 o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, revs)[0]])
Matt Mackall
revset: introduce revset core
r11275 return [r for r in subset if r in o]
Augie Fackler
revset: rename tagged() to tag() and allow it to take an optional tag name
r12715 def tag(repo, subset, x):
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],
_('the argument to tag must be a string'))
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]
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,
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,
"descendants": descendants,
"file": hasfile,
"follow": follow,
"grep": grep,
"head": head,
"heads": heads,
Matt Mackall
revset: introduce revset core
r11275 "keyword": keyword,
Matt Mackall
revset: sort the predicate list
r11284 "limit": limit,
"max": maxrev,
Nicolas Dumazet
revset: add min function
r11708 "min": minrev,
Matt Mackall
revset: sort the predicate list
r11284 "merge": merge,
"modifies": modifies,
Augie Fackler
revset: add id() and rev() to allow explicitly referring to changes by hash or rev
r12716 "id": node,
Matt Mackall
revset: sort the predicate list
r11284 "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,
"reverse": reverse,
Augie Fackler
revset: add id() and rev() to allow explicitly referring to changes by hash or rev
r12716 "rev": rev,
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,
"tagged": tag,
Matt Mackall
revset: sort the predicate list
r11284 "user": author,
Matt Mackall
revset: introduce revset core
r11275 }
methods = {
"range": rangeset,
"string": stringset,
"symbol": symbolset,
"and": andset,
"or": orset,
"not": notset,
"list": listset,
"func": func,
}
Matt Mackall
revset: optimize the parse tree directly...
r11279 def optimize(x, small):
if x == None:
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])
Matt Mackall
revset: introduce revset core
r11275 elif op == 'group':
Matt Mackall
revset: optimize the parse tree directly...
r11279 return optimize(x[1], small)
elif op in 'range list':
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)
Matt Mackall
revsets: reduce cost of outgoing in the optimizer
r12351 if f in "grep date user author keyword branch file outgoing":
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
revset: introduce revset core
r11275 elif f == "reverse limit":
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
parse = parser.parser(tokenize, elements).parse
def match(spec):
Matt Mackall
revset: nicer exception for empty queries
r11385 if not spec:
raise error.ParseError(_("empty query"))
Matt Mackall
revset: introduce revset core
r11275 tree = parse(spec)
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