##// END OF EJS Templates
baseset: implement a fastasc and fastdesc...
baseset: implement a fastasc and fastdesc Baseset contains already-computed revisions. It is considered "cheap" to do operations on an already-computed set. So we add attributes to hold version of the list in ascending and descending order and use them for `fastasc` and `fastdesc`. Having distinct lists is important to provide correct iteration in all cases. Altering a python list will impact an iterator connected to it. eg: not preserving order at iterator creation time >>> l = [0, 1] >>> i = iter(l) >>> l.reverse() >>> list(i) [1, 0] eg: corrupting in progress iteration >>> l = [0, 1] >>> i = iter(l) >>> i.next() 0 >>> l.reverse() >>> i.next() 0

File last commit:

r22826:4ffb327e default
r22826:4ffb327e default
Show More
revset.py
3017 lines | 92.1 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.
Bryan O'Sullivan
util: subclass deque for Python 2.4 backwards compatibility...
r16834 import re
Pierre-Yves David
phases: implements simple revset symbol...
r15819 import parser, util, error, discovery, hbisect, phases
Matt Mackall
revset: avoid demandimport bug...
r16417 import node
Lucas Moscovicz
revset: changed ancestors revset to return lazy generators...
r20690 import heapq
Martin Geisler
Consistently import foo as foomod when foo to avoid shadowing...
r12085 import match as matchmod
Durham Goode
revset: add 'only' revset...
r20613 import ancestor as ancestormod
Patrick Mezard
help: extract items doc generation function
r13593 from i18n import _
FUJIWARA Katsunori
i18n: use "encoding.lower()" to normalize specified string for revset...
r15726 import encoding
Pierre-Yves David
obsolete: introduce caches for all meaningful sets...
r17469 import obsolete as obsmod
FUJIWARA Katsunori
revset: make default kind of pattern for "contains()" rooted at cwd...
r20286 import pathutil
Pierre-Yves David
revset: retrieve hidden from filteredrevs...
r18251 import repoview
Matt Mackall
revset: introduce revset core
r11275
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 def _revancestors(repo, revs, followfirst):
"""Like revlog.ancestors(), but supports followfirst."""
cut = followfirst and 1 or None
cl = repo.changelog
Lucas Moscovicz
revset: changed ancestors revset to return lazy generators...
r20690
def iterate():
Lucas Moscovicz
revset: optimized _revancestors method based on order of revisions...
r20691 revqueue, revsnode = None, None
h = []
revs.descending()
revqueue = util.deque(revs)
if revqueue:
revsnode = revqueue.popleft()
heapq.heappush(h, -revsnode)
seen = set([node.nullrev])
Lucas Moscovicz
revset: changed ancestors revset to return lazy generators...
r20690 while h:
current = -heapq.heappop(h)
if current not in seen:
Lucas Moscovicz
revset: optimized _revancestors method based on order of revisions...
r20691 if revsnode and current == revsnode:
if revqueue:
revsnode = revqueue.popleft()
heapq.heappush(h, -revsnode)
Lucas Moscovicz
revset: changed ancestors revset to return lazy generators...
r20690 seen.add(current)
yield current
for parent in cl.parentrevs(current)[:cut]:
if parent != node.nullrev:
heapq.heappush(h, -parent)
Pierre-Yves David
generatorset: drop the leading underscore in the class name...
r22795 return generatorset(iterate(), iterasc=False)
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409
def _revdescendants(repo, revs, followfirst):
"""Like revlog.descendants() but supports followfirst."""
cut = followfirst and 1 or None
Lucas Moscovicz
revset: changed descendants revset to use lazy generators...
r20692 def iterate():
cl = repo.changelog
first = min(revs)
nullrev = node.nullrev
if first == nullrev:
# Are there nodes with a null first parent and a non-null
# second one? Maybe. Do we care? Probably not.
for i in cl:
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 yield i
Lucas Moscovicz
revset: changed descendants revset to use lazy generators...
r20692 else:
seen = set(revs)
for i in cl.revs(first + 1):
for x in cl.parentrevs(i)[:cut]:
if x != nullrev and x in seen:
seen.add(i)
yield i
break
Pierre-Yves David
generatorset: drop the leading underscore in the class name...
r22795 return generatorset(iterate(), iterasc=True)
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409
Bryan O'Sullivan
revset: introduce and use _revsbetween...
r16862 def _revsbetween(repo, roots, heads):
"""Return all paths between roots and heads, inclusive of both endpoint
sets."""
if not roots:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Bryan O'Sullivan
revset: introduce and use _revsbetween...
r16862 parentrevs = repo.changelog.parentrevs
Pierre-Yves David
revset: stop using a baseset instead of a plain list in _revsbetween...
r22487 visit = list(heads)
Bryan O'Sullivan
revset: introduce and use _revsbetween...
r16862 reachable = set()
seen = {}
minroot = min(roots)
roots = set(roots)
# open-code the post-order traversal due to the tiny size of
# sys.getrecursionlimit()
while visit:
rev = visit.pop()
if rev in roots:
reachable.add(rev)
parents = parentrevs(rev)
seen[rev] = parents
for parent in parents:
if parent >= minroot and parent not in seen:
visit.append(parent)
if not reachable:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Bryan O'Sullivan
revset: introduce and use _revsbetween...
r16862 for rev in sorted(seen):
for parent in seen[rev]:
if parent in reachable:
reachable.add(rev)
Lucas Moscovicz
revset: added baseset class (still empty) to improve revset performance...
r20364 return baseset(sorted(reachable))
Bryan O'Sullivan
revset: introduce and use _revsbetween...
r16862
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'])
Matt Mackall
revset: pass a lookup function to the tokenizer
r20779 def tokenize(program, lookup=None):
Matt Mackall
revset: accept @ in unquoted symbols (issue3686)
r17886 '''
Parse a revset statement into a stream of tokens
Check that @ is a valid unquoted token character (issue3686):
>>> list(tokenize("@::"))
[('symbol', '@', 0), ('::', None, 1), ('end', None, 3)]
'''
Matt Mackall
revset: introduce revset core
r11275 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)
Brodie Rao
cleanup: eradicate long lines
r16683 # gather up a symbol/keyword
Matt Mackall
revset: accept @ in unquoted symbols (issue3686)
r17886 elif c.isalnum() or c in '._@' or ord(c) > 127:
Matt Mackall
revset: introduce revset core
r11275 s = pos
pos += 1
while pos < l: # find end of symbol
d = program[pos]
Matt Mackall
revset: try to handle hyphenated symbols if lookup callback is available...
r20780 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: try to handle hyphenated symbols if lookup callback is available...
r20780 elif '-' in sym:
# some jerk gave us foo-bar-baz, try to check if it's a symbol
if lookup and lookup(sym):
# looks like a real symbol
yield ('symbol', sym, s)
else:
# looks like an expression
parts = sym.split('-')
for p in parts[:-1]:
if p: # possible consecutive -
yield ('symbol', p, s)
s += len(p)
yield ('-', None, pos)
s += 1
if parts[-1]: # possible trailing -
yield ('symbol', parts[-1], 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)
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 if len(l) < min or (max >= 0 and 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"))
Lucas Moscovicz
revset: changed mfunc and getset to work with old style revset methods...
r20527 s = methods[x[0]](repo, subset, *x[1:])
if util.safehasattr(s, 'set'):
return s
return baseset(s)
Matt Mackall
revset: introduce revset core
r11275
Matt Harbison
revset: add a utility for obtaining the source of a given rev...
r17003 def _getrevsource(repo, r):
extra = repo[r].extra()
for label in ('source', 'transplant_source', 'rebase_source'):
if label in extra:
try:
return repo[extra[label]].rev()
except error.RepoLookupError:
pass
return None
Matt Mackall
revset: introduce revset core
r11275 # 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):
Lucas Moscovicz
revset: added baseset class (still empty) to improve revset performance...
r20364 return baseset([-1])
Idan Kamara
revset: optimize stringset when subset == entire repo...
r13938 if len(subset) == len(repo) or x in subset:
Lucas Moscovicz
revset: added baseset class (still empty) to improve revset performance...
r20364 return baseset([x])
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Matt Mackall
revset: introduce revset core
r11275
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):
Lucas Moscovicz
revset: added baseset class (still empty) to improve revset performance...
r20364 cl = baseset(repo.changelog)
FUJIWARA Katsunori
revset: evaluate sub expressions correctly (issue3775)...
r18473 m = getset(repo, cl, x)
n = getset(repo, cl, y)
Matt Mackall
revset: deal with empty sets in range endpoints...
r11456
if not m or not n:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Pierre-Yves David
rangeset: use `first` and `last` instead of direct indexing...
r22817 m, n = m.first(), n.last()
Matt Mackall
revset: deal with empty sets in range endpoints...
r11456
Matt Mackall
revset: introduce revset core
r11275 if m < n:
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 r = spanset(repo, m, n + 1)
Matt Mackall
revset: deal with empty sets in range endpoints...
r11456 else:
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 r = spanset(repo, m, n - 1)
return r & subset
Matt Mackall
revset: introduce revset core
r11275
Bryan O'Sullivan
revset: turn dagrange into a function
r16860 def dagrange(repo, subset, x, y):
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 r = spanset(repo)
Alexander Plavin
log: fix behavior with empty repositories (issue3497)...
r18991 xs = _revsbetween(repo, getset(repo, r, x), getset(repo, r, y))
Lucas Moscovicz
revset: implemented set caching for revset evaluation...
r20365 s = subset.set()
Pierre-Yves David
revset: directly use __contains__ instead of a lambda...
r21217 return xs.filter(s.__contains__)
Bryan O'Sullivan
revset: turn dagrange into a function
r16860
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)
Lucas Moscovicz
revset: added substraction to baseset class...
r20366 yl = getset(repo, subset - xl, y)
Augie Fackler
revsets: preserve ordering with the or operator...
r13932 return xl + yl
Matt Mackall
revset: introduce revset core
r11275
def notset(repo, subset, x):
Lucas Moscovicz
revset: added substraction to baseset class...
r20366 return subset - getset(repo, subset, x)
Matt Mackall
revset: introduce revset core
r11275
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.
FUJIWARA Katsunori
revset: add explanation about the pattern without explicit kind...
r20289
The pattern without explicit kind like ``glob:`` is expected to be
relative to the current directory and match against a file or a
directory.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# i18n: "adds" is a keyword
pat = getstring(x, _("adds requires a pattern"))
return checkstatus(repo, subset, pat, 1)
def ancestor(repo, subset, x):
Paul Cavallaro
revset: change ancestor to accept 0 or more arguments (issue3750)...
r18536 """``ancestor(*changeset)``
Mads Kiilerich
revlog: use context ancestor instead of changelog ancestor...
r20991 A greatest common ancestor of the changesets.
Paul Cavallaro
revset: change ancestor to accept 0 or more arguments (issue3750)...
r18536
Accepts 0 or more changesets.
Will return empty list when passed no args.
Greatest common ancestor of a single changeset is that changeset.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# i18n: "ancestor" is a keyword
Paul Cavallaro
revset: change ancestor to accept 0 or more arguments (issue3750)...
r18536 l = getlist(x)
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 rl = spanset(repo)
Paul Cavallaro
revset: change ancestor to accept 0 or more arguments (issue3750)...
r18536 anc = None
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Paul Cavallaro
revset: change ancestor to accept 0 or more arguments (issue3750)...
r18536 # (getset(repo, rl, i) for i in l) generates a list of lists
for revs in (getset(repo, rl, i) for i in l):
for r in revs:
if anc is None:
Mads Kiilerich
revlog: use context ancestor instead of changelog ancestor...
r20991 anc = repo[r]
Paul Cavallaro
revset: change ancestor to accept 0 or more arguments (issue3750)...
r18536 else:
Mads Kiilerich
revlog: use context ancestor instead of changelog ancestor...
r20991 anc = anc.ancestor(repo[r])
if anc is not None and anc.rev() in subset:
return baseset([anc.rev()])
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 def _ancestors(repo, subset, x, followfirst=False):
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 args = getset(repo, spanset(repo), x)
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 if not args:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Lucas Moscovicz
revset: changed ancestors revset to return lazy generators...
r20690 s = _revancestors(repo, args, followfirst)
Pierre-Yves David
revset: directly use __contains__ instead of a lambda...
r21217 return subset.filter(s.__contains__)
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def ancestors(repo, subset, x):
"""``ancestors(set)``
Changesets that are ancestors of a changeset in set.
"""
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 return _ancestors(repo, subset, x)
def _firstancestors(repo, subset, x):
# ``_firstancestors(set)``
# Like ``ancestors(set)`` but follows only the first parents.
return _ancestors(repo, subset, x, followfirst=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 def ancestorspec(repo, subset, x, n):
"""``set~n``
Brodie Rao
cleanup: eradicate long lines
r16683 Changesets that are the Nth ancestor (first parents only) of a changeset
in set.
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 """
try:
n = int(n[1])
Matt Mackall
revsets: actually catch type error on tip^p1(tip) (issue2884)...
r14851 except (TypeError, ValueError):
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 raise error.ParseError(_("~ expects a number"))
ps = set()
cl = repo.changelog
Lucas Moscovicz
revset: minor changes adding baseset to revsets...
r20424 for r in getset(repo, baseset(cl), x):
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 for i in range(n):
r = cl.parentrevs(r)[0]
ps.add(r)
Pierre-Yves David
revset: use `subset &` in `ancestorspec`...
r22531 return subset & ps
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def author(repo, subset, x):
"""``author(string)``
Alias for ``user(string)``.
"""
# i18n: "author" is a keyword
FUJIWARA Katsunori
i18n: use "encoding.lower()" to normalize specified string for revset...
r15726 n = encoding.lower(getstring(x, _("author requires a string")))
Simon King
revset: add pattern matching to the 'user' revset expression
r16823 kind, pattern, matcher = _substringmatcher(n)
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(lambda x: matcher(encoding.lower(repo[x].user())))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Durham Goode
revset: add 'only' revset...
r20613 def only(repo, subset, x):
"""``only(set, [set])``
Changesets that are ancestors of the first set that are not ancestors
of any other head in the repo. If a second set is specified, the result
is ancestors of the first set that are not ancestors of the second set
(i.e. ::<set1> - ::<set2>).
"""
cl = repo.changelog
Wagner Bruna
revset, i18n: add translator comment to "only"
r21173 # i18n: "only" is a keyword
Durham Goode
revset: add 'only' revset...
r20613 args = getargs(x, 1, 2, _('only takes one or two arguments'))
include = getset(repo, spanset(repo), args[0]).set()
if len(args) == 1:
Matt Harbison
revset: avoid a ValueError when 'only()' is given an empty set...
r21925 if len(include) == 0:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Matt Harbison
revset: avoid a ValueError when 'only()' is given an empty set...
r21925
Durham Goode
revset: add 'only' revset...
r20613 descendants = set(_revdescendants(repo, include, False))
exclude = [rev for rev in cl.headrevs()
if not rev in descendants and not rev in include]
else:
exclude = getset(repo, spanset(repo), args[1])
results = set(ancestormod.missingancestors(include, exclude, cl.parentrevs))
Pierre-Yves David
lazyset: rename the class to filteredset...
r22726 return filteredset(subset, results.__contains__)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
"Yann E. MORIN"
revset: rename bisected() to bisect()...
r15134 def bisect(repo, subset, x):
"""``bisect(string)``
"Yann E. MORIN"
hbisect: add two new revset descriptions: 'goods' and 'bads'...
r15153 Changesets marked in the specified bisect status:
"Yann E. MORIN"
revset.bisect: add new 'range' set to the bisect keyword...
r15136
"Yann E. MORIN"
hbisect: add two new revset descriptions: 'goods' and 'bads'...
r15153 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip
Mads Kiilerich
fix trivial spelling errors
r17424 - ``goods``, ``bads`` : csets topologically good/bad
"Yann E. MORIN"
hbisect: add two new revset descriptions: 'goods' and 'bads'...
r15153 - ``range`` : csets taking part in the bisection
- ``pruned`` : csets that are goods, bads or skipped
- ``untested`` : csets whose fate is yet unknown
- ``ignored`` : csets ignored due to DAG topology
Bryan O'Sullivan
bisect: track the current changeset (issue3382)...
r16647 - ``current`` : the cset currently being bisected
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "bisect" is a keyword
"Yann E. MORIN"
revset.bisect: move bisect() code to hbisect.py...
r15135 status = getstring(x, _("bisect requires a string")).lower()
Bryan O'Sullivan
revset: fix O(n**2) behaviour of bisect() (issue3381)
r16467 state = set(hbisect.get(repo, status))
Pierre-Yves David
revset: use `subset &` in `bisect`...
r22532 return subset & state
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
"Yann E. MORIN"
revset: rename bisected() to bisect()...
r15134 # Backward-compatibility
# - no help entry so that we do not advertise it any more
def bisected(repo, subset, x):
return bisect(repo, subset, x)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def bookmark(repo, subset, x):
"""``bookmark([name])``
The named bookmark or all bookmarks.
Simon King
revset: add pattern matching to 'bookmarks' revset expression
r16822
If `name` starts with `re:`, the remainder of the name is treated as
a regular expression. To match a bookmark that actually starts with `re:`,
use the prefix `literal:`.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# 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'))
Simon King
revset: add pattern matching to 'bookmarks' revset expression
r16822 kind, pattern, matcher = _stringmatcher(bm)
Pierre-Yves David
revset: unify code flow in `bookmark`...
r22499 bms = set()
Simon King
revset: add pattern matching to 'bookmarks' revset expression
r16822 if kind == 'literal':
Michael O'Connor
revset: bookmark revset interprets 'literal:' prefix correctly (issue4329)
r22105 bmrev = repo._bookmarks.get(pattern, None)
Simon King
revset: add pattern matching to 'bookmarks' revset expression
r16822 if not bmrev:
raise util.Abort(_("bookmark '%s' does not exist") % bm)
Pierre-Yves David
revset: unify code flow in `bookmark`...
r22499 bms.add(repo[bmrev].rev())
Simon King
revset: add pattern matching to 'bookmarks' revset expression
r16822 else:
matchrevs = set()
Kevin Bullock
bookmarks: don't use bookmarks.listbookmarks in local computations...
r18495 for name, bmrev in repo._bookmarks.iteritems():
Simon King
revset: add pattern matching to 'bookmarks' revset expression
r16822 if matcher(name):
matchrevs.add(bmrev)
if not matchrevs:
raise util.Abort(_("no bookmarks exist that match '%s'")
% pattern)
for bmrev in matchrevs:
Pierre-Yves David
revset: unify code flow in `bookmark`...
r22499 bms.add(repo[bmrev].rev())
else:
bms = set([repo[r].rev()
for r in repo._bookmarks.values()])
Pierre-Yves David
revset: remove nullrev from the bookmark computation...
r22500 bms -= set([node.nullrev])
Pierre-Yves David
revset: use `subset &` in `bookmark`...
r22530 return subset & bms
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
def branch(repo, subset, x):
"""``branch(string or set)``
All changesets belonging to the given branch or the branches of the given
changesets.
Simon King
revset: add pattern matching to 'branch' revset expression
r16821
If `string` starts with `re:`, the remainder of the name is treated as
a regular expression. To match a branch that actually starts with `re:`,
use the prefix `literal:`.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
try:
b = getstring(x, '')
except error.ParseError:
# not a string, but another revspec, e.g. tip()
pass
Simon King
revset: add pattern matching to 'branch' revset expression
r16821 else:
kind, pattern, matcher = _stringmatcher(b)
if kind == 'literal':
# note: falls through to the revspec case if no branch with
# this name exists
if pattern in repo.branchmap():
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(lambda r: matcher(repo[r].branch()))
Simon King
revset: add pattern matching to 'branch' revset expression
r16821 else:
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(lambda r: matcher(repo[r].branch()))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 s = getset(repo, spanset(repo), x)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 b = set()
for r in s:
b.add(repo[r].branch())
Lucas Moscovicz
revset: implemented set caching for revset evaluation...
r20365 s = s.set()
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(lambda r: r in s or repo[r].branch() in b)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Pierre-Yves David
revset: add a bumped revset...
r17829 def bumped(repo, subset, x):
"""``bumped()``
Mutable changesets marked as successors of public changesets.
Only non-public and non-obsolete changesets can be `bumped`.
"""
# i18n: "bumped" is a keyword
getargs(x, 0, 0, _("bumped takes no arguments"))
bumped = obsmod.getrevs(repo, 'bumped')
Lucas Moscovicz
revset: added intersection to baseset class...
r20367 return subset & bumped
Pierre-Yves David
revset: add a bumped revset...
r17829
Tomasz Kleczek
bundle: add revset expression to show bundle contents (issue3487)...
r17913 def bundle(repo, subset, x):
"""``bundle()``
Changesets in the bundle.
Bundle must be specified by the -R option."""
try:
Mads Kiilerich
bundlerepo: improve performance for bundle() revset expression...
r18411 bundlerevs = repo.changelog.bundlerevs
Tomasz Kleczek
bundle: add revset expression to show bundle contents (issue3487)...
r17913 except AttributeError:
raise util.Abort(_("no bundle provided - specify with -R"))
Lucas Moscovicz
revset: added intersection to baseset class...
r20367 return subset & bundlerevs
Tomasz Kleczek
bundle: add revset expression to show bundle contents (issue3487)...
r17913
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def checkstatus(repo, subset, pat, field):
Patrick Mezard
revset: fix adds/modifies/removes and patterns (issue3403)...
r16521 hasset = matchmod.patkind(pat) == 'set'
Lucas Moscovicz
revset: added lazyset implementation to checkstatus...
r20457
def matches(x):
m = None
fname = None
c = repo[x]
Patrick Mezard
revset: fix adds/modifies/removes and patterns (issue3403)...
r16521 if not m or hasset:
m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
if not m.anypats() and len(m.files()) == 1:
fname = m.files()[0]
if fname is not None:
if fname not in c.files():
Lucas Moscovicz
revset: added lazyset implementation to checkstatus...
r20457 return False
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 else:
for f in c.files():
if m(f):
break
else:
Lucas Moscovicz
revset: added lazyset implementation to checkstatus...
r20457 return False
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 files = repo.status(c.p1().node(), c.node())[field]
Patrick Mezard
revset: fix adds/modifies/removes and patterns (issue3403)...
r16521 if fname is not None:
if fname in files:
Lucas Moscovicz
revset: added lazyset implementation to checkstatus...
r20457 return True
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 else:
for f in files:
if m(f):
Lucas Moscovicz
revset: added lazyset implementation to checkstatus...
r20457 return True
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(matches)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Patrick Mezard
revset: avoid set duplication in roots()
r16396 def _children(repo, narrow, parentset):
Matt Mackall
revset: optimize roots and children
r15899 cs = set()
Siddharth Agarwal
revset.children: ignore rev numbers that are too low...
r18063 if not parentset:
Matt Mackall
revsets: backout d04aac468bf4 due to performance regressions
r20709 return baseset(cs)
Matt Mackall
revset: optimize roots and children
r15899 pr = repo.changelog.parentrevs
Siddharth Agarwal
revset.children: ignore rev numbers that are too low...
r18063 minrev = min(parentset)
Patrick Mezard
revset: do not ignore input revisions in roots()...
r16394 for r in narrow:
Siddharth Agarwal
revset.children: ignore rev numbers that are too low...
r18063 if r <= minrev:
continue
Matt Mackall
revset: optimize roots and children
r15899 for p in pr(r):
Patrick Mezard
revset: avoid set duplication in roots()
r16396 if p in parentset:
Matt Mackall
revset: optimize roots and children
r15899 cs.add(r)
Matt Mackall
revsets: backout d04aac468bf4 due to performance regressions
r20709 return baseset(cs)
Matt Mackall
revset: optimize roots and children
r15899
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def children(repo, subset, x):
"""``children(set)``
Child changesets of changesets in set.
"""
Lucas Moscovicz
revset: implemented set caching for revset evaluation...
r20365 s = getset(repo, baseset(repo), x).set()
Matt Mackall
revset: optimize roots and children
r15899 cs = _children(repo, subset, s)
Lucas Moscovicz
revset: added intersection to baseset class...
r20367 return subset & cs
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
def closed(repo, subset, x):
"""``closed()``
Changeset is closed.
"""
# i18n: "closed" is a keyword
getargs(x, 0, 0, _("closed takes no arguments"))
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(lambda r: repo[r].closesbranch())
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
def contains(repo, subset, x):
"""``contains(pattern)``
Greg Hurrell
help: clarify distinction among `contains`/`file`/`filelog`...
r21199 The revision's manifest contains a file matching pattern (but might not
modify it). See :hg:`help patterns` for information about file patterns.
FUJIWARA Katsunori
revset: add explanation about the pattern without explicit kind...
r20289
The pattern without explicit kind like ``glob:`` is expected to be
relative to the current directory and match against a file exactly
for efficiency.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# i18n: "contains" is a keyword
pat = getstring(x, _("contains requires a pattern"))
Lucas Moscovicz
revset: added lazyset implementation to contains revset
r20461
def matches(x):
if not matchmod.patkind(pat):
pats = pathutil.canonpath(repo.root, repo.getcwd(), pat)
if pats in repo[x]:
return True
else:
c = repo[x]
m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
Matt Mackall
revsets: provide contexts for filesets...
r15964 for f in c.manifest():
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 if m(f):
Lucas Moscovicz
revset: added lazyset implementation to contains revset
r20461 return True
return False
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(matches)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Matt Harbison
revset: add a predicate for finding converted changesets...
r17002 def converted(repo, subset, x):
"""``converted([id])``
Changesets converted from the given identifier in the old repository if
present, or all converted changesets if no identifier is specified.
"""
# There is exactly no chance of resolving the revision, so do a simple
# string compare and hope for the best
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 rev = None
Matt Harbison
revset: add a predicate for finding converted changesets...
r17002 # i18n: "converted" is a keyword
l = getargs(x, 0, 1, _('converted takes one or no arguments'))
if l:
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "converted" is a keyword
Matt Harbison
revset: add a predicate for finding converted changesets...
r17002 rev = getstring(l[0], _('converted requires a revision'))
def _matchvalue(r):
source = repo[r].extra().get('convert_revision', None)
return source is not None and (rev is None or source.startswith(rev))
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(lambda r: _matchvalue(r))
Matt Harbison
revset: add a predicate for finding converted changesets...
r17002
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 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)
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(lambda x: dm(repo[x].date()[0]))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Thomas Arendsen Hein
revset: add desc(string) to search in commit messages...
r14650 def desc(repo, subset, x):
"""``desc(string)``
Search commit message for string. The match is case-insensitive.
"""
# i18n: "desc" is a keyword
FUJIWARA Katsunori
i18n: use "encoding.lower()" to normalize specified string for revset...
r15726 ds = encoding.lower(getstring(x, _("desc requires a string")))
Lucas Moscovicz
revset: added lazyset implementation to desc revset...
r20452
def matches(x):
c = repo[x]
return ds in encoding.lower(c.description())
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(matches)
Thomas Arendsen Hein
revset: add desc(string) to search in commit messages...
r14650
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 def _descendants(repo, subset, x, followfirst=False):
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 args = getset(repo, spanset(repo), x)
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 if not args:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Lucas Moscovicz
revset: changed descendants revset to use lazy generators...
r20692 s = _revdescendants(repo, args, followfirst)
Durham Goode
revset: improve _descendants performance...
r20894
# Both sets need to be ascending in order to lazily return the union
# in the correct order.
args.ascending()
Pierre-Yves David
_descendant: use filteredset instead of orderedlazyset...
r22750 result = (filteredset(s, subset.__contains__, ascending=True) +
filteredset(args, subset.__contains__, ascending=True))
Durham Goode
revset: improve _descendants performance...
r20894
Pierre-Yves David
addset: drop the leading underscore from the class name...
r22793 # Wrap result in a filteredset since it's an addset, which doesn't
Pierre-Yves David
lazyset: rename the class to filteredset...
r22726 # implement all the necessary functions to be consumed by callers.
Pierre-Yves David
_descendant: use filteredset instead of orderedlazyset...
r22750 return filteredset(result, lambda r: True, ascending=True)
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def descendants(repo, subset, x):
"""``descendants(set)``
Changesets which are descendants of changesets in set.
"""
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 return _descendants(repo, subset, x)
def _firstdescendants(repo, subset, x):
# ``_firstdescendants(set)``
# Like ``descendants(set)`` but follows only the first parents.
return _descendants(repo, subset, x, followfirst=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Matt Harbison
revset: add destination() predicate...
r17186 def destination(repo, subset, x):
"""``destination([set])``
Changesets that were created by a graft, transplant or rebase operation,
with the given revisions specified as the source. Omitting the optional set
is the same as passing all().
"""
if x is not None:
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 args = getset(repo, spanset(repo), x).set()
Matt Harbison
revset: add destination() predicate...
r17186 else:
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 args = getall(repo, spanset(repo), x).set()
Matt Harbison
revset: add destination() predicate...
r17186
dests = set()
# subset contains all of the possible destinations that can be returned, so
# iterate over them and see if their source(s) were provided in the args.
# Even if the immediate src of r is not in the args, src's source (or
# further back) may be. Scanning back further than the immediate src allows
# transitive transplants and rebases to yield the same results as transitive
# grafts.
for r in subset:
src = _getrevsource(repo, r)
lineage = None
while src is not None:
if lineage is None:
lineage = list()
lineage.append(r)
# The visited lineage is a match if the current source is in the arg
# set. Since every candidate dest is visited by way of iterating
timeless@mozdev.org
spelling: further
r17494 # subset, any dests further back in the lineage will be tested by a
Matt Harbison
revset: add destination() predicate...
r17186 # different iteration over subset. Likewise, if the src was already
# selected, the current lineage can be selected without going back
# further.
if src in args or src in dests:
dests.update(lineage)
break
r = src
src = _getrevsource(repo, r)
Pierre-Yves David
revset: directly use __contains__ instead of a lambda...
r21217 return subset.filter(dests.__contains__)
Matt Harbison
revset: add destination() predicate...
r17186
Pierre-Yves David
obsolete: add revset and test for divergent changesets...
r18071 def divergent(repo, subset, x):
"""``divergent()``
Final successors of changesets with an alternative set of final successors.
"""
# i18n: "divergent" is a keyword
getargs(x, 0, 0, _("divergent takes no arguments"))
divergent = obsmod.getrevs(repo, 'divergent')
Pierre-Yves David
revset: use `subset &` in `divergent`...
r22533 return subset & divergent
Pierre-Yves David
obsolete: add revset and test for divergent changesets...
r18071
Pierre-Yves David
phases: implements simple revset symbol...
r15819 def draft(repo, subset, x):
"""``draft()``
Changeset in draft phase."""
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "draft" is a keyword
Pierre-Yves David
phases: implements simple revset symbol...
r15819 getargs(x, 0, 0, _("draft takes no arguments"))
Patrick Mezard
phases: introduce phasecache...
r16657 pc = repo._phasecache
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(lambda r: pc.phase(repo, r) == phases.draft)
Pierre-Yves David
phases: implements simple revset symbol...
r15819
Pierre-Yves David
obsolete: compute extinct changesets...
r17173 def extinct(repo, subset, x):
"""``extinct()``
Patrick Mezard
revset: minor doc fixes on obsolete related revsets
r17291 Obsolete changesets with obsolete descendants only.
"""
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "extinct" is a keyword
FUJIWARA Katsunori
revset: use appropriate predicate name in error messages...
r17258 getargs(x, 0, 0, _("extinct takes no arguments"))
Pierre-Yves David
obsolete: rename `getobscache` into `getrevs`...
r17825 extincts = obsmod.getrevs(repo, 'extinct')
Lucas Moscovicz
revset: added intersection to baseset class...
r20367 return subset & extincts
Pierre-Yves David
obsolete: compute extinct changesets...
r17173
Henrik Stuart
revset: add function for matching extra data (issue2767)
r16661 def extra(repo, subset, x):
"""``extra(label, [value])``
Changesets with the given label in the extra metadata, with the given
Simon King
revset: add pattern matching to 'extra' revset expression
r16824 optional value.
If `value` starts with `re:`, the remainder of the value is treated as
a regular expression. To match a value that actually starts with `re:`,
use the prefix `literal:`.
"""
Henrik Stuart
revset: add function for matching extra data (issue2767)
r16661
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "extra" is a keyword
Henrik Stuart
revset: add function for matching extra data (issue2767)
r16661 l = getargs(x, 1, 2, _('extra takes at least 1 and at most 2 arguments'))
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "extra" is a keyword
Henrik Stuart
revset: add function for matching extra data (issue2767)
r16661 label = getstring(l[0], _('first argument to extra must be a string'))
value = None
if len(l) > 1:
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "extra" is a keyword
Henrik Stuart
revset: add function for matching extra data (issue2767)
r16661 value = getstring(l[1], _('second argument to extra must be a string'))
Simon King
revset: add pattern matching to 'extra' revset expression
r16824 kind, value, matcher = _stringmatcher(value)
Henrik Stuart
revset: add function for matching extra data (issue2767)
r16661
def _matchvalue(r):
extra = repo[r].extra()
Simon King
revset: add pattern matching to 'extra' revset expression
r16824 return label in extra and (value is None or matcher(extra[label]))
Henrik Stuart
revset: add function for matching extra data (issue2767)
r16661
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(lambda r: _matchvalue(r))
Pierre-Yves David
phases: implements simple revset symbol...
r15819
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.
FUJIWARA Katsunori
revset: add explanation about difference between 'filelog()' and 'file()'
r17244
Greg Hurrell
help: clarify distinction among `contains`/`file`/`filelog`...
r21199 For performance reasons, visits only revisions mentioned in the file-level
filelog, rather than filtering through all changesets (much faster, but
doesn't include deletes or duplicate changes). For a slower, more accurate
result, use ``file()``.
FUJIWARA Katsunori
revset: add explanation about the pattern without explicit kind...
r20289
The pattern without explicit kind like ``glob:`` is expected to be
relative to the current directory and match against a file exactly
for efficiency.
Matt Mackall
revset: introduce filelog() to emulate log's fast path...
r14342 """
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "filelog" is a keyword
Matt Mackall
revset: introduce filelog() to emulate log's fast path...
r14342 pat = getstring(x, _("filelog requires a pattern"))
s = set()
Matt Mackall
revsets: provide contexts for filesets...
r15964 if not matchmod.patkind(pat):
FUJIWARA Katsunori
revset: use "canonpath()" for "filelog()" pattern without explicit kind...
r20288 f = pathutil.canonpath(repo.root, repo.getcwd(), pat)
FUJIWARA Katsunori
revset: avoid loop for "match.files()" having always one element for efficiency...
r20287 fl = repo.file(f)
for fr in fl:
s.add(fl.linkrev(fr))
Matt Mackall
revset: introduce filelog() to emulate log's fast path...
r14342 else:
FUJIWARA Katsunori
revset: use "canonpath()" for "filelog()" pattern without explicit kind...
r20288 m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[None])
Matt Mackall
revset: introduce filelog() to emulate log's fast path...
r14342 for f in repo[None]:
if m(f):
fl = repo.file(f)
for fr in fl:
s.add(fl.linkrev(fr))
Pierre-Yves David
revset: use `subset &` in `filelog`...
r22534 return subset & s
Matt Mackall
revset: introduce filelog() to emulate log's fast path...
r14342
Matt Mackall
revsets: add first alias for last
r15117 def first(repo, subset, x):
"""``first(set, [n])``
An alias for limit().
"""
return limit(repo, subset, x)
Patrick Mezard
context: add followfirst arg to filectx and workingfilectx...
r16185 def _follow(repo, subset, x, name, followfirst=False):
l = getargs(x, 0, 1, _("%s takes no arguments or a filename") % name)
c = repo['.']
if l:
x = getstring(l[0], _("%s expected a filename") % name)
if x in c:
cx = c[x]
s = set(ctx.rev() for ctx in cx.ancestors(followfirst=followfirst))
# include the revision responsible for the most recent version
s.add(cx.linkrev())
else:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Patrick Mezard
context: add followfirst arg to filectx and workingfilectx...
r16185 else:
Lucas Moscovicz
revset: changed ancestors revset to return lazy generators...
r20690 s = _revancestors(repo, baseset([c.rev()]), followfirst)
Patrick Mezard
context: add followfirst arg to filectx and workingfilectx...
r16185
Pierre-Yves David
revset: use `subset &` in `follow`...
r22535 return subset & s
Patrick Mezard
context: add followfirst arg to filectx and workingfilectx...
r16185
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.
"""
Patrick Mezard
context: add followfirst arg to filectx and workingfilectx...
r16185 return _follow(repo, subset, x, 'follow')
Matt Mackall
revset: add follow(filename) to follow a filename's history across copies
r14343
Patrick Mezard
graphlog: implement --follow-first...
r16174 def _followfirst(repo, subset, x):
# ``followfirst([file])``
# Like ``follow([file])`` but follows only the first parent of
# every revision or file revision.
Patrick Mezard
context: add followfirst arg to filectx and workingfilectx...
r16185 return _follow(repo, subset, x, '_followfirst', followfirst=True)
Matt Mackall
revset: add follow(filename) to follow a filename's history across copies
r14343
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 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)
Lucas Moscovicz
revset: added lazyset implementation to grep revset...
r20453
def matches(x):
c = repo[x]
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 for e in c.files() + [c.user(), c.description()]:
if gr.search(e):
Lucas Moscovicz
revset: added lazyset implementation to grep revset...
r20453 return True
return False
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(matches)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 def _matchfiles(repo, subset, x):
# _matchfiles takes a revset list of prefixed arguments:
#
# [p:foo, i:bar, x:baz]
#
# builds a match object from them and filters subset. Allowed
# prefixes are 'p:' for regular patterns, 'i:' for include
Patrick Mezard
graphlog: evaluate FILE/-I/-X filesets on the working dir...
r16181 # patterns and 'x:' for exclude patterns. Use 'r:' prefix to pass
# a revision identifier, or the empty string to reference the
# working directory, from which the match object is
Patrick Mezard
graphlog: correctly handle calls in subdirectories
r16411 # initialized. Use 'd:' to set the default matching mode, default
# to 'glob'. At most one 'r:' and 'd:' argument can be passed.
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161
# i18n: "_matchfiles" is a keyword
l = getargs(x, 1, -1, _("_matchfiles requires at least one argument"))
pats, inc, exc = [], [], []
hasset = False
Patrick Mezard
graphlog: correctly handle calls in subdirectories
r16411 rev, default = None, None
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 for arg in l:
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "_matchfiles" is a keyword
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 s = getstring(arg, _("_matchfiles requires string arguments"))
prefix, value = s[:2], s[2:]
if prefix == 'p:':
pats.append(value)
elif prefix == 'i:':
inc.append(value)
elif prefix == 'x:':
exc.append(value)
Patrick Mezard
graphlog: evaluate FILE/-I/-X filesets on the working dir...
r16181 elif prefix == 'r:':
if rev is not None:
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "_matchfiles" is a keyword
Patrick Mezard
graphlog: evaluate FILE/-I/-X filesets on the working dir...
r16181 raise error.ParseError(_('_matchfiles expected at most one '
'revision'))
rev = value
Patrick Mezard
graphlog: correctly handle calls in subdirectories
r16411 elif prefix == 'd:':
if default is not None:
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "_matchfiles" is a keyword
Patrick Mezard
graphlog: correctly handle calls in subdirectories
r16411 raise error.ParseError(_('_matchfiles expected at most one '
'default mode'))
default = value
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 else:
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "_matchfiles" is a keyword
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 raise error.ParseError(_('invalid _matchfiles prefix: %s') % prefix)
if not hasset and matchmod.patkind(value) == 'set':
hasset = True
Patrick Mezard
graphlog: correctly handle calls in subdirectories
r16411 if not default:
default = 'glob'
Lucas Moscovicz
revset: added lazyset implementation to _matchfiles...
r20458
def matches(x):
m = None
c = repo[x]
Patrick Mezard
graphlog: evaluate FILE/-I/-X filesets on the working dir...
r16181 if not m or (hasset and rev is None):
ctx = c
if rev is not None:
ctx = repo[rev or None]
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
Patrick Mezard
graphlog: correctly handle calls in subdirectories
r16411 exclude=exc, ctx=ctx, default=default)
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 for f in c.files():
if m(f):
Lucas Moscovicz
revset: added lazyset implementation to _matchfiles...
r20458 return True
return False
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(matches)
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def hasfile(repo, subset, x):
"""``file(pattern)``
Changesets affecting files matched by pattern.
FUJIWARA Katsunori
revset: add explanation about difference between 'filelog()' and 'file()'
r17244
Greg Ward
revset: polish explanation of the difference between file() and filelog()
r17265 For a faster but less accurate result, consider using ``filelog()``
instead.
FUJIWARA Katsunori
revset: add explanation about the pattern without explicit kind...
r20289
This predicate uses ``glob:`` as the default kind of pattern.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# i18n: "file" is a keyword
pat = getstring(x, _("file requires a pattern"))
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 return _matchfiles(repo, subset, ('string', 'p:' + pat))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
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)
Durham Goode
revset: improve head revset performance...
r20713 return baseset(hs).filter(subset.__contains__)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
def heads(repo, subset, x):
"""``heads(set)``
Members of set with no children in set.
"""
s = getset(repo, subset, x)
Lucas Moscovicz
revset: added substraction to baseset class...
r20366 ps = parents(repo, subset, x)
return s - ps
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Patrick Mezard
revset: add hidden() revset
r17390 def hidden(repo, subset, x):
"""``hidden()``
Hidden changesets.
"""
# i18n: "hidden" is a keyword
getargs(x, 0, 0, _("hidden takes no arguments"))
Kevin Bullock
filtering: rename filters to their antonyms...
r18382 hiddenrevs = repoview.filterrevs(repo, 'visible')
Lucas Moscovicz
revset: added intersection to baseset class...
r20367 return subset & hiddenrevs
Patrick Mezard
revset: add hidden() revset
r17390
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def keyword(repo, subset, x):
"""``keyword(string)``
Search commit message, user name, and names of changed files for
Martin Geisler
merge with stable
r14357 string. The match is case-insensitive.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# i18n: "keyword" is a keyword
FUJIWARA Katsunori
i18n: use "encoding.lower()" to normalize specified string for revset...
r15726 kw = encoding.lower(getstring(x, _("keyword requires a string")))
Lucas Moscovicz
revset: added lazyset implementation to keyword revset...
r20447
def matches(r):
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 c = repo[r]
Lucas Moscovicz
revset: added lazyset implementation to keyword revset...
r20447 return util.any(kw in encoding.lower(t) for t in c.files() + [c.user(),
c.description()])
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(matches)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
def limit(repo, subset, x):
Matt Mackall
revset: add default of 1 to limit and last functions
r15116 """``limit(set, [n])``
First n members of set, defaulting to 1.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# i18n: "limit" is a keyword
Matt Mackall
revset: add default of 1 to limit and last functions
r15116 l = getargs(x, 1, 2, _("limit requires one or two arguments"))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 try:
Matt Mackall
revset: add default of 1 to limit and last functions
r15116 lim = 1
if len(l) == 2:
# i18n: "limit" is a keyword
lim = int(getstring(l[1], _("limit requires a number")))
Matt Mackall
revsets: actually catch type error on tip^p1(tip) (issue2884)...
r14851 except (TypeError, ValueError):
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 # i18n: "limit" is a keyword
raise error.ParseError(_("limit expects a number"))
Lucas Moscovicz
revset: implemented set caching for revset evaluation...
r20365 ss = subset.set()
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 os = getset(repo, spanset(repo), l[0])
Pierre-Yves David
revset-limit: remove user of baseset.append...
r22804 result = []
Lucas Moscovicz
revset: changed limit revset implementation to work with lazy revsets...
r20446 it = iter(os)
for x in xrange(lim):
try:
y = it.next()
if y in ss:
Pierre-Yves David
revset-limit: remove user of baseset.append...
r22804 result.append(y)
Lucas Moscovicz
revset: changed limit revset implementation to work with lazy revsets...
r20446 except (StopIteration):
break
Pierre-Yves David
revset-limit: remove user of baseset.append...
r22804 return baseset(result)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Matt Mackall
revsets: add a last function...
r14061 def last(repo, subset, x):
Matt Mackall
revset: add default of 1 to limit and last functions
r15116 """``last(set, [n])``
Last n members of set, defaulting to 1.
Matt Mackall
revsets: add a last function...
r14061 """
# i18n: "last" is a keyword
Matt Mackall
revset: add default of 1 to limit and last functions
r15116 l = getargs(x, 1, 2, _("last requires one or two arguments"))
Matt Mackall
revsets: add a last function...
r14061 try:
Matt Mackall
revset: add default of 1 to limit and last functions
r15116 lim = 1
if len(l) == 2:
# i18n: "last" is a keyword
lim = int(getstring(l[1], _("last requires a number")))
Matt Mackall
revsets: actually catch type error on tip^p1(tip) (issue2884)...
r14851 except (TypeError, ValueError):
Matt Mackall
revsets: add a last function...
r14061 # i18n: "last" is a keyword
raise error.ParseError(_("last expects a number"))
Lucas Moscovicz
revset: implemented set caching for revset evaluation...
r20365 ss = subset.set()
Lucas Moscovicz
revset: changed last implementation to use lazy classes...
r20534 os = getset(repo, spanset(repo), l[0])
os.reverse()
Pierre-Yves David
revset-last: remove user of baseset.append...
r22805 result = []
Lucas Moscovicz
revset: changed last implementation to use lazy classes...
r20534 it = iter(os)
for x in xrange(lim):
try:
y = it.next()
if y in ss:
Pierre-Yves David
revset-last: remove user of baseset.append...
r22805 result.append(y)
Lucas Moscovicz
revset: changed last implementation to use lazy classes...
r20534 except (StopIteration):
break
Pierre-Yves David
revset-last: remove user of baseset.append...
r22805 return baseset(result)
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.
"""
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 os = getset(repo, spanset(repo), x)
Mads Kiilerich
revset: avoid over-aggresive optimizations of non-filtering functions (issue2549)...
r14153 if os:
Lucas Moscovicz
revset: changed minrev and maxrev implementations to use ordered sets...
r20754 m = os.max()
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 if m in subset:
Lucas Moscovicz
revset: added baseset class (still empty) to improve revset performance...
r20364 return baseset([m])
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
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
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Ivan Andrus
revsets: add branchpoint() function...
r17753 def branchpoint(repo, subset, x):
"""``branchpoint()``
Changesets with more than one child.
"""
# i18n: "branchpoint" is a keyword
getargs(x, 0, 0, _("branchpoint takes no arguments"))
cl = repo.changelog
if not subset:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Ivan Andrus
revsets: add branchpoint() function...
r17753 baserev = min(subset)
parentscount = [0]*(len(repo) - baserev)
Pierre-Yves David
clfilter: use changelog to iterate over the repo in branchpoint...
r17785 for r in cl.revs(start=baserev + 1):
Ivan Andrus
revsets: add branchpoint() function...
r17753 for p in cl.parentrevs(r):
if p >= baserev:
parentscount[p - baserev] += 1
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(lambda r: parentscount[r - baserev] > 1)
Ivan Andrus
revsets: add branchpoint() function...
r17753
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def minrev(repo, subset, x):
"""``min(set)``
Changeset with lowest revision number in set.
"""
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 os = getset(repo, spanset(repo), x)
Mads Kiilerich
revset: avoid over-aggresive optimizations of non-filtering functions (issue2549)...
r14153 if os:
Lucas Moscovicz
revset: changed minrev and maxrev implementations to use ordered sets...
r20754 m = os.min()
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 if m in subset:
Lucas Moscovicz
revset: added baseset class (still empty) to improve revset performance...
r20364 return baseset([m])
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
def modifies(repo, subset, x):
"""``modifies(pattern)``
Changesets modifying files matched by pattern.
FUJIWARA Katsunori
revset: add explanation about the pattern without explicit kind...
r20289
The pattern without explicit kind like ``glob:`` is expected to be
relative to the current directory and match against a file or a
directory.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# i18n: "modifies" is a keyword
pat = getstring(x, _("modifies requires a pattern"))
return checkstatus(repo, subset, pat, 0)
Matt Mackall
revset: avoid demandimport bug...
r16417 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:
Matt Harbison
revset: fix traceback for bogus revisions in id(rev)...
r16735 rn = None
pm = repo.changelog._partialmatch(n)
if pm is not None:
rn = repo.changelog.rev(pm)
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(lambda r: r == rn)
Augie Fackler
revset: add id() and rev() to allow explicitly referring to changes by hash or rev
r12716
Pierre-Yves David
revset: add an `obsolete` symbol...
r17170 def obsolete(repo, subset, x):
"""``obsolete()``
Mutable changeset with a newer version."""
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "obsolete" is a keyword
Pierre-Yves David
revset: add an `obsolete` symbol...
r17170 getargs(x, 0, 0, _("obsolete takes no arguments"))
Pierre-Yves David
obsolete: rename `getobscache` into `getrevs`...
r17825 obsoletes = obsmod.getrevs(repo, 'obsolete')
Lucas Moscovicz
revset: added intersection to baseset class...
r20367 return subset & obsoletes
Pierre-Yves David
revset: add an `obsolete` symbol...
r17170
Matt Harbison
revset: add origin() predicate...
r17185 def origin(repo, subset, x):
"""``origin([set])``
Changesets that were specified as a source for the grafts, transplants or
rebases that created the given revisions. Omitting the optional set is the
same as passing all(). If a changeset created by these operations is itself
specified as a source for one of these operations, only the source changeset
for the first operation is selected.
"""
if x is not None:
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 args = getset(repo, spanset(repo), x).set()
Matt Harbison
revset: add origin() predicate...
r17185 else:
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 args = getall(repo, spanset(repo), x).set()
Matt Harbison
revset: add origin() predicate...
r17185
def _firstsrc(rev):
src = _getrevsource(repo, rev)
if src is None:
return None
while True:
prev = _getrevsource(repo, src)
if prev is None:
return src
src = prev
o = set([_firstsrc(r) for r in args])
Pierre-Yves David
revset: remove invalid value in the origin set...
r22498 o -= set([None])
Pierre-Yves David
revset: use `subset &` in `origin`...
r22536 return subset & o
Matt Harbison
revset: add origin() predicate...
r17185
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def outgoing(repo, subset, x):
"""``outgoing([path])``
Changesets not found in the specified destination repository, or the
default push location.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 import hg # avoid start-up nasties
# i18n: "outgoing" is a keyword
Mads Kiilerich
revset and fileset: fix typos in parser error messages
r14717 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 # i18n: "outgoing" is a keyword
dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
dest, branches = hg.parseurl(dest)
revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
if revs:
revs = [repo.lookup(rev) for rev in revs]
Matt Mackall
hg: change various repository() users to use peer() where appropriate...
r14556 other = hg.peer(repo, {}, dest)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 repo.ui.pushbuffer()
Pierre-Yves David
discovery: introduce outgoing object for result of findcommonoutgoing...
r15837 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 repo.ui.popbuffer()
cl = repo.changelog
Pierre-Yves David
discovery: introduce outgoing object for result of findcommonoutgoing...
r15837 o = set([cl.rev(r) for r in outgoing.missing])
Pierre-Yves David
revset: use `subset &` in `outgoing`...
r22529 return subset & 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()
Pierre-Yves David
revset: use `subset &` in bare `p1()`...
r22538 if p >= 0:
return subset & baseset([p])
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
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
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 for r in getset(repo, spanset(repo), x):
Matt Mackall
revset: introduce revset core
r11275 ps.add(cl.parentrevs(r)[0])
Pierre-Yves David
revset: remove nullrev from set computed in p1() and p2()...
r22495 ps -= set([node.nullrev])
Lucas Moscovicz
revset: added intersection to baseset class...
r20367 return subset & ps
Matt Mackall
revset: introduce revset core
r11275
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()
Pierre-Yves David
revset: use `subset &` in bare `p2()`...
r22539 if p >= 0:
return subset & baseset([p])
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Kevin Bullock
revsets: let p1() and p2() return parents of working dir...
r12928 except IndexError:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
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
Lucas Moscovicz
revset: changed revsets to use spanset...
r20526 for r in getset(repo, spanset(repo), x):
Matt Mackall
revset: introduce revset core
r11275 ps.add(cl.parentrevs(r)[1])
Pierre-Yves David
revset: remove nullrev from set computed in p1() and p2()...
r22495 ps -= set([node.nullrev])
Lucas Moscovicz
revset: added intersection to baseset class...
r20367 return subset & ps
Matt Mackall
revset: introduce revset core
r11275
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:
Pierre-Yves David
revset: refactor parents() into a single return point...
r22496 ps = set(p.rev() for p in repo[x].parents())
else:
ps = set()
cl = repo.changelog
for r in getset(repo, spanset(repo), x):
ps.update(cl.parentrevs(r))
Pierre-Yves David
revset: remove nullrev from set computed in parents()...
r22497 ps -= set([node.nullrev])
Pierre-Yves David
revert: bring back usage of `subset & ps` in `parents`...
r22712 return subset & ps
Matt Mackall
revset: introduce revset core
r11275
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 def parentspec(repo, subset, x, n):
"""``set^0``
The set.
``set^1`` (or ``set^``), ``set^2``
First or second parent, respectively, of all changesets in set.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Brodie Rao
revset: handle re.compile() errors in grep()...
r12320 try:
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 n = int(n[1])
Kevin Gessner
revset: add missing whitespace
r14072 if n not in (0, 1, 2):
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 raise ValueError
Matt Mackall
revsets: actually catch type error on tip^p1(tip) (issue2884)...
r14851 except (TypeError, ValueError):
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 raise error.ParseError(_("^ expects a number 0, 1, or 2"))
ps = set()
Matt Mackall
revset: introduce revset core
r11275 cl = repo.changelog
Lucas Moscovicz
revset: added baseset class (still empty) to improve revset performance...
r20364 for r in getset(repo, baseset(cl), x):
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 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])
Lucas Moscovicz
revset: added intersection to baseset class...
r20367 return subset & 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.
FUJIWARA Katsunori
doc: add detail explanation for 'present()' predicate of revsets
r16748
If any of specified revisions is not present in the local repository,
the query is normally aborted. But this predicate allows the query
to continue even in such cases.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Wagner Bruna
revset: predicate to avoid lookup errors...
r11944 try:
return getset(repo, subset, x)
except error.RepoLookupError:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Wagner Bruna
revset: predicate to avoid lookup errors...
r11944
Pierre-Yves David
phases: implements simple revset symbol...
r15819 def public(repo, subset, x):
"""``public()``
Changeset in public phase."""
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "public" is a keyword
Pierre-Yves David
phases: implements simple revset symbol...
r15819 getargs(x, 0, 0, _("public takes no arguments"))
Patrick Mezard
phases: introduce phasecache...
r16657 pc = repo._phasecache
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(lambda r: pc.phase(repo, r) == phases.public)
Pierre-Yves David
phases: implements simple revset symbol...
r15819
Matt Mackall
revset: add remote() predicate to lookup remote revisions
r15936 def remote(repo, subset, x):
FUJIWARA Katsunori
revset: fix documentation for 'remote()' predicate...
r16007 """``remote([id [,path]])``
Matt Mackall
revset: add remote() predicate to lookup remote revisions
r15936 Local revision that corresponds to the given identifier in a
remote repository, if present. Here, the '.' identifier is a
synonym for the current local branch.
"""
import hg # avoid start-up nasties
# i18n: "remote" is a keyword
FUJIWARA Katsunori
revset: fix documentation for 'remote()' predicate...
r16007 l = getargs(x, 0, 2, _("remote takes one, two or no arguments"))
Matt Mackall
revset: add remote() predicate to lookup remote revisions
r15936
q = '.'
if len(l) > 0:
# i18n: "remote" is a keyword
q = getstring(l[0], _("remote requires a string id"))
if q == '.':
q = repo['.'].branch()
dest = ''
if len(l) > 1:
# i18n: "remote" is a keyword
dest = getstring(l[1], _("remote requires a repository path"))
dest = repo.ui.expandpath(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.peer(repo, {}, dest)
n = other.lookup(q)
if n in repo:
r = repo[n].rev()
FUJIWARA Katsunori
revset: fix 'remote()' failure when remote repo has more revs than local...
r16006 if r in subset:
Lucas Moscovicz
revset: added baseset class (still empty) to improve revset performance...
r20364 return baseset([r])
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Matt Mackall
revset: add remote() predicate to lookup remote revisions
r15936
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.
FUJIWARA Katsunori
revset: add explanation about the pattern without explicit kind...
r20289
The pattern without explicit kind like ``glob:`` is expected to be
relative to the current directory and match against a file or a
directory.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Martin Geisler
revset: add translator comments to i18n strings
r12815 # i18n: "removes" is a keyword
Benoit Boissinot
revset: use 'requires' instead of 'wants' in error message
r12736 pat = getstring(x, _("removes requires a pattern"))
Matt Mackall
revset: introduce revset core
r11275 return checkstatus(repo, subset, pat, 2)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def rev(repo, subset, x):
"""``rev(number)``
Revision with the given numeric identifier.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 # i18n: "rev" is a keyword
l = getargs(x, 1, 1, _("rev requires one argument"))
try:
# i18n: "rev" is a keyword
l = int(getstring(l[0], _("rev requires a number")))
Matt Mackall
revsets: actually catch type error on tip^p1(tip) (issue2884)...
r14851 except (TypeError, ValueError):
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 # i18n: "rev" is a keyword
raise error.ParseError(_("rev expects a number"))
Pierre-Yves David
revset: use `subset &` in `rev`...
r22537 return subset & baseset([l])
Matt Mackall
revset: introduce revset core
r11275
Angel Ezquerra
revset: add "matching" keyword...
r16402 def matching(repo, subset, x):
"""``matching(revision [, field])``
Changesets in which a given set of fields match the set of fields in the
selected revision or set.
FUJIWARA Katsunori
doc: flatten description of 'matching()' predicate to be formatted well...
r16528
Angel Ezquerra
revset: add "matching" keyword...
r16402 To match more than one field pass the list of fields to match separated
FUJIWARA Katsunori
doc: flatten description of 'matching()' predicate to be formatted well...
r16528 by spaces (e.g. ``author description``).
Valid fields are most regular revision fields and some special fields.
Regular revision fields are ``description``, ``author``, ``branch``,
Angel Ezquerra
revset: add "diff" field to "matching" keyword...
r17102 ``date``, ``files``, ``phase``, ``parents``, ``substate``, ``user``
and ``diff``.
Note that ``author`` and ``user`` are synonyms. ``diff`` refers to the
contents of the revision. Two revisions matching their ``diff`` will
also match their ``files``.
FUJIWARA Katsunori
doc: flatten description of 'matching()' predicate to be formatted well...
r16528
Special fields are ``summary`` and ``metadata``:
``summary`` matches the first line of the description.
Jesse Glick
revset: documentation typo "metatadata"
r16639 ``metadata`` is equivalent to matching ``description user date``
FUJIWARA Katsunori
doc: flatten description of 'matching()' predicate to be formatted well...
r16528 (i.e. it matches the main metadata fields).
``metadata`` is the default field which is used when no fields are
specified. You can match more than one field at a time.
Angel Ezquerra
revset: add "matching" keyword...
r16402 """
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "matching" is a keyword
Angel Ezquerra
revset: add "matching" keyword...
r16402 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments"))
Lucas Moscovicz
revset: added baseset class (still empty) to improve revset performance...
r20364 revs = getset(repo, baseset(repo.changelog), l[0])
Angel Ezquerra
revset: add "matching" keyword...
r16402
fieldlist = ['metadata']
if len(l) > 1:
fieldlist = getstring(l[1],
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "matching" is a keyword
Angel Ezquerra
revset: add "matching" keyword...
r16402 _("matching requires a string "
"as its second argument")).split()
Angel Ezquerra
revset: add "diff" field to "matching" keyword...
r17102 # Make sure that there are no repeated fields,
# expand the 'special' 'metadata' field type
# and check the 'files' whenever we check the 'diff'
Angel Ezquerra
revset: add "matching" keyword...
r16402 fields = []
for field in fieldlist:
if field == 'metadata':
fields += ['user', 'description', 'date']
Angel Ezquerra
revset: add "diff" field to "matching" keyword...
r17102 elif field == 'diff':
# a revision matching the diff must also match the files
# since matching the diff is very costly, make sure to
# also match the files first
fields += ['files', 'diff']
Angel Ezquerra
revset: add "matching" keyword...
r16402 else:
if field == 'author':
field = 'user'
fields.append(field)
fields = set(fields)
Angel Ezquerra
revset: make matching keyword not match summary when matching for description
r16444 if 'summary' in fields and 'description' in fields:
# If a revision matches its description it also matches its summary
fields.discard('summary')
Angel Ezquerra
revset: add "matching" keyword...
r16402
# We may want to match more than one field
Angel Ezquerra
revset: speedup matching() by first matching fields that take less time to...
r16446 # Not all fields take the same amount of time to be matched
# Sort the selected fields in order of increasing matching cost
Patrick Mezard
revset: make matching() work on python 2.4...
r16453 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary',
Angel Ezquerra
revset: add "diff" field to "matching" keyword...
r17102 'files', 'description', 'substate', 'diff']
Angel Ezquerra
revset: speedup matching() by first matching fields that take less time to...
r16446 def fieldkeyfunc(f):
try:
return fieldorder.index(f)
except ValueError:
# assume an unknown field is very costly
return len(fieldorder)
fields = list(fields)
fields.sort(key=fieldkeyfunc)
Angel Ezquerra
revset: add "matching" keyword...
r16402 # Each field will be matched with its own "getfield" function
# which will be added to the getfieldfuncs array of functions
getfieldfuncs = []
_funcs = {
'user': lambda r: repo[r].user(),
'branch': lambda r: repo[r].branch(),
'date': lambda r: repo[r].date(),
'description': lambda r: repo[r].description(),
'files': lambda r: repo[r].files(),
'parents': lambda r: repo[r].parents(),
'phase': lambda r: repo[r].phase(),
'substate': lambda r: repo[r].substate,
'summary': lambda r: repo[r].description().splitlines()[0],
Angel Ezquerra
revset: add "diff" field to "matching" keyword...
r17102 'diff': lambda r: list(repo[r].diff(git=True),)
Angel Ezquerra
revset: add "matching" keyword...
r16402 }
for info in fields:
getfield = _funcs.get(info, None)
if getfield is None:
raise error.ParseError(
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "matching" is a keyword
Angel Ezquerra
revset: add "matching" keyword...
r16402 _("unexpected field name passed to matching: %s") % info)
getfieldfuncs.append(getfield)
# convert the getfield array of functions into a "getinfo" function
# which returns an array of field values (or a single value if there
# is only one field to match)
Angel Ezquerra
revset: speedup matching() by stopping the match early if a field does not match...
r16445 getinfo = lambda r: [f(r) for f in getfieldfuncs]
Angel Ezquerra
revset: add "matching" keyword...
r16402
Lucas Moscovicz
revset: added lazyset implementation to matching revset...
r20459 def matches(x):
for rev in revs:
target = getinfo(rev)
Angel Ezquerra
revset: speedup matching() by stopping the match early if a field does not match...
r16445 match = True
for n, f in enumerate(getfieldfuncs):
Lucas Moscovicz
revset: added lazyset implementation to matching revset...
r20459 if target[n] != f(x):
Angel Ezquerra
revset: speedup matching() by stopping the match early if a field does not match...
r16445 match = False
if match:
Lucas Moscovicz
revset: added lazyset implementation to matching revset...
r20459 return True
return False
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(matches)
Angel Ezquerra
revset: add "matching" keyword...
r16402
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)``
Patrick Mezard
revset: do not ignore input revisions in roots()...
r16394 Changesets in set with no parent changeset in set.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Durham Goode
revset: improve roots revset performance...
r20895 s = getset(repo, spanset(repo), x).set()
subset = baseset([r for r in s if r in subset.set()])
Patrick Mezard
revset: do not ignore input revisions in roots()...
r16394 cs = _children(repo, subset, s)
Lucas Moscovicz
revset: added substraction to baseset class...
r20366 return subset - cs
Wagner Bruna
revset: predicate to avoid lookup errors...
r11944
Pierre-Yves David
phases: implements simple revset symbol...
r15819 def secret(repo, subset, x):
"""``secret()``
Changeset in secret phase."""
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "secret" is a keyword
Pierre-Yves David
phases: implements simple revset symbol...
r15819 getargs(x, 0, 0, _("secret takes no arguments"))
Patrick Mezard
phases: introduce phasecache...
r16657 pc = repo._phasecache
Lucas Moscovicz
revset: changed revset code to use filter method...
r20611 return subset.filter(lambda x: pc.phase(repo, x) == phases.secret)
Pierre-Yves David
phases: implements simple revset symbol...
r15819
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:
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "sort" is a keyword
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)
Lucas Moscovicz
revset: changed sort method to use native sort implementation of smartsets...
r20719 revs = getset(repo, subset, s)
if keys == ["rev"]:
revs.sort()
return revs
elif keys == ["-rev"]:
revs.sort(reverse=True)
return revs
for r in revs:
Matt Mackall
revset: introduce revset core
r11275 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()
Lucas Moscovicz
revset: added baseset class (still empty) to improve revset performance...
r20364 return baseset([e[-1] for e in l])
Matt Mackall
revset: introduce revset core
r11275
Simon King
revset: add helper function for matching strings to patterns
r16819 def _stringmatcher(pattern):
"""
accepts a string, possibly starting with 're:' or 'literal:' prefix.
returns the matcher name, pattern, and matcher function.
missing or unknown prefixes are treated as literal matches.
helper for tests:
>>> def test(pattern, *tests):
... kind, pattern, matcher = _stringmatcher(pattern)
... return (kind, pattern, [bool(matcher(t)) for t in tests])
exact matching (no prefix):
>>> test('abcdefg', 'abc', 'def', 'abcdefg')
('literal', 'abcdefg', [False, False, True])
regex matching ('re:' prefix)
>>> test('re:a.+b', 'nomatch', 'fooadef', 'fooadefbar')
('re', 'a.+b', [False, False, True])
force exact matches ('literal:' prefix)
>>> test('literal:re:foobar', 'foobar', 're:foobar')
('literal', 're:foobar', [False, True])
unknown prefixes are ignored and treated as literals
>>> test('foo:bar', 'foo', 'bar', 'foo:bar')
('literal', 'foo:bar', [False, False, True])
"""
if pattern.startswith('re:'):
pattern = pattern[3:]
try:
regex = re.compile(pattern)
except re.error, e:
raise error.ParseError(_('invalid regular expression: %s')
% e)
return 're', pattern, regex.search
elif pattern.startswith('literal:'):
pattern = pattern[8:]
return 'literal', pattern, pattern.__eq__
Simon King
revset: add pattern matching to the 'user' revset expression
r16823 def _substringmatcher(pattern):
kind, pattern, matcher = _stringmatcher(pattern)
if kind == 'literal':
matcher = lambda s: pattern in s
return kind, pattern, matcher
Simon King
revset: add helper function for matching strings to patterns
r16819
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.
Matt Harbison
revset: document the regular expression support for tag(name)...
r20824
If `name` starts with `re:`, the remainder of the name is treated as
a regular expression. To match a tag that actually starts with `re:`,
use the prefix `literal:`.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
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:
Simon King
revset: add pattern matching to 'tag' revset expression...
r16820 pattern = getstring(args[0],
# i18n: "tag" is a keyword
_('the argument to tag must be a string'))
kind, pattern, matcher = _stringmatcher(pattern)
if kind == 'literal':
Matt Mackall
revset: avoid validating all tag nodes for tag(x)...
r16825 # avoid resolving all tags
tn = repo._tagscache.tags.get(pattern, None)
if tn is None:
Simon King
revset: add pattern matching to 'tag' revset expression...
r16820 raise util.Abort(_("tag '%s' does not exist") % pattern)
Matt Mackall
revset: avoid validating all tag nodes for tag(x)...
r16825 s = set([repo[tn].rev()])
Simon King
revset: add pattern matching to 'tag' revset expression...
r16820 else:
s = set([cl.rev(n) for t, n in repo.tagslist() if matcher(t)])
Augie Fackler
revset: rename tagged() to tag() and allow it to take an optional tag name
r12715 else:
s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
Lucas Moscovicz
revset: added intersection to baseset class...
r20367 return subset & s
Matt Mackall
revset: add tagged predicate
r11280
Patrick Mezard
revsets: generate predicate help dynamically
r12821 def tagged(repo, subset, x):
return tag(repo, subset, x)
Pierre-Yves David
obsolete: compute unstable changeset...
r17171 def unstable(repo, subset, x):
"""``unstable()``
Patrick Mezard
revset: minor doc fixes on obsolete related revsets
r17291 Non-obsolete changesets with obsolete ancestors.
"""
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "unstable" is a keyword
FUJIWARA Katsunori
revset: use appropriate predicate name in error messages...
r17258 getargs(x, 0, 0, _("unstable takes no arguments"))
Pierre-Yves David
obsolete: rename `getobscache` into `getrevs`...
r17825 unstables = obsmod.getrevs(repo, 'unstable')
Lucas Moscovicz
revset: added intersection to baseset class...
r20367 return subset & unstables
Pierre-Yves David
obsolete: compute unstable changeset...
r17171
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.
Simon King
revset: add pattern matching to the 'user' revset expression
r16823
If `string` starts with `re:`, the remainder of the string is treated as
a regular expression. To match a user that actually contains `re:`, use
the prefix `literal:`.
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: optimize building large lists in formatrevspec...
r15898 # for internal use
def _list(repo, subset, x):
s = getstring(x, "internal error")
if not s:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Matt Mackall
revset: optimize building large lists in formatrevspec...
r15898 ls = [repo[r].rev() for r in s.split('\0')]
Lucas Moscovicz
revset: implemented set caching for revset evaluation...
r20365 s = subset.set()
return baseset([r for r in ls if r in s])
Matt Mackall
revset: optimize building large lists in formatrevspec...
r15898
Lucas Moscovicz
revset: added _intlist method to replace _list for %ld...
r20566 # for internal use
def _intlist(repo, subset, x):
s = getstring(x, "internal error")
if not s:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Lucas Moscovicz
revset: added _intlist method to replace _list for %ld...
r20566 ls = [int(r) for r in s.split('\0')]
s = subset.set()
return baseset([r for r in ls if r in s])
Lucas Moscovicz
revset: added _hexlist method to replace _list for %ln...
r20569 # for internal use
def _hexlist(repo, subset, x):
s = getstring(x, "internal error")
if not s:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Lucas Moscovicz
revset: added _hexlist method to replace _list for %ln...
r20569 cl = repo.changelog
ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
s = subset.set()
return baseset([r for r in ls if r in s])
Matt Mackall
revset: optimize building large lists in formatrevspec...
r15898
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,
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 "_firstancestors": _firstancestors,
Matt Mackall
revset: sort the predicate list
r11284 "author": author,
Durham Goode
revset: add 'only' revset...
r20613 "only": only,
"Yann E. MORIN"
revset: rename bisected() to bisect()...
r15134 "bisect": bisect,
Benoit Boissinot
revset: add a revset command to get bisect state.
r13602 "bisected": bisected,
Matt Mackall
bookmarks: move revset support to core
r13359 "bookmark": bookmark,
Matt Mackall
revset: introduce revset core
r11275 "branch": branch,
Ivan Andrus
revsets: add branchpoint() function...
r17753 "branchpoint": branchpoint,
Pierre-Yves David
revset: add a bumped revset...
r17829 "bumped": bumped,
Tomasz Kleczek
bundle: add revset expression to show bundle contents (issue3487)...
r17913 "bundle": bundle,
Matt Mackall
revset: sort the predicate list
r11284 "children": children,
"closed": closed,
"contains": contains,
Matt Harbison
revset: add a predicate for finding converted changesets...
r17002 "converted": converted,
Matt Mackall
revset: sort the predicate list
r11284 "date": date,
Thomas Arendsen Hein
revset: add desc(string) to search in commit messages...
r14650 "desc": desc,
Matt Mackall
revset: sort the predicate list
r11284 "descendants": descendants,
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 "_firstdescendants": _firstdescendants,
Matt Harbison
revset: add destination() predicate...
r17186 "destination": destination,
Pierre-Yves David
obsolete: add revset and test for divergent changesets...
r18071 "divergent": divergent,
Pierre-Yves David
phases: implements simple revset symbol...
r15819 "draft": draft,
Pierre-Yves David
obsolete: compute extinct changesets...
r17173 "extinct": extinct,
Henrik Stuart
revset: add function for matching extra data (issue2767)
r16661 "extra": extra,
Matt Mackall
revset: sort the predicate list
r11284 "file": hasfile,
Matt Mackall
revset: introduce filelog() to emulate log's fast path...
r14342 "filelog": filelog,
Matt Mackall
revsets: add first alias for last
r15117 "first": first,
Matt Mackall
revset: sort the predicate list
r11284 "follow": follow,
Patrick Mezard
graphlog: implement --follow-first...
r16174 "_followfirst": _followfirst,
Matt Mackall
revset: sort the predicate list
r11284 "grep": grep,
"head": head,
"heads": heads,
Patrick Mezard
revset: add hidden() revset
r17390 "hidden": hidden,
Matt Mackall
revset: avoid demandimport bug...
r16417 "id": node_,
Matt Mackall
revset: introduce revset core
r11275 "keyword": keyword,
Matt Mackall
revsets: add a last function...
r14061 "last": last,
Matt Mackall
revset: sort the predicate list
r11284 "limit": limit,
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 "_matchfiles": _matchfiles,
Matt Mackall
revset: sort the predicate list
r11284 "max": maxrev,
Thomas Arendsen Hein
revset: update sorting of symbols
r14649 "merge": merge,
Nicolas Dumazet
revset: add min function
r11708 "min": minrev,
Matt Mackall
revset: sort the predicate list
r11284 "modifies": modifies,
Pierre-Yves David
revset: add an `obsolete` symbol...
r17170 "obsolete": obsolete,
Matt Harbison
revset: add origin() predicate...
r17185 "origin": origin,
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,
Pierre-Yves David
phases: implements simple revset symbol...
r15819 "public": public,
Matt Mackall
revset: add remote() predicate to lookup remote revisions
r15936 "remote": remote,
Matt Mackall
revset: sort the predicate list
r11284 "removes": removes,
Thomas Arendsen Hein
revset: update sorting of symbols
r14649 "rev": rev,
Matt Mackall
revset: sort the predicate list
r11284 "reverse": reverse,
Matt Mackall
revset: introduce revset core
r11275 "roots": roots,
Matt Mackall
revset: sort the predicate list
r11284 "sort": sort,
Pierre-Yves David
phases: implements simple revset symbol...
r15819 "secret": secret,
Angel Ezquerra
revset: add "matching" keyword...
r16402 "matching": matching,
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,
Pierre-Yves David
obsolete: compute unstable changeset...
r17171 "unstable": unstable,
Matt Mackall
revset: optimize building large lists in formatrevspec...
r15898 "_list": _list,
Lucas Moscovicz
revset: added _intlist method to replace _list for %ld...
r20566 "_intlist": _intlist,
Lucas Moscovicz
revset: added _hexlist method to replace _list for %ln...
r20569 "_hexlist": _hexlist,
Matt Mackall
revset: introduce revset core
r11275 }
Alexander Plavin
revset: add a whitelist of DoS-safe symbols...
r19721 # symbols which can't be used for a DoS attack for any given input
# (e.g. those which accept regexes as plain strings shouldn't be included)
# functions that just return a lot of changesets (like all) don't count here
safesymbols = set([
"adds",
"all",
"ancestor",
"ancestors",
"_firstancestors",
"author",
"bisect",
"bisected",
"bookmark",
"branch",
"branchpoint",
"bumped",
"bundle",
"children",
"closed",
"converted",
"date",
"desc",
"descendants",
"_firstdescendants",
"destination",
"divergent",
"draft",
"extinct",
"extra",
"file",
"filelog",
"first",
"follow",
"_followfirst",
"head",
"heads",
"hidden",
"id",
"keyword",
"last",
"limit",
"_matchfiles",
"max",
"merge",
"min",
"modifies",
"obsolete",
"origin",
"outgoing",
"p1",
"p2",
"parents",
"present",
"public",
"remote",
"removes",
"rev",
"reverse",
"roots",
"sort",
"secret",
"matching",
"tag",
"tagged",
"user",
"unstable",
"_list",
Lucas Moscovicz
revset: added _intlist method to replace _list for %ld...
r20566 "_intlist",
Lucas Moscovicz
revset: added _hexlist method to replace _list for %ln...
r20569 "_hexlist",
Alexander Plavin
revset: add a whitelist of DoS-safe symbols...
r19721 ])
Matt Mackall
revset: introduce revset core
r11275 methods = {
"range": rangeset,
Bryan O'Sullivan
revset: turn dagrange into a function
r16860 "dagrange": dagrange,
Matt Mackall
revset: introduce revset core
r11275 "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 == '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
Bryan O'Sullivan
revset: drop unreachable code
r16859 elif op == 'and':
Matt Mackall
revset: optimize the parse tree directly...
r11279 wa, ta = optimize(x[1], True)
wb, tb = optimize(x[2], True)
Siddharth Agarwal
revset: optimize missing ancestor expressions...
r20499
# (::x and not ::y)/(not ::y and ::x) have a fast path
Siddharth Agarwal
revset: replace _missingancestors optimization with only revset...
r21893 def isonly(revs, bases):
Siddharth Agarwal
revset: optimize missing ancestor expressions...
r20499 return (
revs[0] == 'func'
and getstring(revs[1], _('not a symbol')) == 'ancestors'
and bases[0] == 'not'
and bases[1][0] == 'func'
and getstring(bases[1][1], _('not a symbol')) == 'ancestors')
Matt Mackall
revset: optimize the parse tree directly...
r11279 w = min(wa, wb)
Siddharth Agarwal
revset: replace _missingancestors optimization with only revset...
r21893 if isonly(ta, tb):
return w, ('func', ('symbol', 'only'), ('list', ta[2], tb[1][2]))
if isonly(tb, ta):
return w, ('func', ('symbol', 'only'), ('list', tb[2], ta[1][2]))
Siddharth Agarwal
revset: optimize missing ancestor expressions...
r20499
Matt Mackall
revset: optimize the parse tree directly...
r11279 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)
Bryan O'Sullivan
revset: turn dagrange into a function
r16860 elif op in 'dagrange range list parent ancestorspec':
Matt Mackall
revsets: do the right thing with x^:y (issue2884)...
r14842 if op == 'parent':
# x^:y means (x^) : y, not x ^ (:y)
post = ('parentpost', x[1])
if x[2][0] == 'dagrangepre':
return optimize(('dagrange', post, x[2][1]), small)
elif x[2][0] == 'rangepre':
return optimize(('range', post, x[2][1]), small)
Matt Mackall
revset: optimize the parse tree directly...
r11279 wa, ta = optimize(x[1], small)
wb, tb = optimize(x[2], small)
return wa + wb, (op, ta, tb)
Matt Mackall
revset: introduce revset core
r11275 elif op == 'func':
Martin Geisler
revset: all your error messages are belong to _
r11383 f = getstring(x[1], _("not a symbol"))
Matt Mackall
revset: optimize the parse tree directly...
r11279 wa, ta = optimize(x[2], small)
Thomas Arendsen Hein
revset: add desc(string) to search in commit messages...
r14650 if f in ("author branch closed date desc file grep keyword "
"outgoing user"):
Matt Mackall
revset: optimize the parse tree directly...
r11279 w = 10 # slow
Matt Mackall
revsets: reduce cost of outgoing in the optimizer
r12351 elif f in "modifies adds removes":
Matt Mackall
revset: optimize the parse tree directly...
r11279 w = 30 # slower
Matt Mackall
revset: introduce revset core
r11275 elif f == "contains":
Matt Mackall
revset: optimize the parse tree directly...
r11279 w = 100 # very slow
Matt Mackall
revset: introduce revset core
r11275 elif f == "ancestor":
Matt Mackall
revset: optimize the parse tree directly...
r11279 w = 1 * smallbonus
Durham Goode
revset: lower weight for _intlist function...
r22451 elif f in "reverse limit first _intlist":
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
Patrick Mezard
revset: explicitely tag alias arguments for expansion...
r16771 _aliasarg = ('func', ('symbol', '_aliasarg'))
def _getaliasarg(tree):
"""If tree matches ('func', ('symbol', '_aliasarg'), ('string', X))
return X, None otherwise.
"""
if (len(tree) == 3 and tree[:2] == _aliasarg
and tree[2][0] == 'string'):
return tree[2][1]
return None
def _checkaliasarg(tree, known=None):
"""Check tree contains no _aliasarg construct or only ones which
value is in known. Used to avoid alias placeholders injection.
"""
if isinstance(tree, tuple):
arg = _getaliasarg(tree)
if arg is not None and (not known or arg not in known):
raise error.ParseError(_("not a function: %s") % '_aliasarg')
for t in tree:
_checkaliasarg(t, known)
Alexander Solovyov
revset aliases
r14098 class revsetalias(object):
funcre = re.compile('^([^(]+)\(([^)]+)\)$')
Mads Kiilerich
revset: fix aliases with 0 or more than 2 parameters...
r14723 args = None
Alexander Solovyov
revset aliases
r14098
Mads Kiilerich
revset: fix aliases with 0 or more than 2 parameters...
r14723 def __init__(self, name, value):
Alexander Solovyov
revset aliases
r14098 '''Aliases like:
h = heads(default)
b($1) = ancestors($1) - ancestors(default)
'''
Patrick Mezard
revset: fix alias substitution recursion (issue3240)...
r16096 m = self.funcre.search(name)
if m:
self.name = m.group(1)
self.tree = ('func', ('symbol', m.group(1)))
self.args = [x.strip() for x in m.group(2).split(',')]
for arg in self.args:
Patrick Mezard
revset: explicitely tag alias arguments for expansion...
r16771 # _aliasarg() is an unknown symbol only used separate
# alias argument placeholders from regular strings.
value = value.replace(arg, '_aliasarg(%r)' % (arg,))
Patrick Mezard
revset: fix alias substitution recursion (issue3240)...
r16096 else:
self.name = name
self.tree = ('symbol', name)
self.replacement, pos = parse(value)
if pos != len(value):
raise error.ParseError(_('invalid token'), pos)
Patrick Mezard
revset: explicitely tag alias arguments for expansion...
r16771 # Check for placeholder injection
_checkaliasarg(self.replacement, self.args)
Alexander Solovyov
revset aliases
r14098
Patrick Mezard
revset: fix alias substitution recursion (issue3240)...
r16096 def _getalias(aliases, tree):
"""If tree looks like an unexpanded alias, return it. Return None
otherwise.
"""
if isinstance(tree, tuple) and tree:
if tree[0] == 'symbol' and len(tree) == 2:
name = tree[1]
alias = aliases.get(name)
if alias and alias.args is None and alias.tree == tree:
return alias
if tree[0] == 'func' and len(tree) > 1:
if tree[1][0] == 'symbol' and len(tree[1]) == 2:
name = tree[1][1]
alias = aliases.get(name)
if alias and alias.args is not None and alias.tree == tree[:2]:
return alias
return None
Alexander Solovyov
revset aliases
r14098
Patrick Mezard
revset: fix alias substitution recursion (issue3240)...
r16096 def _expandargs(tree, args):
Patrick Mezard
revset: explicitely tag alias arguments for expansion...
r16771 """Replace _aliasarg instances with the substitution value of the
same name in args, recursively.
Patrick Mezard
revset: fix alias substitution recursion (issue3240)...
r16096 """
Patrick Mezard
revset: explicitely tag alias arguments for expansion...
r16771 if not tree or not isinstance(tree, tuple):
Patrick Mezard
revset: fix alias substitution recursion (issue3240)...
r16096 return tree
Patrick Mezard
revset: explicitely tag alias arguments for expansion...
r16771 arg = _getaliasarg(tree)
if arg is not None:
return args[arg]
Patrick Mezard
revset: fix alias substitution recursion (issue3240)...
r16096 return tuple(_expandargs(t, args) for t in tree)
Patrick Mezard
revset: cache alias expansions...
r16838 def _expandaliases(aliases, tree, expanding, cache):
Patrick Mezard
revset: fix alias substitution recursion (issue3240)...
r16096 """Expand aliases in tree, recursively.
'aliases' is a dictionary mapping user defined aliases to
revsetalias objects.
"""
if not isinstance(tree, tuple):
# Do not expand raw strings
Alexander Solovyov
revset aliases
r14098 return tree
Patrick Mezard
revset: fix alias substitution recursion (issue3240)...
r16096 alias = _getalias(aliases, tree)
if alias is not None:
if alias in expanding:
raise error.ParseError(_('infinite expansion of revset alias "%s" '
'detected') % alias.name)
expanding.append(alias)
Patrick Mezard
revset: cache alias expansions...
r16838 if alias.name not in cache:
cache[alias.name] = _expandaliases(aliases, alias.replacement,
expanding, cache)
result = cache[alias.name]
Patrick Mezard
revset: fix infinite alias expansion detection...
r16772 expanding.pop()
Patrick Mezard
revset: fix alias substitution recursion (issue3240)...
r16096 if alias.args is not None:
l = getlist(tree[2])
if len(l) != len(alias.args):
raise error.ParseError(
_('invalid number of arguments: %s') % len(l))
Patrick Mezard
revset: cache alias expansions...
r16838 l = [_expandaliases(aliases, a, [], cache) for a in l]
Patrick Mezard
revset: fix alias substitution recursion (issue3240)...
r16096 result = _expandargs(result, dict(zip(alias.args, l)))
else:
Patrick Mezard
revset: cache alias expansions...
r16838 result = tuple(_expandaliases(aliases, t, expanding, cache)
Patrick Mezard
revset: fix alias substitution recursion (issue3240)...
r16096 for t in tree)
return result
Alexander Solovyov
revset aliases
r14098
def findaliases(ui, tree):
Patrick Mezard
revset: explicitely tag alias arguments for expansion...
r16771 _checkaliasarg(tree)
Patrick Mezard
revset: fix alias substitution recursion (issue3240)...
r16096 aliases = {}
Alexander Solovyov
revset aliases
r14098 for k, v in ui.configitems('revsetalias'):
alias = revsetalias(k, v)
Patrick Mezard
revset: fix alias substitution recursion (issue3240)...
r16096 aliases[alias.name] = alias
Patrick Mezard
revset: cache alias expansions...
r16838 return _expandaliases(aliases, tree, [], {})
Alexander Solovyov
revset aliases
r14098
Matt Mackall
revset: pass a lookup function to the tokenizer
r20779 def parse(spec, lookup=None):
Yuya Nishihara
fileset, revset: do not use global parser object for thread safety...
r20208 p = parser.parser(tokenize, elements)
Matt Mackall
revset: pass a lookup function to the tokenizer
r20779 return p.parse(spec, lookup=lookup)
def match(ui, spec, repo=None):
Matt Mackall
revset: nicer exception for empty queries
r11385 if not spec:
raise error.ParseError(_("empty query"))
Matt Mackall
revset: pass a lookup function to the tokenizer
r20779 lookup = None
if repo:
lookup = repo.__contains__
tree, pos = parse(spec, lookup)
Bernhard Leiner
revset: report a parse error if a revset is not parsed completely (issue2654)
r14496 if (pos != len(spec)):
Mads Kiilerich
parsers: fix localization markup of parser errors
r14701 raise error.ParseError(_("invalid token"), pos)
Matt Mackall
revset: allow bypassing alias expansion...
r14900 if ui:
tree = findaliases(ui, tree)
Matt Mackall
revset: optimize the parse tree directly...
r11279 weight, tree = optimize(tree, True)
Matt Mackall
revset: introduce revset core
r11275 def mfunc(repo, subset):
Lucas Moscovicz
revset: changed mfunc and getset to work with old style revset methods...
r20527 if util.safehasattr(subset, 'set'):
Pierre-Yves David
revset: use a single return statement in matcher function...
r22686 result = getset(repo, subset, tree)
else:
result = getset(repo, baseset(subset), tree)
return result
Matt Mackall
revset: introduce revset core
r11275 return mfunc
Patrick Mezard
revsets: generate predicate help dynamically
r12821
Matt Mackall
revset: add formatspec convenience query builder
r14901 def formatspec(expr, *args):
'''
This is a convenience function for using revsets internally, and
escapes arguments appropriately. Aliases are intentionally ignored
so that intended expression behavior isn't accidentally subverted.
Supported arguments:
Matt Mackall
revset: add %r for embedded revset support to formatspec...
r15266 %r = revset expression, parenthesized
Matt Mackall
revset: add formatspec convenience query builder
r14901 %d = int(arg), no quoting
%s = string(arg), escaped and single-quoted
%b = arg.branch(), escaped and single-quoted
%n = hex(arg), single-quoted
%% = a literal '%'
Matt Mackall
revset: add %r for embedded revset support to formatspec...
r15266 Prefixing the type with 'l' specifies a parenthesized list of that type.
Matt Mackall
revset: add 'l' flag to formatspec for args...
r15140
Matt Mackall
revset: fix %r handling in formatspec
r15268 >>> formatspec('%r:: and %lr', '10 or 11', ("this()", "that()"))
'(10 or 11):: and ((this()) or (that()))'
Matt Mackall
revset: add formatspec convenience query builder
r14901 >>> formatspec('%d:: and not %d::', 10, 20)
'10:: and not 20::'
Matt Mackall
revset: deal with empty lists in formatspec
r15325 >>> formatspec('%ld or %ld', [], [1])
Matt Mackall
revset: optimize building large lists in formatrevspec...
r15898 "_list('') or 1"
Matt Mackall
revset: add formatspec convenience query builder
r14901 >>> formatspec('keyword(%s)', 'foo\\xe9')
"keyword('foo\\\\xe9')"
>>> b = lambda: 'default'
>>> b.branch = b
>>> formatspec('branch(%b)', b)
"branch('default')"
Matt Mackall
revset: add 'l' flag to formatspec for args...
r15140 >>> formatspec('root(%ls)', ['a', 'b', 'c', 'd'])
Matt Mackall
revset: optimize building large lists in formatrevspec...
r15898 "root(_list('a\\x00b\\x00c\\x00d'))"
Matt Mackall
revset: add formatspec convenience query builder
r14901 '''
def quote(s):
return repr(str(s))
Matt Mackall
revset: add 'l' flag to formatspec for args...
r15140 def argtype(c, arg):
if c == 'd':
return str(int(arg))
elif c == 's':
return quote(arg)
Matt Mackall
revset: add %r for embedded revset support to formatspec...
r15266 elif c == 'r':
parse(arg) # make sure syntax errors are confined
return '(%s)' % arg
Matt Mackall
revset: add 'l' flag to formatspec for args...
r15140 elif c == 'n':
Matt Mackall
revset: avoid demandimport bug...
r16417 return quote(node.hex(arg))
Matt Mackall
revset: add 'l' flag to formatspec for args...
r15140 elif c == 'b':
return quote(arg.branch())
Matt Mackall
revset: balance %l or-expressions (issue3129)
r15595 def listexp(s, t):
l = len(s)
if l == 0:
Matt Mackall
revset: optimize building large lists in formatrevspec...
r15898 return "_list('')"
elif l == 1:
Matt Mackall
revset: balance %l or-expressions (issue3129)
r15595 return argtype(t, s[0])
Matt Mackall
revset: optimize building large lists in formatrevspec...
r15898 elif t == 'd':
Lucas Moscovicz
revset: added _intlist method to replace _list for %ld...
r20566 return "_intlist('%s')" % "\0".join(str(int(a)) for a in s)
Matt Mackall
revset: optimize building large lists in formatrevspec...
r15898 elif t == 's':
return "_list('%s')" % "\0".join(s)
elif t == 'n':
Lucas Moscovicz
revset: added _hexlist method to replace _list for %ln...
r20569 return "_hexlist('%s')" % "\0".join(node.hex(a) for a in s)
Matt Mackall
revset: optimize building large lists in formatrevspec...
r15898 elif t == 'b':
return "_list('%s')" % "\0".join(a.branch() for a in s)
Martin Geisler
Use explicit integer division...
r15791 m = l // 2
Matt Mackall
revset: balance %l or-expressions (issue3129)
r15595 return '(%s or %s)' % (listexp(s[:m], t), listexp(s[m:], t))
Matt Mackall
revset: add formatspec convenience query builder
r14901 ret = ''
pos = 0
arg = 0
while pos < len(expr):
c = expr[pos]
if c == '%':
pos += 1
d = expr[pos]
if d == '%':
ret += d
Matt Mackall
revset: fix %r handling in formatspec
r15268 elif d in 'dsnbr':
Matt Mackall
revset: add 'l' flag to formatspec for args...
r15140 ret += argtype(d, args[arg])
Matt Mackall
revset: add formatspec convenience query builder
r14901 arg += 1
Matt Mackall
revset: add 'l' flag to formatspec for args...
r15140 elif d == 'l':
# a list of some type
pos += 1
d = expr[pos]
Matt Mackall
merge with stable
r15596 ret += listexp(list(args[arg]), d)
Matt Mackall
revset: add formatspec convenience query builder
r14901 arg += 1
else:
raise util.Abort('unexpected revspec format character %s' % d)
else:
ret += c
pos += 1
return ret
Patrick Mezard
debugrevspec: pretty print output...
r16218 def prettyformat(tree):
def _prettyformat(tree, level, lines):
if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
lines.append((level, str(tree)))
else:
lines.append((level, '(%s' % tree[0]))
for s in tree[1:]:
_prettyformat(s, level + 1, lines)
lines[-1:] = [(lines[-1][0], lines[-1][1] + ')')]
lines = []
_prettyformat(tree, 0, lines)
output = '\n'.join((' '*l + s) for l, s in lines)
return output
Alexander Plavin
revset: add helper function to get revset parse tree depth...
r19719 def depth(tree):
if isinstance(tree, tuple):
return max(map(depth, tree)) + 1
else:
return 0
Alexander Plavin
revset: add helper function to get functions used in a revset parse tree...
r19720 def funcsused(tree):
if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
return set()
else:
funcs = set()
for s in tree[1:]:
funcs |= funcsused(s)
if tree[0] == 'func':
funcs.add(tree[1][1])
return funcs
Pierre-Yves David
revset: introduce an abstractsmartset class...
r22692 class abstractsmartset(object):
def __nonzero__(self):
"""True if the smartset is not empty"""
raise NotImplementedError()
def __contains__(self, rev):
"""provide fast membership testing"""
raise NotImplementedError()
def __set__(self):
"""Returns a set or a smartset containing all the elements.
The returned structure should be the fastest option for membership
testing.
This is part of the mandatory API for smartset."""
raise NotImplementedError()
def __iter__(self):
"""iterate the set in the order it is supposed to be iterated"""
raise NotImplementedError()
Pierre-Yves David
abstractsmartset: document the `fastasc` and `fastdesc` attributes/methods...
r22716 # Attributes containing a function to perform a fast iteration in a given
# direction. A smartset can have none, one, or both defined.
#
# Default value is None instead of a function returning None to avoid
# initializing an iterator just for testing if a fast method exists.
fastasc = None
fastdesc = None
Pierre-Yves David
revset: introduce an abstractsmartset class...
r22692 def isascending(self):
"""True if the set will iterate in ascending order"""
raise NotImplementedError()
def ascending(self):
"""Sorts the set in ascending order (in place).
This is part of the mandatory API for smartset."""
Pierre-Yves David
abstractsmartset: default implementation for `ascending` and `descending`...
r22713 self.sort()
Pierre-Yves David
revset: introduce an abstractsmartset class...
r22692
def isdescending(self):
"""True if the set will iterate in descending order"""
raise NotImplementedError()
def descending(self):
"""Sorts the set in descending order (in place).
This is part of the mandatory API for smartset."""
Pierre-Yves David
abstractsmartset: default implementation for `ascending` and `descending`...
r22713 self.sort(reverse=True)
Pierre-Yves David
revset: introduce an abstractsmartset class...
r22692
def min(self):
"""return the minimum element in the set"""
Pierre-Yves David
abstractsmartset: add a default implementation for min and max...
r22722 if self.fastasc is not None:
for r in self.fastasc():
return r
raise ValueError('arg is an empty sequence')
return min(self)
Pierre-Yves David
revset: introduce an abstractsmartset class...
r22692
def max(self):
"""return the maximum element in the set"""
Pierre-Yves David
abstractsmartset: add a default implementation for min and max...
r22722 if self.fastdesc is not None:
for r in self.fastdesc():
return r
raise ValueError('arg is an empty sequence')
return max(self)
Pierre-Yves David
revset: introduce an abstractsmartset class...
r22692
Pierre-Yves David
smartset: add first and last methods...
r22808 def first(self):
"""return the first element in the set (user iteration perspective)
Return None if the set is empty"""
raise NotImplementedError()
def last(self):
"""return the last element in the set (user iteration perspective)
Return None if the set is empty"""
raise NotImplementedError()
Pierre-Yves David
revset: introduce an abstractsmartset class...
r22692 def reverse(self):
"""reverse the expected iteration order"""
raise NotImplementedError()
def sort(self, reverse=True):
"""get the set to iterate in an ascending or descending order"""
raise NotImplementedError()
def __and__(self, other):
"""Returns a new object with the intersection of the two collections.
This is part of the mandatory API for smartset."""
Pierre-Yves David
abstractsmartset: add default implementation for __and__
r22728 return self.filter(other.__contains__)
Pierre-Yves David
revset: introduce an abstractsmartset class...
r22692
def __add__(self, other):
"""Returns a new object with the union of the two collections.
This is part of the mandatory API for smartset."""
Pierre-Yves David
abstractsmartset: add default implementation for __add__
r22729 kwargs = {}
if self.isascending() and other.isascending():
kwargs['ascending'] = True
if self.isdescending() and other.isdescending():
kwargs['ascending'] = False
Pierre-Yves David
addset: drop the leading underscore from the class name...
r22793 return addset(self, other, **kwargs)
Pierre-Yves David
revset: introduce an abstractsmartset class...
r22692
def __sub__(self, other):
"""Returns a new object with the substraction of the two collections.
This is part of the mandatory API for smartset."""
Pierre-Yves David
abstractsmartset: add default implementation for __sub__
r22730 c = other.__contains__
return self.filter(lambda r: not c(r))
Pierre-Yves David
revset: introduce an abstractsmartset class...
r22692
def filter(self, condition):
"""Returns this smartset filtered by condition as a new smartset.
`condition` is a callable which takes a revision number and returns a
boolean.
This is part of the mandatory API for smartset."""
Pierre-Yves David
abstractsmartset: add default implementation for filter
r22727 kwargs = {}
if self.isascending():
kwargs['ascending'] = True
elif self.isdescending():
kwargs['ascending'] = False
return filteredset(self, condition, **kwargs)
Pierre-Yves David
revset: introduce an abstractsmartset class...
r22692
Pierre-Yves David
baseset: stop inheriting from built-in list class...
r22825 class baseset(abstractsmartset):
Lucas Moscovicz
revset: added docstring to baseset class
r20416 """Basic data structure that represents a revset and contains the basic
operation that it should be able to perform.
Lucas Moscovicz
revset: added comments to all methods needed to duck-type from baseset...
r20727
Every method in this class should be implemented by any smartset class.
Lucas Moscovicz
revset: added docstring to baseset class
r20416 """
Pierre-Yves David
revset: add a default argument for baseset.__init__...
r20752 def __init__(self, data=()):
Pierre-Yves David
baseset: stop inheriting from built-in list class...
r22825 if not isinstance(data, list):
data = list(data)
self._list = data
Lucas Moscovicz
revset: implemented set caching for revset evaluation...
r20365 self._set = None
Pierre-Yves David
baseset: implement a fastasc and fastdesc...
r22826 @util.propertycache
def _asclist(self):
asclist = self._list[:]
asclist.sort()
return asclist
def fastasc(self):
return iter(self._asclist)
def fastdesc(self):
return reversed(self._asclist)
Lucas Moscovicz
revset: implemented set caching for revset evaluation...
r20365 def set(self):
Lucas Moscovicz
revset: added comments to all methods needed to duck-type from baseset...
r20727 """Returns a set or a smartset containing all the elements.
The returned structure should be the fastest option for membership
testing.
This is part of the mandatory API for smartset."""
Lucas Moscovicz
revset: implemented set caching for revset evaluation...
r20365 if not self._set:
self._set = set(self)
return self._set
Lucas Moscovicz
revset: added baseset class (still empty) to improve revset performance...
r20364
Pierre-Yves David
revset: add an optimised baseset.__contains__ (issue4371)...
r22503 @util.propertycache
def __contains__(self):
return self.set().__contains__
Pierre-Yves David
revset: add a `__nonzero__` to baseset...
r22691 def __nonzero__(self):
Pierre-Yves David
baseset: stop inheriting from built-in list class...
r22825 return bool(self._list)
def sort(self, reverse=False):
self._list.sort(reverse=reverse)
def reverse(self):
self._list.reverse()
def __iter__(self):
return iter(self._list)
def __len__(self):
return len(self._list)
Pierre-Yves David
revset: add a `__nonzero__` to baseset...
r22691
Lucas Moscovicz
revset: use more explicit argument names for baseset methods...
r20726 def __sub__(self, other):
Lucas Moscovicz
revset: added comments to all methods needed to duck-type from baseset...
r20727 """Returns a new object with the substraction of the two collections.
This is part of the mandatory API for smartset."""
Gregory Szorc
revset: optimize baseset.__sub__ (issue4313)...
r21939 # If we are operating on 2 baseset, do the computation now since all
Pierre-Yves David
lazyset: rename the class to filteredset...
r22726 # data is available. The alternative is to involve a filteredset, which
Gregory Szorc
revset: optimize baseset.__sub__ (issue4313)...
r21939 # may be slow.
if isinstance(other, baseset):
other = other.set()
return baseset([x for x in self if x not in other])
Matt Mackall
revset: maintain ordering when subtracting from a baseset (issue4289)
r21870 return self.filter(lambda x: x not in other)
Lucas Moscovicz
revset: added substraction to baseset class...
r20366
Lucas Moscovicz
revset: use more explicit argument names for baseset methods...
r20726 def __and__(self, other):
Lucas Moscovicz
revset: added comments to all methods needed to duck-type from baseset...
r20727 """Returns a new object with the intersection of the two collections.
Lucas Moscovicz
revset: added intersection to baseset class...
r20367
Lucas Moscovicz
revset: added comments to all methods needed to duck-type from baseset...
r20727 This is part of the mandatory API for smartset."""
Lucas Moscovicz
revset: use more explicit argument names for baseset methods...
r20726 return baseset([y for y in self if y in other])
Lucas Moscovicz
revset: added comments to all methods needed to duck-type from baseset...
r20727
Lucas Moscovicz
revset: use more explicit argument names for baseset methods...
r20726 def __add__(self, other):
Lucas Moscovicz
revset: added comments to all methods needed to duck-type from baseset...
r20727 """Returns a new object with the union of the two collections.
This is part of the mandatory API for smartset."""
Lucas Moscovicz
revset: added __add__ method to baseset class
r20417 s = self.set()
Lucas Moscovicz
revset: use more explicit argument names for baseset methods...
r20726 l = [r for r in other if r not in s]
Lucas Moscovicz
revset: added __add__ method to baseset class
r20417 return baseset(list(self) + l)
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725 def isascending(self):
Lucas Moscovicz
revset: added comments to all methods needed to duck-type from baseset...
r20727 """Returns True if the collection is ascending order, False if not.
This is part of the mandatory API for smartset."""
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725 return False
def isdescending(self):
Lucas Moscovicz
revset: added comments to all methods needed to duck-type from baseset...
r20727 """Returns True if the collection is descending order, False if not.
This is part of the mandatory API for smartset."""
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725 return False
Pierre-Yves David
baseset: implement `first` and `last` methods
r22812 def first(self):
if self:
Pierre-Yves David
baseset: stop inheriting from built-in list class...
r22825 return self._list[0]
Pierre-Yves David
baseset: implement `first` and `last` methods
r22812 return None
def last(self):
if self:
Pierre-Yves David
baseset: stop inheriting from built-in list class...
r22825 return self._list[-1]
Pierre-Yves David
baseset: implement `first` and `last` methods
r22812 return None
Pierre-Yves David
lazyset: rename the class to filteredset...
r22726 class filteredset(abstractsmartset):
Lucas Moscovicz
revset: added lazyset class with basic operations...
r20427 """Duck type for baseset class which iterates lazily over the revisions in
the subset and contains a function which tests for membership in the
revset
"""
Pierre-Yves David
lazyset: add order awareness to the class...
r22725 def __init__(self, subset, condition=lambda x: True, ascending=None):
Pierre-Yves David
revset: add some documentation for lazyset
r20738 """
condition: a function that decide whether a revision in the subset
belongs to the revset or not.
"""
Lucas Moscovicz
revset: added lazyset class with basic operations...
r20427 self._subset = subset
self._condition = condition
Lucas Moscovicz
revset: added cache to lazysets...
r20512 self._cache = {}
Pierre-Yves David
lazyset: add order awareness to the class...
r22725 if ascending is not None:
ascending = bool(ascending)
self._ascending = ascending
Lucas Moscovicz
revset: added lazyset class with basic operations...
r20427
def __contains__(self, x):
Lucas Moscovicz
revset: added cache to lazysets...
r20512 c = self._cache
if x not in c:
Pierre-Yves David
revset: reduce dict lookup in lazyset.__contains__...
r22527 v = c[x] = x in self._subset and self._condition(x)
return v
Lucas Moscovicz
revset: added cache to lazysets...
r20512 return c[x]
Lucas Moscovicz
revset: added lazyset class with basic operations...
r20427
def __iter__(self):
Pierre-Yves David
lazyset: split the iteration logic from the condition filtering logic...
r22719 return self._iterfilter(self._subset)
def _iterfilter(self, it):
Lucas Moscovicz
revset: added lazyset class with basic operations...
r20427 cond = self._condition
Pierre-Yves David
lazyset: split the iteration logic from the condition filtering logic...
r22719 for x in it:
Lucas Moscovicz
revset: added lazyset class with basic operations...
r20427 if cond(x):
yield x
Pierre-Yves David
lazyset: inherit the fastasc and fastdesc method from subset...
r22720 @property
def fastasc(self):
it = self._subset.fastasc
if it is None:
return None
return lambda: self._iterfilter(it())
@property
def fastdesc(self):
it = self._subset.fastdesc
if it is None:
return None
return lambda: self._iterfilter(it())
Lucas Moscovicz
revset: added __nonzero__ method to lazyset...
r20552 def __nonzero__(self):
for r in self:
return True
return False
Lucas Moscovicz
revset: added operations to duck type baseset...
r20429 def __len__(self):
# Basic implementation to be changed in future patches.
l = baseset([r for r in self])
return len(l)
def __getitem__(self, x):
# Basic implementation to be changed in future patches.
l = baseset([r for r in self])
return l[x]
def sort(self, reverse=False):
Pierre-Yves David
lazyset: add order awareness to the class...
r22725 if self._ascending is None:
if not util.safehasattr(self._subset, 'sort'):
self._subset = baseset(self._subset)
self._subset.sort(reverse=reverse)
self._ascending = not reverse
elif bool(reverse) == self._ascending:
self.reverse()
Lucas Moscovicz
revset: added operations to duck type baseset...
r20429
def reverse(self):
self._subset.reverse()
Pierre-Yves David
lazyset: add order awareness to the class...
r22725 if self._ascending is not None:
self._ascending = not self._ascending
Lucas Moscovicz
revset: added operations to duck type baseset...
r20429
def set(self):
return set([r for r in self])
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725 def isascending(self):
Pierre-Yves David
lazyset: add order awareness to the class...
r22725 return self._ascending is not None and self._ascending
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725
def isdescending(self):
Pierre-Yves David
lazyset: add order awareness to the class...
r22725 return self._ascending is not None and not self._ascending
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725
Pierre-Yves David
filteredset: implement `first` and `last`
r22813 def first(self):
for x in self:
return x
return None
def last(self):
it = None
if self._ascending is not None:
if self._ascending:
it = self.fastdesc
else:
it = self.fastasc
if it is None:
# slowly consume everything. This needs improvement
it = lambda: reversed(list(self))
for x in it():
return x
return None
Pierre-Yves David
addset: drop the leading underscore from the class name...
r22793 class addset(abstractsmartset):
Lucas Moscovicz
revset: made addset a private class...
r20708 """Represent the addition of two sets
Wrapper structure for lazily adding two structures without losing much
Lucas Moscovicz
revset: added addset class with its basic methods...
r20694 performance on the __contains__ method
Lucas Moscovicz
revset: made addset a private class...
r20708
Lucas Moscovicz
revset: added ascending attribute to addset class...
r20712 If the ascending attribute is set, that means the two structures are
ordered in either an ascending or descending way. Therefore, we can add
Mads Kiilerich
spelling: fixes from spell checker
r21024 them maintaining the order by iterating over both at the same time
Lucas Moscovicz
revset: added addset class with its basic methods...
r20694 """
Lucas Moscovicz
revset: added ascending attribute to addset class...
r20712 def __init__(self, revs1, revs2, ascending=None):
Lucas Moscovicz
revset: added addset class with its basic methods...
r20694 self._r1 = revs1
self._r2 = revs2
self._iter = None
Lucas Moscovicz
revset: added ascending attribute to addset class...
r20712 self._ascending = ascending
Lucas Moscovicz
revset: added cached generated list to addset...
r20720 self._genlist = None
Pierre-Yves David
_addset: add a __len__ method...
r20845 def __len__(self):
return len(self._list)
Pierre-Yves David
addset: add a __nonzero__ method...
r22743 def __nonzero__(self):
return bool(self._r1 or self._r2)
Lucas Moscovicz
revset: added cached generated list to addset...
r20720 @util.propertycache
def _list(self):
if not self._genlist:
self._genlist = baseset(self._iterator())
return self._genlist
Lucas Moscovicz
revset: added addset class with its basic methods...
r20694
def _iterator(self):
Lucas Moscovicz
revset: changed _iterator() method on addset to work with a given order...
r20722 """Iterate over both collections without repeating elements
If the ascending attribute is not set, iterate over the first one and
then over the second one checking for membership on the first one so we
dont yield any duplicates.
If the ascending attribute is set, iterate over both collections at the
same time, yielding only one value at a time in the given order.
"""
Pierre-Yves David
addset: drop caching through generatorset...
r22799 if self._ascending is None:
def gen():
for r in self._r1:
yield r
s = self._r1.set()
for r in self._r2:
if r not in s:
Lucas Moscovicz
revset: added addset class with its basic methods...
r20694 yield r
Pierre-Yves David
addset: drop caching through generatorset...
r22799 gen = gen()
else:
iter1 = iter(self._r1)
iter2 = iter(self._r2)
gen = self._iterordered(self._ascending, iter1, iter2)
return gen
Lucas Moscovicz
revset: added addset class with its basic methods...
r20694
def __iter__(self):
Lucas Moscovicz
revset: changed _iterator() in addset to use the generated list when available...
r20721 if self._genlist:
return iter(self._genlist)
return iter(self._iterator())
Lucas Moscovicz
revset: added addset class with its basic methods...
r20694
Pierre-Yves David
addset: offer a fastasc and fastdesc methods...
r22742 @property
def fastasc(self):
iter1 = self._r1.fastasc
iter2 = self._r2.fastasc
if None in (iter1, iter2):
return None
return lambda: self._iterordered(True, iter1(), iter2())
@property
def fastdesc(self):
iter1 = self._r1.fastdesc
iter2 = self._r2.fastdesc
if None in (iter1, iter2):
return None
return lambda: self._iterordered(False, iter1(), iter2())
Pierre-Yves David
addset: split simple and ordered iteration...
r22741 def _iterordered(self, ascending, iter1, iter2):
"""produce an ordered iteration from two iterators with the same order
The ascending is used to indicated the iteration direction.
"""
choice = max
if ascending:
choice = min
val1 = None
val2 = None
choice = max
Pierre-Yves David
addset: use the ascending argument in _iterordered...
r22791 if ascending:
Pierre-Yves David
addset: split simple and ordered iteration...
r22741 choice = min
try:
# Consume both iterators in an ordered way until one is
# empty
while True:
if val1 is None:
val1 = iter1.next()
if val2 is None:
val2 = iter2.next()
next = choice(val1, val2)
yield next
if val1 == next:
val1 = None
if val2 == next:
val2 = None
except StopIteration:
# Flush any remaining values and consume the other one
it = iter2
if val1 is not None:
yield val1
it = iter1
elif val2 is not None:
# might have been equality and both are empty
yield val2
for val in it:
yield val
Lucas Moscovicz
revset: added addset class with its basic methods...
r20694 def __contains__(self, x):
return x in self._r1 or x in self._r2
Lucas Moscovicz
revset: added set method to addset to duck type generatorset...
r20711 def set(self):
return self
Lucas Moscovicz
revset: added sort method in addset...
r20724 def sort(self, reverse=False):
"""Sort the added set
For this we use the cached list with all the generated values and if we
know they are ascending or descending we can sort them in a smart way.
"""
if self._ascending is None:
self._list.sort(reverse=reverse)
self._ascending = not reverse
else:
if bool(self._ascending) == bool(reverse):
self.reverse()
Lucas Moscovicz
revset: added isascending and isdescending methods to _addset...
r20733 def isascending(self):
return self._ascending is not None and self._ascending
def isdescending(self):
return self._ascending is not None and not self._ascending
Lucas Moscovicz
revset: added reverse method to addset...
r20723 def reverse(self):
self._list.reverse()
if self._ascending is not None:
self._ascending = not self._ascending
Pierre-Yves David
addset: implement first and last methods...
r22810 def first(self):
if self:
return self._list.first()
return None
def last(self):
if self:
return self._list.last()
return None
Pierre-Yves David
generatorset: drop the leading underscore in the class name...
r22795 class generatorset(abstractsmartset):
Lucas Moscovicz
revset: made generatorset a private class...
r20705 """Wrap a generator for lazy iteration
Wrapper structure for generators that provides lazy membership and can
Lucas Moscovicz
revset: added cached generated list on generatorset...
r20540 be iterated more than once.
When asked for membership it generates values until either it finds the
requested one or has gone through all the elements in the generator
"""
Pierre-Yves David
generatorset: make it possible to use gen as fastasc or fastdesc...
r22755 def __init__(self, gen, iterasc=None):
Pierre-Yves David
revset: add documentation and comment for _generatorset...
r20739 """
gen: a generator producing the values for the generatorset.
"""
Lucas Moscovicz
revset: added generatorset class with cached __contains__ method
r20536 self._gen = gen
Pierre-Yves David
generatorset: get list-based fast iterations after the generator is consumed...
r22798 self._asclist = None
Lucas Moscovicz
revset: added generatorset class with cached __contains__ method
r20536 self._cache = {}
Pierre-Yves David
generatorset: stop using a base as the _genlist...
r22796 self._genlist = []
Lucas Moscovicz
revset: added sort methods to generatorsets...
r20703 self._finished = False
Pierre-Yves David
generatorset: explicitly track iteration order...
r22800 self._ascending = True
Pierre-Yves David
generatorset: make it possible to use gen as fastasc or fastdesc...
r22755 if iterasc is not None:
if iterasc:
Pierre-Yves David
generatorset: move iteration code into _iterator...
r22797 self.fastasc = self._iterator
Pierre-Yves David
generatorset: move membership testing on ordered gen to the main class...
r22757 self.__contains__ = self._asccontains
Pierre-Yves David
generatorset: make it possible to use gen as fastasc or fastdesc...
r22755 else:
Pierre-Yves David
generatorset: move iteration code into _iterator...
r22797 self.fastdesc = self._iterator
Pierre-Yves David
generatorset: move membership testing on ordered gen to the main class...
r22757 self.__contains__ = self._desccontains
Lucas Moscovicz
revset: added cached generated list on generatorset...
r20540
Pierre-Yves David
generatorset: implement __nonzero__...
r22739 def __nonzero__(self):
for r in self:
return True
return False
Lucas Moscovicz
revset: added generatorset class with cached __contains__ method
r20536 def __contains__(self, x):
if x in self._cache:
return self._cache[x]
Gregory Szorc
revset: improve performance of _generatorset.__contains__ (issue 4201)...
r20828 # Use new values only, as existing values would be cached.
for l in self._consumegen():
Lucas Moscovicz
revset: changed generatorset code to remove unnecesary function call...
r20634 if l == x:
return True
Lucas Moscovicz
revset: added generatorset class with cached __contains__ method
r20536
self._cache[x] = False
return False
Pierre-Yves David
generatorset: move membership testing on ordered gen to the main class...
r22757 def _asccontains(self, x):
"""version of contains optimised for ascending generator"""
if x in self._cache:
return self._cache[x]
# Use new values only, as existing values would be cached.
for l in self._consumegen():
if l == x:
return True
if l > x:
break
self._cache[x] = False
return False
def _desccontains(self, x):
"""version of contains optimised for descending generator"""
if x in self._cache:
return self._cache[x]
# Use new values only, as existing values would be cached.
for l in self._consumegen():
if l == x:
return True
if l < x:
break
self._cache[x] = False
return False
Lucas Moscovicz
revset: added generatorset class with cached __contains__ method
r20536 def __iter__(self):
Pierre-Yves David
generatorset: explicitly track iteration order...
r22800 if self._ascending:
it = self.fastasc
else:
it = self.fastdesc
if it is not None:
return it()
# we need to consume the iterator
for x in self._consumegen():
pass
# recall the same code
return iter(self)
Pierre-Yves David
generatorset: move iteration code into _iterator...
r22797
def _iterator(self):
Durham Goode
revset: fix generatorset race condition...
r20833 if self._finished:
Pierre-Yves David
revset: rely on built in iterator when possible in _generatorset.__iter__...
r22670 return iter(self._genlist)
Durham Goode
revset: fix generatorset race condition...
r20833
Pierre-Yves David
revset: document the choice made in __generatorset.__iter__...
r22494 # We have to use this complex iteration strategy to allow multiple
# iterations at the same time. We need to be able to catch revision
# removed from `consumegen` and added to genlist in another instance.
#
# Getting rid of it would provide an about 15% speed up on this
# iteration.
Durham Goode
revset: fix generatorset race condition...
r20833 genlist = self._genlist
Pierre-Yves David
revset: prefetch an attribute in _generatorset.__iter__...
r22669 nextrev = self._consumegen().next
_len = len # cache global lookup
Pierre-Yves David
revset: rely on built in iterator when possible in _generatorset.__iter__...
r22670 def gen():
i = 0
while True:
if i < _len(genlist):
yield genlist[i]
else:
yield nextrev()
i += 1
return gen()
Gregory Szorc
revset: improve performance of _generatorset.__contains__ (issue 4201)...
r20828
def _consumegen(self):
Pierre-Yves David
revset: avoid in loop lookup in _generatorset._consumegen...
r22528 cache = self._cache
genlist = self._genlist.append
Lucas Moscovicz
revset: changed generatorset code to remove unnecesary function call...
r20634 for item in self._gen:
Pierre-Yves David
revset: avoid in loop lookup in _generatorset._consumegen...
r22528 cache[item] = True
genlist(item)
Lucas Moscovicz
revset: changed generatorset code to remove unnecesary function call...
r20634 yield item
Pierre-Yves David
generatorset: get list-based fast iterations after the generator is consumed...
r22798 if not self._finished:
self._finished = True
asc = self._genlist[:]
asc.sort()
self._asclist = asc
self.fastasc = asc.__iter__
self.fastdesc = asc.__reversed__
Lucas Moscovicz
revset: added sort methods to generatorsets...
r20703
Lucas Moscovicz
revset: added generatorset class with cached __contains__ method
r20536 def set(self):
return self
Lucas Moscovicz
revset: added sort methods to generatorsets...
r20703 def sort(self, reverse=False):
Pierre-Yves David
generatorset: explicitly track iteration order...
r22800 self._ascending = not reverse
def reverse(self):
self._ascending = not self._ascending
Lucas Moscovicz
revset: added sort methods to generatorsets...
r20703
Pierre-Yves David
generatorset: implement isascending and isdescending
r22801 def isascending(self):
return self._ascending
def isdescending(self):
return not self._ascending
Pierre-Yves David
generatorset: implement first and last methods
r22811 def first(self):
if self._ascending:
it = self.fastasc
else:
it = self.fastdesc
if it is None:
# we need to consume all and try again
for x in self._consumegen():
pass
return self.first()
if self:
return it.next()
return None
def last(self):
if self._ascending:
it = self.fastdesc
else:
it = self.fastasc
if it is None:
# we need to consume all and try again
for x in self._consumegen():
pass
return self.first()
if self:
return it.next()
return None
Pierre-Yves David
revset: turn spanset into a factory function...
r22509 def spanset(repo, start=None, end=None):
"""factory function to dispatch between fullreposet and actual spanset
Feel free to update all spanset call sites and kill this function at some
point.
"""
if start is None and end is None:
return fullreposet(repo)
return _spanset(repo, start, end)
Pierre-Yves David
spanset: drop _orderedsetmixin inheritance...
r22752 class _spanset(abstractsmartset):
Lucas Moscovicz
revset: added spanset class to represent revision ranges
r20482 """Duck type for baseset class which represents a range of revisions and
can work lazily and without having all the range in memory
Lucas Moscovicz
revset: added documentation and comment for spanset class
r20737
Note that spanset(x, y) behave almost like xrange(x, y) except for two
notable points:
- when x < y it will be automatically descending,
- revision filtered with this repoview will be skipped.
Lucas Moscovicz
revset: added spanset class to represent revision ranges
r20482 """
Lucas Moscovicz
revset: changed spanset to take a repo argument...
r20525 def __init__(self, repo, start=0, end=None):
Lucas Moscovicz
revset: added documentation and comment for spanset class
r20737 """
start: first revision included the set
(default to 0)
end: first revision excluded (last+1)
(default to len(repo)
Spanset will be descending if `end` < `start`.
"""
Pierre-Yves David
spanset: enforce the order lazily to gain `fastasc` and `fastdesc` methods...
r22717 if end is None:
end = len(repo)
self._ascending = start <= end
if not self._ascending:
start, end = end + 1, start +1
Lucas Moscovicz
revset: added spanset class to represent revision ranges
r20482 self._start = start
Pierre-Yves David
spanset: enforce the order lazily to gain `fastasc` and `fastdesc` methods...
r22717 self._end = end
Lucas Moscovicz
revset: changed spanset to take a repo argument...
r20525 self._hiddenrevs = repo.changelog.filteredrevs
Lucas Moscovicz
revset: changed spanset implementation to take hidden revisions into account...
r20521
Pierre-Yves David
spanset: enforce the order lazily to gain `fastasc` and `fastdesc` methods...
r22717 def sort(self, reverse=False):
self._ascending = not reverse
def reverse(self):
self._ascending = not self._ascending
def _iterfilter(self, iterrange):
s = self._hiddenrevs
for r in iterrange:
if r not in s:
yield r
Lucas Moscovicz
revset: added spanset class to represent revision ranges
r20482 def __iter__(self):
Pierre-Yves David
spanset: enforce the order lazily to gain `fastasc` and `fastdesc` methods...
r22717 if self._ascending:
return self.fastasc()
Lucas Moscovicz
revset: added spanset class to represent revision ranges
r20482 else:
Pierre-Yves David
spanset: enforce the order lazily to gain `fastasc` and `fastdesc` methods...
r22717 return self.fastdesc()
def fastasc(self):
iterrange = xrange(self._start, self._end)
Lucas Moscovicz
revset: changed spanset implementation to take hidden revisions into account...
r20521 if self._hiddenrevs:
Pierre-Yves David
spanset: enforce the order lazily to gain `fastasc` and `fastdesc` methods...
r22717 return self._iterfilter(iterrange)
return iter(iterrange)
def fastdesc(self):
iterrange = xrange(self._end - 1, self._start - 1, -1)
if self._hiddenrevs:
return self._iterfilter(iterrange)
return iter(iterrange)
Lucas Moscovicz
revset: added spanset class to represent revision ranges
r20482
Pierre-Yves David
revset: fix revision filtering in spanset.contains (regression)...
r21201 def __contains__(self, rev):
Pierre-Yves David
revset: do less lookup during spanset.__contains__...
r22526 hidden = self._hiddenrevs
Pierre-Yves David
spanset: do a single range check in __contains__...
r22718 return ((self._start <= rev < self._end)
Pierre-Yves David
revset: do less lookup during spanset.__contains__...
r22526 and not (hidden and rev in hidden))
Lucas Moscovicz
revset: added spanset class to represent revision ranges
r20482
Lucas Moscovicz
revset: added __nonzero__ method to spanset class...
r20716 def __nonzero__(self):
for r in self:
return True
return False
Lucas Moscovicz
revset: added operations to spanset to duck type baseset...
r20484 def __len__(self):
Lucas Moscovicz
revset: changed spanset implementation to take hidden revisions into account...
r20521 if not self._hiddenrevs:
return abs(self._end - self._start)
else:
count = 0
Pierre-Yves David
revset: also inline spanset._contained in __len__...
r21205 start = self._start
end = self._end
Lucas Moscovicz
revset: changed spanset implementation to take hidden revisions into account...
r20521 for rev in self._hiddenrevs:
Pierre-Yves David
revset: cosmetic changes in spanset range comparison...
r21284 if (end < rev <= start) or (start <= rev < end):
Lucas Moscovicz
revset: changed spanset implementation to take hidden revisions into account...
r20521 count += 1
return abs(self._end - self._start) - count
Lucas Moscovicz
revset: added operations to spanset to duck type baseset...
r20484
def __getitem__(self, x):
# Basic implementation to be changed in future patches.
l = baseset([r for r in self])
return l[x]
def set(self):
return self
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725 def isascending(self):
Pierre-Yves David
revset: wider definition of ascending and descending for spanset...
r22481 return self._start <= self._end
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725
def isdescending(self):
Pierre-Yves David
revset: wider definition of ascending and descending for spanset...
r22481 return self._start >= self._end
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725
Pierre-Yves David
spanset: implement `first` and `last` methods
r22809 def first(self):
if self._ascending:
it = self.fastasc
else:
it = self.fastdesc
for x in it():
return x
return None
def last(self):
if self._ascending:
it = self.fastdesc
else:
it = self.fastasc
for x in it():
return x
return None
Pierre-Yves David
revset: turn spanset into a factory function...
r22509 class fullreposet(_spanset):
Pierre-Yves David
revert: add a fullreposet class...
r22508 """a set containing all revisions in the repo
This class exists to host special optimisation.
"""
def __init__(self, repo):
super(fullreposet, self).__init__(repo)
Pierre-Yves David
revset: fast implementation for fullreposet.__and__...
r22510 def __and__(self, other):
"""fullrepo & other -> other
As self contains the whole repo, all of the other set should also be in
self. Therefor `self & other = other`.
This boldly assumes the other contains valid revs only.
"""
# other not a smartset, make is so
if not util.safehasattr(other, 'set'):
# filter out hidden revision
# (this boldly assumes all smartset are pure)
#
# `other` was used with "&", let's assume this is a set like
# object.
other = baseset(other - self._hiddenrevs)
elif not util.safehasattr(other, 'ascending'):
Pierre-Yves David
generatorset: drop the leading underscore in the class name...
r22795 # "other" is generatorset not a real smart set
Pierre-Yves David
revset: fast implementation for fullreposet.__and__...
r22510 # we fallback to the old way (sad kitten)
return super(fullreposet, self).__and__(other)
# preserve order:
#
# this is probably useless and harmful in multiple cases but matches
# the current behavior.
if self.isascending():
other.ascending()
else:
other.descending()
return other
Patrick Mezard
hggettext: handle i18nfunctions declaration for docstrings translations
r12823 # tell hggettext to extract docstrings from these functions:
i18nfunctions = symbols.values()