##// END OF EJS Templates
patch: unify iterhunks() afile/bfile handling...
patch: unify iterhunks() afile/bfile handling git afile/bfile are extracted twice, once when reading a 'diff --git', and again when reading a unified hunk. The problem is not all git blocks have unified hunks (renames just have metadata) and they were not extracted the same way. This is what this patch unifies.

File last commit:

r14357:cb4ff8ef merge default
r14386:c2ef8cc5 default
Show More
revset.py
1029 lines | 30.6 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
Matt Mackall
help: consolidate topic hooks in help.py...
r14318 import parser, util, error, discovery, hbisect
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 _
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])
except ValueError:
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
n = getstring(x, _("author requires a string")).lower()
return [r for r in subset if n in repo[r].user().lower()]
def bisected(repo, subset, x):
"""``bisected(string)``
Changesets marked in the specified bisect state (good, bad, skip).
"""
state = getstring(x, _("bisect requires a string")).lower()
if state not in ('good', 'bad', 'skip', 'unknown'):
Brodie Rao
revset: fix undefined name ParseError
r14057 raise error.ParseError(_('invalid bisect state'))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 marked = set(repo.changelog.rev(n) for n in hbisect.load_state(repo)[state])
return [r for r in subset if r in marked]
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])]
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]
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:
x = getstring(l[0], "follow expected a filename")
s = set(ctx.rev() for ctx in repo['.'][x].ancestors())
else:
s = set(repo.changelog.ancestors(p))
s |= set([p])
return [r for r in subset if r in s]
def followfile(repo, subset, f):
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
kw = getstring(x, _("keyword requires a string")).lower()
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 limit(repo, subset, x):
"""``limit(set, n)``
First n members of set.
"""
# i18n: "limit" is a keyword
l = getargs(x, 2, 2, _("limit requires two arguments"))
try:
# i18n: "limit" is a keyword
lim = int(getstring(l[1], _("limit requires a number")))
except ValueError:
# 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):
"""``last(set, n)``
Last n members of set.
"""
# i18n: "last" is a keyword
l = getargs(x, 2, 2, _("last requires two arguments"))
try:
# i18n: "last" is a keyword
lim = int(getstring(l[1], _("last requires a number")))
except ValueError:
# 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
l = getargs(x, 0, 1, _("outgoing requires a repository path"))
# 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]
other = hg.repository(hg.remoteui(repo, {}), dest)
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
except ValueError:
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")))
except ValueError:
# 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,
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,
"descendants": descendants,
"file": hasfile,
Matt Mackall
revset: introduce filelog() to emulate log's fast path...
r14342 "filelog": filelog,
Matt Mackall
revset: sort the predicate list
r11284 "follow": follow,
"grep": grep,
"head": head,
"heads": heads,
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,
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,
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
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)
Matt Mackall
revset: teach optimizer that closed is slowish
r13873 if f in "grep date user author keyword branch file outgoing closed":
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
Mads Kiilerich
revset: fix typo when assigning weight to reverse and limit
r13506 elif f in "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
Alexander Solovyov
revset aliases
r14098 class revsetalias(object):
funcre = re.compile('^([^(]+)\(([^)]+)\)$')
args = ()
def __init__(self, token, value):
'''Aliases like:
h = heads(default)
b($1) = ancestors($1) - ancestors(default)
'''
if isinstance(token, tuple):
self.type, self.name = token
else:
m = self.funcre.search(token)
if m:
self.type = 'func'
self.name = m.group(1)
self.args = [x.strip() for x in m.group(2).split(',')]
else:
self.type = 'symbol'
self.name = token
if isinstance(value, str):
for arg in self.args:
value = value.replace(arg, repr(arg))
self.replacement, pos = parse(value)
if pos != len(value):
raise error.ParseError('invalid token', pos)
else:
self.replacement = value
def match(self, tree):
if not tree:
return False
if tree == (self.type, self.name):
return True
if tree[0] != self.type:
return False
if len(tree) > 1 and tree[1] != ('symbol', self.name):
return False
# 'func' + funcname + args
if ((self.args and len(tree) != 3) or
(len(self.args) == 1 and tree[2][0] == 'list') or
(len(self.args) > 1 and (tree[2][0] != 'list' or
len(tree[2]) - 1 != len(self.args)))):
raise error.ParseError('invalid amount of arguments', len(tree) - 2)
return True
def replace(self, tree):
if tree == (self.type, self.name):
return self.replacement
result = self.replacement
def getsubtree(i):
if tree[2][0] == 'list':
return tree[2][i + 1]
return tree[i + 2]
for i, v in enumerate(self.args):
valalias = revsetalias(('string', v), getsubtree(i))
result = valalias.process(result)
return result
def process(self, tree):
if self.match(tree):
return self.replace(tree)
if isinstance(tree, tuple):
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)
r13665 tree, pos = parse(spec)
if (pos != len(spec)):
raise error.ParseError("invalid token", pos)
Alexander Solovyov
revset aliases
r14098 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
Patrick Mezard
hggettext: handle i18nfunctions declaration for docstrings translations
r12823 # tell hggettext to extract docstrings from these functions:
i18nfunctions = symbols.values()