##// END OF EJS Templates
subrepo: backout 519ac79d680b...
subrepo: backout 519ac79d680b Unfortunately git 1.6 does not support the upstream parameter in for-each-ref.

File last commit:

r13031:3da456d0 default
r13178:c4d857f5 default
Show More
revset.py
813 lines | 23.5 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
Wagner Bruna
i18n: translate revset predicate docstrings
r12855 from i18n import _, gettext
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):
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]
def rev(repo, subset, x):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``rev(number)``
Revision with the given numeric identifier.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "rev" is a keyword
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:
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "rev" is a keyword
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:
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "rev" is a keyword
Augie Fackler
revset: add id() and rev() to allow explicitly referring to changes by hash or rev
r12716 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):
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:
Patrick Mezard
revset: fix p1, p2 and parents in dirstate case (a5f7f1e9340e)...
r12935 p = repo[x].parents()[0].rev()
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]
def maxrev(repo, subset, x):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``max(set)``
Changeset with highest revision number in set.
"""
Matt Mackall
revset: introduce revset core
r11275 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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``min(set)``
Changeset with lowest revision number in set.
"""
Nicolas Dumazet
revset: add min function
r11708 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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``limit(set, n)``
First n members of set.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "limit" is a keyword
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:
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "limit" is a keyword
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: add translator comments to i18n strings
r12815 # i18n: "limit" is a keyword
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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``children(set)``
Child changesets of changesets in set.
"""
Matt Mackall
revset: introduce revset core
r11275 cs = set()
cl = repo.changelog
Wagner Bruna
revset: disable subset optimization for parents() and children() (issue2437)...
r12786 s = set(getset(repo, range(len(repo)), x))
Matt Mackall
revset: introduce revset core
r11275 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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``branch(set)``
All changesets belonging to the branches of changesets in set.
"""
Matt Mackall
revset: introduce revset core
r11275 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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``ancestor(single, single)``
Greatest common ancestor of the two changesets.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "ancestor" is a keyword
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: add translator comments to i18n strings
r12815 # i18n: "ancestor" is a keyword
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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``ancestors(set)``
Changesets that are ancestors of a changeset in set.
"""
Matt Mackall
revset: introduce revset core
r11275 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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``descendants(set)``
Changesets which are descendants of changesets in set.
"""
Matt Mackall
revset: introduce revset core
r11275 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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``follow()``
An alias for ``::.`` (ancestors of the working copy's first parent).
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "follow" is a keyword
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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``date(interval)``
Changesets within the interval, see :hg:`help dates`.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "date" is a keyword
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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``keyword(string)``
Search commit message, user name, and names of changed files for
string.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "keyword" is a keyword
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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``grep(regex)``
Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
to ensure special escape characters are handled correctly.
"""
Brodie Rao
revset: handle re.compile() errors in grep()...
r12320 try:
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "grep" is a keyword
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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``author(string)``
Alias for ``user(string)``.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "author" is a keyword
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()]
Patrick Mezard
revsets: generate predicate help dynamically
r12821 def user(repo, subset, x):
"""``user(string)``
User name is string.
"""
return author(repo, subset, x)
Matt Mackall
revset: introduce revset core
r11275 def hasfile(repo, subset, x):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``file(pattern)``
Changesets affecting files matched by pattern.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "file" is a keyword
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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``contains(pattern)``
Revision contains pattern.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "contains" is a keyword
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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``modifies(pattern)``
Changesets modifying files matched by pattern.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "modifies" is a keyword
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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``adds(pattern)``
Changesets that add a file matching pattern.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "adds" is a keyword
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):
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)
def merge(repo, subset, x):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``merge()``
Changeset is a merge changeset.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "merge" is a keyword
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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``closed()``
Changeset is closed.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "closed" is a keyword
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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``head()``
Changeset is a named branch head.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "head" is a keyword
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):
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
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 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]
def getall(repo, subset, x):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``all()``
All changesets, the same as ``0:tip``.
"""
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "all" is a keyword
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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``heads(set)``
Members of set with no children in set.
"""
Matt Mackall
revset: introduce revset core
r11275 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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``roots(set)``
Changesets with no parent changeset in set.
"""
Matt Mackall
revset: introduce revset core
r11275 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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``outgoing([path])``
Changesets not found in the specified destination repository, or the
default push location.
"""
Matt Mackall
revset: delay import of hg to avoid start-up import loops
r11293 import hg # avoid start-up nasties
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "outgoing" is a keyword
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "outgoing" is a keyword
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 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):
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """``tag(name)``
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'))
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)
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,
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,
}
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])
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
Patrick Mezard
revsets: generate predicate help dynamically
r12821
def makedoc(topic, doc):
"""Generate and include predicates help in revsets topic."""
predicates = []
for name in sorted(symbols):
text = symbols[name].__doc__
if not text:
continue
Wagner Bruna
i18n: translate revset predicate docstrings
r12855 text = gettext(text.rstrip())
Patrick Mezard
revsets: generate predicate help dynamically
r12821 lines = text.splitlines()
lines[1:] = [(' ' + l.strip()) for l in lines[1:]]
predicates.append('\n'.join(lines))
Wagner Bruna
i18n: translate revset predicate docstrings
r12855 predicates = '\n\n'.join(predicates)
Patrick Mezard
revsets: generate predicate help dynamically
r12821 doc = doc.replace('.. predicatesmarker', predicates)
return doc
Patrick Mezard
hggettext: handle i18nfunctions declaration for docstrings translations
r12823
# tell hggettext to extract docstrings from these functions:
i18nfunctions = symbols.values()