##// END OF EJS Templates
util: extract the logic calculating environment variables...
util: extract the logic calculating environment variables The method will be reused in chgserver. Move it out so it can be reused.

File last commit:

r30719:42c75b4f default
r30736:d9e5b0ae default
Show More
revset.py
3892 lines | 127.9 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.
Gregory Szorc
revset: use absolute_import
r25971 from __future__ import absolute_import
Lucas Moscovicz
revset: changed ancestors revset to return lazy generators...
r20690 import heapq
Gregory Szorc
revset: use absolute_import
r25971 import re
Augie Fackler
revset: build _syminitletters from a saner source: the string module...
r30071 import string
Gregory Szorc
revset: use absolute_import
r25971
from .i18n import _
from . import (
Pierre-Yves David
revset: reintroduce and experimental revset for update destination...
r26713 destutil,
Gregory Szorc
revset: use absolute_import
r25971 encoding,
error,
hbisect,
match as matchmod,
node,
obsolete as obsmod,
parser,
pathutil,
phases,
Augie Fackler
revset: build _syminitletters from a saner source: the string module...
r30071 pycompat,
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 registrar,
Gregory Szorc
revset: use absolute_import
r25971 repoview,
util,
)
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."""
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 if followfirst:
cut = 1
else:
cut = None
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 cl = repo.changelog
Lucas Moscovicz
revset: changed ancestors revset to return lazy generators...
r20690
def iterate():
Pierre-Yves David
revancestors: replace `descending` with `sort(reverse=False)`
r22832 revs.sort(reverse=True)
Pierre-Yves David
revset: use an iterator instead of a dequeue in ancestors()...
r24939 irevs = iter(revs)
Lucas Moscovicz
revset: optimized _revancestors method based on order of revisions...
r20691 h = []
Pierre-Yves David
_revancestors: use 'next' to remove the verbose try except clauses...
r25143 inputrev = next(irevs, None)
if inputrev is not None:
Pierre-Yves David
revset: use an iterator instead of a dequeue in ancestors()...
r24939 heapq.heappush(h, -inputrev)
Lucas Moscovicz
revset: optimized _revancestors method based on order of revisions...
r20691
Yuya Nishihara
revset: fix ancestors(null) to include null revision (issue4512)...
r23956 seen = set()
Lucas Moscovicz
revset: changed ancestors revset to return lazy generators...
r20690 while h:
current = -heapq.heappop(h)
Pierre-Yves David
revset: avoid returning duplicates when returning ancestors...
r24940 if current == inputrev:
Pierre-Yves David
_revancestors: use 'next' to remove the verbose try except clauses...
r25143 inputrev = next(irevs, None)
if inputrev is not None:
Pierre-Yves David
revset: avoid returning duplicates when returning ancestors...
r24940 heapq.heappush(h, -inputrev)
Lucas Moscovicz
revset: changed ancestors revset to return lazy generators...
r20690 if current not in seen:
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."""
Jordi Gutiérrez Hermoso
style: kill ersatz if-else ternary operators...
r24306 if followfirst:
cut = 1
else:
cut = None
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409
Lucas Moscovicz
revset: changed descendants revset to use lazy generators...
r20692 def iterate():
cl = repo.changelog
Pierre-Yves David
revset: mark spots that should use 'smartset.min()'...
r25549 # XXX this should be 'parentset.min()' assuming 'parentset' is a
# smartset (and if it is not, it should.)
Lucas Moscovicz
revset: changed descendants revset to use lazy generators...
r20692 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
Yuya Nishihara
revset: mark reachablerootspure as private
r26095 def _reachablerootspure(repo, minroot, roots, heads, includepath):
Laurent Charignon
revset: rename revsbetween to reachableroots and add an argument...
r26002 """return (heads(::<roots> and ::<heads>))
If includepath is True, return (<roots>::<heads>)."""
Bryan O'Sullivan
revset: introduce and use _revsbetween...
r16862 if not roots:
Yuya Nishihara
reachableroots: construct and sort baseset in revset module...
r26094 return []
Bryan O'Sullivan
revset: introduce and use _revsbetween...
r16862 parentrevs = repo.changelog.parentrevs
Yuya Nishihara
reachableroots: use internal "revstates" array to test if rev is a root...
r26053 roots = set(roots)
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 = {}
Pierre-Yves David
revset: prefetch all attributes before loop in _revsbetween...
r25566 # prefetch all the things! (because python is slow)
reached = reachable.add
dovisit = visit.append
nextvisit = visit.pop
Bryan O'Sullivan
revset: introduce and use _revsbetween...
r16862 # open-code the post-order traversal due to the tiny size of
# sys.getrecursionlimit()
while visit:
Pierre-Yves David
revset: prefetch all attributes before loop in _revsbetween...
r25566 rev = nextvisit()
Bryan O'Sullivan
revset: introduce and use _revsbetween...
r16862 if rev in roots:
Pierre-Yves David
revset: prefetch all attributes before loop in _revsbetween...
r25566 reached(rev)
Laurent Charignon
revset: rename revsbetween to reachableroots and add an argument...
r26002 if not includepath:
continue
Bryan O'Sullivan
revset: introduce and use _revsbetween...
r16862 parents = parentrevs(rev)
seen[rev] = parents
for parent in parents:
if parent >= minroot and parent not in seen:
Pierre-Yves David
revset: prefetch all attributes before loop in _revsbetween...
r25566 dovisit(parent)
Bryan O'Sullivan
revset: introduce and use _revsbetween...
r16862 if not reachable:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Laurent Charignon
revset: rename revsbetween to reachableroots and add an argument...
r26002 if not includepath:
return reachable
Bryan O'Sullivan
revset: introduce and use _revsbetween...
r16862 for rev in sorted(seen):
for parent in seen[rev]:
if parent in reachable:
Pierre-Yves David
revset: prefetch all attributes before loop in _revsbetween...
r25566 reached(rev)
Pierre-Yves David
reachableroots: sort the smartset in the pure version too...
r26091 return reachable
Bryan O'Sullivan
revset: introduce and use _revsbetween...
r16862
Laurent Charignon
reachableroots: default to the C implementation...
r26006 def reachableroots(repo, roots, heads, includepath=False):
"""return (heads(::<roots> and ::<heads>))
If includepath is True, return (<roots>::<heads>)."""
if not roots:
return baseset()
Pierre-Yves David
reachableroots: use smartset min...
r26093 minroot = roots.min()
Yuya Nishihara
reachableroots: use internal "revstates" array to test if rev is a root...
r26053 roots = list(roots)
Laurent Charignon
reachableroots: default to the C implementation...
r26006 heads = list(heads)
try:
Yuya Nishihara
reachableroots: construct and sort baseset in revset module...
r26094 revs = repo.changelog.reachableroots(minroot, heads, roots, includepath)
Laurent Charignon
reachableroots: default to the C implementation...
r26006 except AttributeError:
Yuya Nishihara
revset: mark reachablerootspure as private
r26095 revs = _reachablerootspure(repo, minroot, roots, heads, includepath)
Yuya Nishihara
reachableroots: construct and sort baseset in revset module...
r26094 revs = baseset(revs)
revs.sort()
return revs
Laurent Charignon
reachableroots: default to the C implementation...
r26006
Matt Mackall
revset: introduce revset core
r11275 elements = {
Yuya Nishihara
parser: separate actions for primary expression and prefix operator...
r25815 # token-type: binding-strength, primary, prefix, infix, suffix
"(": (21, None, ("group", 1, ")"), ("func", 1, ")"), None),
"##": (20, None, None, ("_concat", 20), None),
"~": (18, None, None, ("ancestor", 18), None),
Yuya Nishihara
parser: remove unused binding parameter from suffix action...
r29767 "^": (18, None, None, ("parent", 18), "parentpost"),
Yuya Nishihara
parser: separate actions for primary expression and prefix operator...
r25815 "-": (5, None, ("negate", 19), ("minus", 5), None),
Yuya Nishihara
parser: remove unused binding parameter from suffix action...
r29767 "::": (17, None, ("dagrangepre", 17), ("dagrange", 17), "dagrangepost"),
"..": (17, None, ("dagrangepre", 17), ("dagrange", 17), "dagrangepost"),
":": (15, "rangeall", ("rangepre", 15), ("range", 15), "rangepost"),
Yuya Nishihara
parser: separate actions for primary expression and prefix operator...
r25815 "not": (10, None, ("not", 10), None, None),
"!": (10, None, ("not", 10), None, None),
"and": (5, None, None, ("and", 5), None),
"&": (5, None, None, ("and", 5), None),
Yuya Nishihara
parser: remove unused binding parameter from suffix action...
r29767 "%": (5, None, None, ("only", 5), "onlypost"),
Yuya Nishihara
parser: separate actions for primary expression and prefix operator...
r25815 "or": (4, None, None, ("or", 4), None),
"|": (4, None, None, ("or", 4), None),
"+": (4, None, None, ("or", 4), None),
"=": (3, None, None, ("keyvalue", 3), None),
",": (2, None, None, ("list", 2), None),
")": (0, None, None, None, None),
"symbol": (0, "symbol", None, None, None),
"string": (0, "string", None, None, None),
"end": (0, None, None, None, None),
Matt Mackall
revset: introduce revset core
r11275 }
keywords = set(['and', 'or', 'not'])
FUJIWARA Katsunori
revset: make tokenize extensible to parse alias declarations and definitions...
r23842 # default set of valid characters for the initial letter of symbols
Augie Fackler
revset: build _syminitletters from a saner source: the string module...
r30071 _syminitletters = set(
string.ascii_letters +
string.digits + pycompat.sysstr('._@')) | set(map(chr, xrange(128, 256)))
FUJIWARA Katsunori
revset: make tokenize extensible to parse alias declarations and definitions...
r23842
# default set of valid characters for non-initial letters of symbols
Augie Fackler
revset: build _syminitletters from a saner source: the string module...
r30071 _symletters = _syminitletters | set(pycompat.sysstr('-/'))
FUJIWARA Katsunori
revset: make tokenize extensible to parse alias declarations and definitions...
r23842
def tokenize(program, lookup=None, syminitletters=None, symletters=None):
Matt Mackall
revset: accept @ in unquoted symbols (issue3686)
r17886 '''
Parse a revset statement into a stream of tokens
FUJIWARA Katsunori
revset: make tokenize extensible to parse alias declarations and definitions...
r23842 ``syminitletters`` is the set of valid characters for the initial
letter of symbols.
By default, character ``c`` is recognized as valid for initial
letter of symbols, if ``c.isalnum() or c in '._@' or ord(c) > 127``.
``symletters`` is the set of valid characters for non-initial
letters of symbols.
By default, character ``c`` is recognized as valid for non-initial
letters of symbols, if ``c.isalnum() or c in '-._/@' or ord(c) > 127``.
Matt Mackall
revset: accept @ in unquoted symbols (issue3686)
r17886 Check that @ is a valid unquoted token character (issue3686):
>>> list(tokenize("@::"))
[('symbol', '@', 0), ('::', None, 1), ('end', None, 3)]
'''
FUJIWARA Katsunori
revset: make tokenize extensible to parse alias declarations and definitions...
r23842 if syminitletters is None:
syminitletters = _syminitletters
if symletters is None:
symletters = _symletters
Matt Mackall
revset: accept @ in unquoted symbols (issue3686)
r17886
Yuya Nishihara
revset: port parsing rule of old-style ranges from scmutil.revrange()...
r25902 if program and lookup:
# attempt to parse old-style ranges first to deal with
# things like old-tag which contain query metacharacters
parts = program.split(':', 1)
if all(lookup(sym) for sym in parts if sym):
if parts[0]:
yield ('symbol', parts[0], 0)
if len(parts) > 1:
s = len(parts[0])
yield (':', None, s)
if parts[1]:
yield ('symbol', parts[1], s + 1)
yield ('end', None, len(program))
return
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
FUJIWARA Katsunori
revset: introduce new operator "##" to concatenate strings/symbols at runtime...
r23742 elif c == '#' and program[pos:pos + 2] == '##': # look ahead carefully
yield ('##', None, pos)
pos += 1 # skip ahead
Yuya Nishihara
revset: add parsing rule for key=value pair...
r25704 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:
Yuya Nishihara
revset: handle error of string unescaping
r26232 decode = parser.unescapestr
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
FUJIWARA Katsunori
revset: make tokenize extensible to parse alias declarations and definitions...
r23842 elif c in syminitletters:
Matt Mackall
revset: introduce revset core
r11275 s = pos
pos += 1
while pos < l: # find end of symbol
d = program[pos]
FUJIWARA Katsunori
revset: make tokenize extensible to parse alias declarations and definitions...
r23842 if d not in symletters:
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:
Ryan McElroy
revsets: more informative syntax error message...
r24708 raise error.ParseError(_("syntax error in revset '%s'") %
program, 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
Yuya Nishihara
revset: check invalid function syntax "func-name"() explicitly...
r29441 def getsymbol(x):
if x and x[0] == 'symbol':
return x[1]
raise error.ParseError(_('not a symbol'))
Matt Mackall
revset: introduce revset core
r11275 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':
Yuya Nishihara
revset: flatten chained 'list' operations (aka function args) (issue5072)...
r27987 return list(x[1:])
Matt Mackall
revset: introduce revset core
r11275 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
Yuya Nishihara
revset: rename getkwargs() to getargsdict()...
r25767 def getargsdict(x, funcname, keys):
Yuya Nishihara
revset: add function to build dict of positional and keyword arguments...
r25705 return parser.buildargsdict(getlist(x), funcname, keys.split(),
keyvaluenode='keyvalue', keynode='symbol')
Matt Mackall
revset: introduce revset core
r11275 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:])
Pierre-Yves David
getset: check if an object is a baseset using `isascending` instead of `set`...
r22884 if util.safehasattr(s, 'isascending'):
Lucas Moscovicz
revset: changed mfunc and getset to work with old style revset methods...
r20527 return s
Pierre-Yves David
devel: use the new 'config' argument for the revset develwarn
r29098 # else case should not happen, because all non-func are internal,
# ignoring for now.
if x[0] == 'func' and x[1][0] == 'symbol' and x[1][1] in symbols:
Pierre-Yves David
devel: fix a typo in a deprecation warning...
r29147 repo.ui.deprecwarn('revset "%s" uses list instead of smartset'
Pierre-Yves David
devel: officially deprecate old style revset...
r29146 % x[1][1],
'3.9')
Lucas Moscovicz
revset: changed mfunc and getset to work with old style revset methods...
r20527 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()
Yuya Nishihara
revset: drop magic of fullreposet membership test (issue4682)...
r25265 if (x in subset
or x == node.nullrev and isinstance(subset, fullreposet)):
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
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 def rangeset(repo, subset, x, y, order):
Pierre-Yves David
revset-rangeset: call 'getset' on a 'fullreposet'...
r23162 m = getset(repo, fullreposet(repo), x)
n = getset(repo, fullreposet(repo), 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()
Yuya Nishihara
revset: extract function that creates range set from computed revisions...
r30043 return _makerangeset(repo, subset, m.first(), n.last(), order)
Yuya Nishihara
revset: do not rewrite ':y' to '0:y' (issue5385)...
r30044 def rangepre(repo, subset, y, order):
# ':y' can't be rewritten to '0:y' since '0' may be hidden
n = getset(repo, fullreposet(repo), y)
if not n:
return baseset()
return _makerangeset(repo, subset, 0, n.last(), order)
Yuya Nishihara
revset: extract function that creates range set from computed revisions...
r30043 def _makerangeset(repo, subset, m, n, order):
Yuya Nishihara
revset: work around x:y range where x or y is wdir()...
r25766 if m == n:
r = baseset([m])
elif n == node.wdirrev:
r = spanset(repo, m, len(repo)) + baseset([n])
elif m == node.wdirrev:
r = baseset([m]) + spanset(repo, len(repo) - 1, n - 1)
elif 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)
Yuya Nishihara
revset: fix order of nested 'range' expression (BC)...
r29944
if order == defineorder:
return r & subset
else:
# carrying the sorting over when possible would be more efficient
return subset & r
Matt Mackall
revset: introduce revset core
r11275
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 def dagrange(repo, subset, x, y, order):
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 r = fullreposet(repo)
Laurent Charignon
revset: rename revsbetween to reachableroots and add an argument...
r26002 xs = reachableroots(repo, getset(repo, r, x), getset(repo, r, y),
includepath=True)
Yuya Nishihara
revset: make dagrange preserve order of input set...
r29139 return subset & xs
Bryan O'Sullivan
revset: turn dagrange into a function
r16860
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 def andset(repo, subset, x, y, order):
Matt Mackall
revset: introduce revset core
r11275 return getset(repo, getset(repo, subset, x), y)
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 def differenceset(repo, subset, x, y, order):
Durham Goode
revset: use smartset minus operator...
r28217 return getset(repo, subset, x) - getset(repo, subset, y)
Yuya Nishihara
revset: wrap arguments of 'or' by 'list' node...
r29929 def _orsetlist(repo, subset, xs):
Yuya Nishihara
revset: make balanced addsets by orset() without using _combinesets()...
r25929 assert xs
if len(xs) == 1:
return getset(repo, subset, xs[0])
p = len(xs) // 2
Yuya Nishihara
revset: wrap arguments of 'or' by 'list' node...
r29929 a = _orsetlist(repo, subset, xs[:p])
b = _orsetlist(repo, subset, xs[p:])
Yuya Nishihara
revset: make balanced addsets by orset() without using _combinesets()...
r25929 return a + b
Matt Mackall
revset: introduce revset core
r11275
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 def orset(repo, subset, x, order):
Yuya Nishihara
revset: fix order of nested 'or' expression (BC)...
r29934 xs = getlist(x)
if order == followorder:
# slow path to take the subset order
return subset & _orsetlist(repo, fullreposet(repo), xs)
else:
return _orsetlist(repo, subset, xs)
Yuya Nishihara
revset: wrap arguments of 'or' by 'list' node...
r29929
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 def notset(repo, subset, x, order):
Lucas Moscovicz
revset: added substraction to baseset class...
r20366 return subset - getset(repo, subset, x)
Matt Mackall
revset: introduce revset core
r11275
Yuya Nishihara
revset: flatten chained 'list' operations (aka function args) (issue5072)...
r27987 def listset(repo, subset, *xs):
timeless
revset: add hint for list error to use or
r27517 raise error.ParseError(_("can't use a list in this context"),
hint=_('see hg help "revsets.x or y"'))
Matt Mackall
revset: introduce revset core
r11275
Yuya Nishihara
revset: add parsing rule for key=value pair...
r25704 def keyvaluepair(repo, subset, k, v):
raise error.ParseError(_("can't use a key-value pair in this context"))
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 def func(repo, subset, a, b, order):
Yuya Nishihara
revset: check invalid function syntax "func-name"() explicitly...
r29441 f = getsymbol(a)
if f in symbols:
Augie Fackler
revset: avoid shadowing a variable with a list comprehension
r30392 func = symbols[f]
if getattr(func, '_takeorder', False):
return func(repo, subset, b, order)
return func(repo, subset, b)
Matt Harbison
revset: don't suggest private or undocumented queries...
r25632
keep = lambda fn: getattr(fn, '__doc__', None) is not None
syms = [s for (s, fn) in symbols.items() if keep(fn)]
Yuya Nishihara
revset: check invalid function syntax "func-name"() explicitly...
r29441 raise error.UnknownIdentifier(f, syms)
Matt Mackall
revset: introduce revset core
r11275
# functions
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 # symbols are callables like:
# fn(repo, subset, x)
# with:
# repo - current repository instance
# subset - of revisions to be examined
# x - argument in tree form
symbols = {}
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 # 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()
FUJIWARA Katsunori
revset: replace predicate by revsetpredicate of registrar...
r28395 predicate = registrar.revsetpredicate()
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 @predicate('_destupdate')
Pierre-Yves David
revset: reintroduce and experimental revset for update destination...
r26713 def _destupdate(repo, subset, x):
# experimental revset for update destination
args = getargsdict(x, 'limit', 'clean check')
return subset & baseset([destutil.destupdate(repo, **args)[0]])
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 @predicate('_destmerge')
Pierre-Yves David
revset: rename and test '_destmerge'...
r26716 def _destmerge(repo, subset, x):
# experimental revset for merge destination
Pierre-Yves David
destutil: allow to specify an explicit source for the merge...
r28139 sourceset = None
if x is not None:
sourceset = getset(repo, fullreposet(repo), x)
return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
Pierre-Yves David
merge: move default destination computation in a revset...
r26303
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('adds(pattern)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def adds(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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)
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('ancestor(*changeset)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def ancestor(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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)
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 rl = fullreposet(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):
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 heads = getset(repo, fullreposet(repo), x)
Mads Kiilerich
revset: better naming of variables containing the value of a single argument...
r22944 if not heads:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Mads Kiilerich
revset: better naming of variables containing the value of a single argument...
r22944 s = _revancestors(repo, heads, followfirst)
Pierre-Yves David
revset-_ancestor: use & instead of filter...
r23003 return subset & s
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('ancestors(set)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def ancestors(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changesets that are ancestors of a changeset in set.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 return _ancestors(repo, subset, x)
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('_firstancestors', safe=True)
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 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
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 def ancestorspec(repo, subset, x, n, order):
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 """``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
Pierre-Yves David
revset-ancestorspec: call 'getset' on a 'fullreposet'...
r23163 for r in getset(repo, fullreposet(repo), 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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('author(string)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def author(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Alias for ``user(string)``.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# 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)
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(lambda x: matcher(encoding.lower(repo[x].user())),
condrepr=('<user %r>', n))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('bisect(string)', safe=True)
"Yann E. MORIN"
revset: rename bisected() to bisect()...
r15134 def bisect(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('bisected', safe=True)
"Yann E. MORIN"
revset: rename bisected() to bisect()...
r15134 def bisected(repo, subset, x):
return bisect(repo, subset, x)
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('bookmark([name])', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def bookmark(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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'))
Matt Harbison
util: extract stringmatcher() from revset...
r26481 kind, pattern, matcher = util.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:
FUJIWARA Katsunori
revset: raise RepoLookupError to make present() predicate continue the query...
r23978 raise error.RepoLookupError(_("bookmark '%s' does not exist")
Yuya Nishihara
revset: strip off "literal:" prefix from bookmark not found error...
r26538 % pattern)
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:
FUJIWARA Katsunori
revset: raise RepoLookupError to make present() predicate continue the query...
r23978 raise error.RepoLookupError(_("no bookmarks exist"
" that match '%s'") % pattern)
Simon King
revset: add pattern matching to 'bookmarks' revset expression
r16822 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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('branch(string or set)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def branch(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 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 """
Durham Goode
revbranchcache: store repo on the object...
r24374 getbi = repo.revbranchcache().branchinfo
Mads Kiilerich
revset: use localrepo revbranchcache for branch name filtering...
r23787
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:
Matt Harbison
util: extract stringmatcher() from revset...
r26481 kind, pattern, matcher = util.stringmatcher(b)
Simon King
revset: add pattern matching to 'branch' revset expression
r16821 if kind == 'literal':
# note: falls through to the revspec case if no branch with
Yuya Nishihara
revset: do not fall through to revspec for literal: branch (issue4838)...
r26537 # this name exists and pattern kind is not specified explicitly
Simon King
revset: add pattern matching to 'branch' revset expression
r16821 if pattern in repo.branchmap():
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(lambda r: matcher(getbi(r)[0]),
condrepr=('<branch %r>', b))
Yuya Nishihara
revset: do not fall through to revspec for literal: branch (issue4838)...
r26537 if b.startswith('literal:'):
raise error.RepoLookupError(_("branch '%s' does not exist")
% pattern)
Simon King
revset: add pattern matching to 'branch' revset expression
r16821 else:
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(lambda r: matcher(getbi(r)[0]),
condrepr=('<branch %r>', b))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 s = getset(repo, fullreposet(repo), x)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 b = set()
for r in s:
Durham Goode
revbranchcache: store repo on the object...
r24374 b.add(getbi(r)[0])
Pierre-Yves David
revset-branch: remove usage of `set()`...
r22867 c = s.__contains__
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(lambda r: c(r) or getbi(r)[0] in b,
condrepr=lambda: '<branch %r>' % sorted(b))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('bumped()', safe=True)
Pierre-Yves David
revset: add a bumped revset...
r17829 def bumped(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Mutable changesets marked as successors of public changesets.
Pierre-Yves David
revset: add a bumped revset...
r17829
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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('bundle()', safe=True)
Tomasz Kleczek
bundle: add revset expression to show bundle contents (issue3487)...
r17913 def bundle(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changesets in the bundle.
Tomasz Kleczek
bundle: add revset expression to show bundle contents (issue3487)...
r17913
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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.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
Martin von Zweigbergk
revset: don't recreate matcher for every revision...
r23115 mcache = [None]
Lucas Moscovicz
revset: added lazyset implementation to checkstatus...
r20457 def matches(x):
c = repo[x]
Martin von Zweigbergk
revset: don't recreate matcher for every revision...
r23115 if not mcache[0] or hasset:
mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
m = mcache[0]
fname = None
if not m.anypats() and len(m.files()) == 1:
fname = m.files()[0]
Patrick Mezard
revset: fix adds/modifies/removes and patterns (issue3403)...
r16521 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
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(matches, condrepr=('<status[%r] %r>', field, pat))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
Martin von Zweigbergk
revsets: passing a set to baseset() is not wrong...
r29406 def _children(repo, subset, parentset):
Pierre-Yves David
revset: gratuitous code move in '_children'...
r25550 if not parentset:
return baseset()
Matt Mackall
revset: optimize roots and children
r15899 cs = set()
pr = repo.changelog.parentrevs
Pierre-Yves David
revset: use parentsets.min in _children...
r25567 minrev = parentset.min()
Yuya Nishihara
revset: make children() not look at p2 if null (issue5439)...
r30699 nullrev = node.nullrev
Martin von Zweigbergk
revsets: passing a set to baseset() is not wrong...
r29406 for r in subset:
Siddharth Agarwal
revset.children: ignore rev numbers that are too low...
r18063 if r <= minrev:
continue
Yuya Nishihara
revset: make children() not look at p2 if null (issue5439)...
r30699 p1, p2 = pr(r)
if p1 in parentset:
cs.add(r)
if p2 != nullrev and p2 in parentset:
cs.add(r)
Matt Mackall
revsets: backout d04aac468bf4 due to performance regressions
r20709 return baseset(cs)
Matt Mackall
revset: optimize roots and children
r15899
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('children(set)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def children(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Child changesets of changesets in set.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
Pierre-Yves David
revset-children: call 'getset' on a 'fullreposet'...
r23164 s = getset(repo, fullreposet(repo), x)
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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('closed()', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def closed(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changeset is closed.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# i18n: "closed" is a keyword
getargs(x, 0, 0, _("closed takes no arguments"))
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(lambda r: repo[r].closesbranch(),
condrepr='<branch closed>')
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 @predicate('contains(pattern)')
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def contains(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """The revision's manifest contains a file matching pattern (but might not
Greg Hurrell
help: clarify distinction among `contains`/`file`/`filelog`...
r21199 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
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(matches, condrepr=('<contains %r>', pat))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('converted([id])', safe=True)
Matt Harbison
revset: add a predicate for finding converted changesets...
r17002 def converted(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changesets converted from the given identifier in the old repository if
Matt Harbison
revset: add a predicate for finding converted changesets...
r17002 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))
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(lambda r: _matchvalue(r),
condrepr=('<converted %r>', rev))
Matt Harbison
revset: add a predicate for finding converted changesets...
r17002
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('date(interval)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def date(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changesets within the interval, see :hg:`help dates`.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# i18n: "date" is a keyword
ds = getstring(x, _("date requires a string"))
dm = util.matchdate(ds)
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(lambda x: dm(repo[x].date()[0]),
condrepr=('<date %r>', ds))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('desc(string)', safe=True)
Thomas Arendsen Hein
revset: add desc(string) to search in commit messages...
r14650 def desc(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Search commit message for string. The match is case-insensitive.
Thomas Arendsen Hein
revset: add desc(string) to search in commit messages...
r14650 """
# 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())
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(matches, condrepr=('<desc %r>', ds))
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):
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 roots = getset(repo, fullreposet(repo), x)
Mads Kiilerich
revset: better naming of variables containing the value of a single argument...
r22944 if not roots:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Mads Kiilerich
revset: better naming of variables containing the value of a single argument...
r22944 s = _revdescendants(repo, roots, 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.
Mads Kiilerich
revset: better naming of variables containing the value of a single argument...
r22944 base = subset & roots
Pierre-Yves David
revset-_descendant: rework the whole sorting and combining logic...
r22860 desc = subset & s
result = base + desc
if subset.isascending():
result.sort()
elif subset.isdescending():
result.sort(reverse=True)
else:
result = subset & result
Pierre-Yves David
_descendants: directly use smartset...
r22830 return result
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('descendants(set)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def descendants(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changesets which are descendants of changesets in set.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 return _descendants(repo, subset, x)
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('_firstdescendants', safe=True)
Patrick Mezard
graphlog: fix --follow-first --rev combinations...
r16409 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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('destination([set])', safe=True)
Matt Harbison
revset: add destination() predicate...
r17186 def destination(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changesets that were created by a graft, transplant or rebase operation,
Matt Harbison
revset: add destination() predicate...
r17186 with the given revisions specified as the source. Omitting the optional set
is the same as passing all().
"""
if x is not None:
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 sources = getset(repo, fullreposet(repo), x)
Matt Harbison
revset: add destination() predicate...
r17186 else:
Yuya Nishihara
revset: drop unnecessary calls of getall() with empty argument...
r24201 sources = fullreposet(repo)
Matt Harbison
revset: add destination() predicate...
r17186
dests = set()
# subset contains all of the possible destinations that can be returned, so
Mads Kiilerich
revset: better naming of variables containing the value of a single argument...
r22944 # iterate over them and see if their source(s) were provided in the arg set.
# Even if the immediate src of r is not in the arg set, src's source (or
Matt Harbison
revset: add destination() predicate...
r17186 # 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.
Mads Kiilerich
revset: better naming of variables containing the value of a single argument...
r22944 if src in sources or src in dests:
Matt Harbison
revset: add destination() predicate...
r17186 dests.update(lineage)
break
r = src
src = _getrevsource(repo, r)
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(dests.__contains__,
condrepr=lambda: '<destination %r>' % sorted(dests))
Matt Harbison
revset: add destination() predicate...
r17186
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('divergent()', safe=True)
Pierre-Yves David
obsolete: add revset and test for divergent changesets...
r18071 def divergent(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """
Pierre-Yves David
obsolete: add revset and test for divergent changesets...
r18071 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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('extinct()', safe=True)
Pierre-Yves David
obsolete: compute extinct changesets...
r17173 def extinct(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Obsolete changesets with obsolete descendants only.
Patrick Mezard
revset: minor doc fixes on obsolete related revsets
r17291 """
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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('extra(label, [value])', safe=True)
Henrik Stuart
revset: add function for matching extra data (issue2767)
r16661 def extra(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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:`.
"""
Yuya Nishihara
revset: rename getkwargs() to getargsdict()...
r25767 args = getargsdict(x, 'extra', 'label value')
Yuya Nishihara
revset: port extra() to support keyword arguments...
r25706 if 'label' not in args:
# i18n: "extra" is a keyword
raise error.ParseError(_('extra takes at least 1 argument'))
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "extra" is a keyword
Yuya Nishihara
revset: port extra() to support keyword arguments...
r25706 label = getstring(args['label'], _('first argument to extra must be '
'a string'))
Henrik Stuart
revset: add function for matching extra data (issue2767)
r16661 value = None
Yuya Nishihara
revset: port extra() to support keyword arguments...
r25706 if 'value' in args:
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "extra" is a keyword
Yuya Nishihara
revset: port extra() to support keyword arguments...
r25706 value = getstring(args['value'], _('second argument to extra must be '
'a string'))
Matt Harbison
util: extract stringmatcher() from revset...
r26481 kind, value, matcher = util.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
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(lambda r: _matchvalue(r),
condrepr=('<extra[%r] %r>', label, value))
Pierre-Yves David
phases: implements simple revset symbol...
r15819
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('filelog(pattern)', safe=True)
Matt Mackall
revset: introduce filelog() to emulate log's fast path...
r14342 def filelog(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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.
Pierre-Yves David
linkrev: work around linkrev to filtered entry in 'filelog' revset...
r23719
If some linkrev points to revisions filtered by the current repoview, we'll
work around it to return a non-filtered value.
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()
Pierre-Yves David
linkrev: work around linkrev to filtered entry in 'filelog' revset...
r23719 cl = repo.changelog
Matt Mackall
revset: introduce filelog() to emulate log's fast path...
r14342
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)
Pierre-Yves David
linkrev: work around linkrev to filtered entry in 'filelog' revset...
r23719 files = [f]
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])
Pierre-Yves David
linkrev: work around linkrev to filtered entry in 'filelog' revset...
r23719 files = (f for f in repo[None] if m(f))
for f in files:
fl = repo.file(f)
Matt Mackall
log: speed up single file log with hidden revs (issue4747)...
r27945 known = {}
scanpos = 0
Pierre-Yves David
linkrev: work around linkrev to filtered entry in 'filelog' revset...
r23719 for fr in list(fl):
Matt Mackall
log: speed up single file log with hidden revs (issue4747)...
r27945 fn = fl.node(fr)
if fn in known:
s.add(known[fn])
Martin von Zweigbergk
filelog: remove trailing "form feed" character
r23821 continue
Matt Mackall
log: speed up single file log with hidden revs (issue4747)...
r27945
lr = fl.linkrev(fr)
if lr in cl:
s.add(lr)
elif scanpos is not None:
# lowest matching changeset is filtered, scan further
# ahead in changelog
start = max(lr, scanpos) + 1
scanpos = None
for r in cl.revs(start):
# minimize parsing of non-matching entries
if f in cl.revision(r) and f in cl.readfiles(r):
try:
# try to use manifest delta fastpath
n = repo[r].filenode(f)
if n not in known:
if n == fn:
s.add(r)
scanpos = r
break
else:
known[n] = r
except error.ManifestLookupError:
# deletion in changelog
continue
Matt Mackall
revset: introduce filelog() to emulate log's fast path...
r14342
Pierre-Yves David
revset: use `subset &` in `filelog`...
r22534 return subset & s
Matt Mackall
revset: introduce filelog() to emulate log's fast path...
r14342
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('first(set, [n])', safe=True)
Matt Mackall
revsets: add first alias for last
r15117 def first(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """An alias for limit().
Matt Mackall
revsets: add first alias for last
r15117 """
return limit(repo, subset, x)
Patrick Mezard
context: add followfirst arg to filectx and workingfilectx...
r16185 def _follow(repo, subset, x, name, followfirst=False):
Gábor Stefanik
revset: support "follow(renamed.py, e22f4f3f06c3)" (issue5334)...
r29814 l = getargs(x, 0, 2, _("%s takes no arguments or a pattern "
"and an optional revset") % name)
Patrick Mezard
context: add followfirst arg to filectx and workingfilectx...
r16185 c = repo['.']
if l:
liscju
revsets: makes follow() supports file patterns (issue4757) (BC)...
r26102 x = getstring(l[0], _("%s expected a pattern") % name)
Gábor Stefanik
revset: support "follow(renamed.py, e22f4f3f06c3)" (issue5334)...
r29814 rev = None
if len(l) >= 2:
Yuya Nishihara
revset: make follow() reject more than one start revisions...
r30178 revs = getset(repo, fullreposet(repo), l[1])
if len(revs) != 1:
Gábor Stefanik
revset: support "follow(renamed.py, e22f4f3f06c3)" (issue5334)...
r29814 raise error.RepoLookupError(
Yuya Nishihara
revset: make follow() reject more than one start revisions...
r30178 _("%s expected one starting revision") % name)
rev = revs.last()
Gábor Stefanik
revset: support "follow(renamed.py, e22f4f3f06c3)" (issue5334)...
r29814 c = repo[rev]
liscju
revsets: makes follow() supports file patterns (issue4757) (BC)...
r26102 matcher = matchmod.match(repo.root, repo.getcwd(), [x],
Gábor Stefanik
revset: support "follow(renamed.py, e22f4f3f06c3)" (issue5334)...
r29814 ctx=repo[rev], default='path')
liscju
revsets: makes follow() supports file patterns (issue4757) (BC)...
r26102
Durham Goode
revset: use manifest.matches in _follow revset...
r28008 files = c.manifest().walk(matcher)
liscju
revsets: makes follow() supports file patterns (issue4757) (BC)...
r26102 s = set()
Durham Goode
revset: use manifest.matches in _follow revset...
r28008 for fname in files:
fctx = c[fname]
s = s.union(set(c.rev() for c in fctx.ancestors(followfirst)))
# include the revision responsible for the most recent version
s.add(fctx.introrev())
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
Gábor Stefanik
revset: support "follow(renamed.py, e22f4f3f06c3)" (issue5334)...
r29814 @predicate('follow([pattern[, startrev]])', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def follow(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """
Yuya Nishihara
revset: replace "working copy" with "working directory" in function help
r24366 An alias for ``::.`` (ancestors of the working directory's first parent).
liscju
revsets: makes follow() supports file patterns (issue4757) (BC)...
r26102 If pattern is specified, the histories of files matching given
Gábor Stefanik
revset: support "follow(renamed.py, e22f4f3f06c3)" (issue5334)...
r29814 pattern in the revision given by startrev are followed, including copies.
Matt Mackall
revset: add follow(filename) to follow a filename's history across copies
r14343 """
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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('_followfirst', safe=True)
Patrick Mezard
graphlog: implement --follow-first...
r16174 def _followfirst(repo, subset, x):
Gábor Stefanik
revset: support "follow(renamed.py, e22f4f3f06c3)" (issue5334)...
r29814 # ``followfirst([pattern[, startrev]])``
# Like ``follow([pattern[, startrev]])`` but follows only the first parent
# of every revisions or files revisions.
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
Denis Laxalde
revset: add a followlines(file, fromline, toline[, rev]) revset...
r30719 @predicate('followlines(file, fromline, toline[, rev=.])', safe=True)
def followlines(repo, subset, x):
"""Changesets modifying `file` in line range ('fromline', 'toline').
Line range corresponds to 'file' content at 'rev' and should hence be
consistent with file size. If rev is not specified, working directory's
parent is used.
"""
from . import context # avoid circular import issues
args = getargs(x, 3, 4, _("followlines takes at least three arguments"))
rev = '.'
if len(args) == 4:
revarg = getargsdict(args[3], 'followlines', 'rev')
if 'rev' in revarg:
revs = getset(repo, fullreposet(repo), revarg['rev'])
if len(revs) != 1:
raise error.ParseError(
_("followlines expects exactly one revision"))
rev = revs.last()
pat = getstring(args[0], _("followlines requires a pattern"))
if not matchmod.patkind(pat):
fname = pathutil.canonpath(repo.root, repo.getcwd(), pat)
else:
m = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=repo[rev])
files = [f for f in repo[rev] if m(f)]
if len(files) != 1:
raise error.ParseError(_("followlines expects exactly one file"))
fname = files[0]
try:
fromline, toline = [int(getsymbol(a)) for a in args[1:3]]
except ValueError:
raise error.ParseError(_("line range bounds must be integers"))
if toline - fromline < 0:
raise error.ParseError(_("line range must be positive"))
if fromline < 1:
raise error.ParseError(_("fromline must be strictly positive"))
fromline -= 1
fctx = repo[rev].filectx(fname)
revs = (c.rev() for c in context.blockancestors(fctx, fromline, toline))
return subset & generatorset(revs, iterasc=False)
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('all()', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def getall(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """All changesets, the same as ``0:tip``.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# i18n: "all" is a keyword
getargs(x, 0, 0, _("all takes no arguments"))
Yuya Nishihara
revset: have all() filter out null revision...
r24202 return subset & spanset(repo) # drop "null" if any
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 @predicate('grep(regex)')
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def grep(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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")))
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except re.error as e:
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 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
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(matches, condrepr=('<grep %r>', gr.pattern))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('_matchfiles', safe=True)
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
Yuya Nishihara
revset: drop translation markers from error messages of internal _matchfiles...
r28271 l = getargs(x, 1, -1, "_matchfiles requires at least one argument")
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 pats, inc, exc = [], [], []
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:
Yuya Nishihara
revset: drop translation markers from error messages of internal _matchfiles...
r28271 s = getstring(arg, "_matchfiles requires string arguments")
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 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:
Yuya Nishihara
revset: drop translation markers from error messages of internal _matchfiles...
r28271 raise error.ParseError('_matchfiles expected at most one '
'revision')
Martin von Zweigbergk
log: evaluate filesets on working copy, not its parent...
r23950 if value != '': # empty means working directory; leave rev as None
rev = value
Patrick Mezard
graphlog: correctly handle calls in subdirectories
r16411 elif prefix == 'd:':
if default is not None:
Yuya Nishihara
revset: drop translation markers from error messages of internal _matchfiles...
r28271 raise error.ParseError('_matchfiles expected at most one '
'default mode')
Patrick Mezard
graphlog: correctly handle calls in subdirectories
r16411 default = value
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 else:
Yuya Nishihara
revset: drop translation markers from error messages of internal _matchfiles...
r28271 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix)
Patrick Mezard
graphlog: correctly handle calls in subdirectories
r16411 if not default:
default = 'glob'
Lucas Moscovicz
revset: added lazyset implementation to _matchfiles...
r20458
Matt Mackall
revset: avoid recalculating filesets...
r23061 m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
exclude=exc, ctx=repo[rev], default=default)
Pierre-Yves David
revset: speed up '_matchfiles'...
r27028 # This directly read the changelog data as creating changectx for all
# revisions is quite expensive.
Laurent Charignon
log: speed up hg log <file|folder>...
r27440 getfiles = repo.changelog.readfiles
Pierre-Yves David
revset: speed up '_matchfiles'...
r27028 wdirrev = node.wdirrev
Lucas Moscovicz
revset: added lazyset implementation to _matchfiles...
r20458 def matches(x):
Pierre-Yves David
revset: speed up '_matchfiles'...
r27028 if x == wdirrev:
files = repo[x].files()
else:
Laurent Charignon
log: speed up hg log <file|folder>...
r27440 files = getfiles(x)
Pierre-Yves David
revset: speed up '_matchfiles'...
r27028 for f in files:
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161 if m(f):
Lucas Moscovicz
revset: added lazyset implementation to _matchfiles...
r20458 return True
return False
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(matches,
condrepr=('<matchfiles patterns=%r, include=%r '
'exclude=%r, default=%r, rev=%r>',
pats, inc, exc, default, rev))
Patrick Mezard
graphlog: paths/-I/-X handling requires a new revset...
r16161
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('file(pattern)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def hasfile(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('head()', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def head(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changeset is a named branch head.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# i18n: "head" is a keyword
getargs(x, 0, 0, _("head takes no arguments"))
hs = set()
Pierre-Yves David
revset: translate node directly with changelog in 'head'...
r25620 cl = repo.changelog
Martin von Zweigbergk
revsets: use itervalues() where only values are needed...
r29407 for ls in repo.branchmap().itervalues():
Pierre-Yves David
revset: translate node directly with changelog in 'head'...
r25620 hs.update(cl.rev(h) for h in ls)
Martin von Zweigbergk
revset: make head() honor order of subset...
r29408 return subset & baseset(hs)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('heads(set)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def heads(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Members of set with no children in set.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('hidden()', safe=True)
Patrick Mezard
revset: add hidden() revset
r17390 def hidden(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Hidden changesets.
Patrick Mezard
revset: add hidden() revset
r17390 """
# 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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('keyword(string)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def keyword(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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]
Pierre-Yves David
revset: gratuitous formating fix in keyword...
r25551 return any(kw in encoding.lower(t)
for t in c.files() + [c.user(), c.description()])
Lucas Moscovicz
revset: added lazyset implementation to keyword revset...
r20447
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(matches, condrepr=('<keyword %r>', kw))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('limit(set[, n[, offset]])', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def limit(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """First n members of set, defaulting to 1, starting from offset.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
Yuya Nishihara
revset: add optional offset argument to limit() predicate...
r26638 args = getargsdict(x, 'limit', 'set n offset')
Yuya Nishihara
revset: port limit() to support keyword arguments...
r26637 if 'set' not in args:
# i18n: "limit" is a keyword
Yuya Nishihara
revset: add optional offset argument to limit() predicate...
r26638 raise error.ParseError(_("limit requires one to three arguments"))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 try:
Yuya Nishihara
revset: add optional offset argument to limit() predicate...
r26638 lim, ofs = 1, 0
Yuya Nishihara
revset: port limit() to support keyword arguments...
r26637 if 'n' in args:
Matt Mackall
revset: add default of 1 to limit and last functions
r15116 # i18n: "limit" is a keyword
Yuya Nishihara
revset: port limit() to support keyword arguments...
r26637 lim = int(getstring(args['n'], _("limit requires a number")))
Yuya Nishihara
revset: add optional offset argument to limit() predicate...
r26638 if 'offset' in args:
# i18n: "limit" is a keyword
ofs = int(getstring(args['offset'], _("limit requires a number")))
if ofs < 0:
raise error.ParseError(_("negative offset"))
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"))
Yuya Nishihara
revset: port limit() to support keyword arguments...
r26637 os = getset(repo, fullreposet(repo), args['set'])
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)
Yuya Nishihara
revset: add optional offset argument to limit() predicate...
r26638 for x in xrange(ofs):
y = next(it, None)
if y is None:
break
Lucas Moscovicz
revset: changed limit revset implementation to work with lazy revsets...
r20446 for x in xrange(lim):
Pierre-Yves David
revset: use 'next()' to detect end of iteration in 'limit'...
r25144 y = next(it, None)
if y is None:
Lucas Moscovicz
revset: changed limit revset implementation to work with lazy revsets...
r20446 break
Yuya Nishihara
revset: eliminate temporary reference to subset in limit() and last()
r26636 elif y in subset:
Pierre-Yves David
revset: use 'next()' to detect end of iteration in 'limit'...
r25144 result.append(y)
Yuya Nishihara
revset: add inspection data to limit() and last() functions...
r28426 return baseset(result, datarepr=('<limit n=%d, offset=%d, %r, %r>',
lim, ofs, subset, os))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('last(set, [n])', safe=True)
Matt Mackall
revsets: add a last function...
r14061 def last(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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"))
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 os = getset(repo, fullreposet(repo), l[0])
Lucas Moscovicz
revset: changed last implementation to use lazy classes...
r20534 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):
Pierre-Yves David
revset: use 'next()' to detect end of iteration in 'last'...
r25145 y = next(it, None)
if y is None:
Lucas Moscovicz
revset: changed last implementation to use lazy classes...
r20534 break
Yuya Nishihara
revset: eliminate temporary reference to subset in limit() and last()
r26636 elif y in subset:
Pierre-Yves David
revset: use 'next()' to detect end of iteration in 'last'...
r25145 result.append(y)
Yuya Nishihara
revset: add inspection data to limit() and last() functions...
r28426 return baseset(result, datarepr=('<last n=%d, %r, %r>', lim, subset, os))
Matt Mackall
revsets: add a last function...
r14061
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('max(set)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def maxrev(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changeset with highest revision number in set.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 os = getset(repo, fullreposet(repo), x)
Durham Goode
revset: remove existence check from min() and max()...
r26305 try:
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:
Yuya Nishihara
revset: add inspection data to max() and min() functions...
r28427 return baseset([m], datarepr=('<max %r, %r>', subset, os))
Durham Goode
revset: remove existence check from min() and max()...
r26305 except ValueError:
# os.max() throws a ValueError when the collection is empty.
# Same as python's max().
pass
Yuya Nishihara
revset: add inspection data to max() and min() functions...
r28427 return baseset(datarepr=('<max %r, %r>', subset, os))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('merge()', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def merge(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changeset is a merge changeset.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
# i18n: "merge" is a keyword
getargs(x, 0, 0, _("merge takes no arguments"))
cl = repo.changelog
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(lambda r: cl.parentrevs(r)[1] != -1,
condrepr='<merge>')
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('branchpoint()', safe=True)
Ivan Andrus
revsets: add branchpoint() function...
r17753 def branchpoint(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changesets with more than one child.
Ivan Andrus
revsets: add branchpoint() function...
r17753 """
# 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()
Pierre-Yves David
revset: mark spots that should use 'smartset.min()'...
r25549 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
# (and if it is not, it should.)
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
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(lambda r: parentscount[r - baserev] > 1,
condrepr='<branchpoint>')
Ivan Andrus
revsets: add branchpoint() function...
r17753
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('min(set)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def minrev(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changeset with lowest revision number in set.
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 """
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 os = getset(repo, fullreposet(repo), x)
Durham Goode
revset: remove existence check from min() and max()...
r26305 try:
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:
Yuya Nishihara
revset: add inspection data to max() and min() functions...
r28427 return baseset([m], datarepr=('<min %r, %r>', subset, os))
Durham Goode
revset: remove existence check from min() and max()...
r26305 except ValueError:
# os.min() throws a ValueError when the collection is empty.
# Same as python's min().
pass
Yuya Nishihara
revset: add inspection data to max() and min() functions...
r28427 return baseset(datarepr=('<min %r, %r>', subset, os))
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('modifies(pattern)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def modifies(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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)
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 @predicate('named(namespace)')
Sean Farley
namespaces: add revset for 'named(namespace)'...
r23836 def named(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """The changesets in a given namespace.
Sean Farley
namespaces: add revset for 'named(namespace)'...
r23836
If `namespace` starts with `re:`, the remainder of the string is treated as
a regular expression. To match a namespace that actually starts with `re:`,
use the prefix `literal:`.
"""
# i18n: "named" is a keyword
args = getargs(x, 1, 1, _('named requires a namespace argument'))
ns = getstring(args[0],
# i18n: "named" is a keyword
_('the argument to named must be a string'))
Matt Harbison
util: extract stringmatcher() from revset...
r26481 kind, pattern, matcher = util.stringmatcher(ns)
Sean Farley
namespaces: add revset for 'named(namespace)'...
r23836 namespaces = set()
if kind == 'literal':
if pattern not in repo.names:
FUJIWARA Katsunori
revset: raise RepoLookupError to make present() predicate continue the query...
r23978 raise error.RepoLookupError(_("namespace '%s' does not exist")
% ns)
Sean Farley
namespaces: add revset for 'named(namespace)'...
r23836 namespaces.add(repo.names[pattern])
else:
for name, ns in repo.names.iteritems():
if matcher(name):
namespaces.add(ns)
if not namespaces:
FUJIWARA Katsunori
revset: raise RepoLookupError to make present() predicate continue the query...
r23978 raise error.RepoLookupError(_("no namespace exists"
" that match '%s'") % pattern)
Sean Farley
namespaces: add revset for 'named(namespace)'...
r23836
names = set()
for ns in namespaces:
for name in ns.listnames(repo):
FUJIWARA Katsunori
revset: mask specific names for named() predicate...
r24151 if name not in ns.deprecated:
names.update(repo[n].rev() for n in ns.nodes(repo, name))
Sean Farley
namespaces: add revset for 'named(namespace)'...
r23836
names -= set([node.nullrev])
return subset & names
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('id(string)', safe=True)
Matt Mackall
revset: avoid demandimport bug...
r16417 def node_(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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:
Alexander Drozdov
revset: id() called with 40-byte strings should give the same results as for short strings...
r24904 try:
rn = repo.changelog.rev(node.bin(n))
except (LookupError, TypeError):
rn = None
Augie Fackler
revset: add id() and rev() to allow explicitly referring to changes by hash or rev
r12716 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)
Pierre-Yves David
revset-node: speedup by a few hundred fold...
r23005 if rn is None:
return baseset()
result = baseset([rn])
return result & subset
Augie Fackler
revset: add id() and rev() to allow explicitly referring to changes by hash or rev
r12716
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('obsolete()', safe=True)
Pierre-Yves David
revset: add an `obsolete` symbol...
r17170 def obsolete(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('only(set, [set])', safe=True)
Yuya Nishihara
revset: move 'only' so that functions are sorted alphabetically
r23466 def only(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changesets that are ancestors of the first set that are not ancestors
Yuya Nishihara
revset: move 'only' so that functions are sorted alphabetically
r23466 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
# i18n: "only" is a keyword
args = getargs(x, 1, 2, _('only takes one or two arguments'))
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 include = getset(repo, fullreposet(repo), args[0])
Yuya Nishihara
revset: move 'only' so that functions are sorted alphabetically
r23466 if len(args) == 1:
if not include:
return baseset()
descendants = set(_revdescendants(repo, include, False))
exclude = [rev for rev in cl.headrevs()
if not rev in descendants and not rev in include]
else:
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 exclude = getset(repo, fullreposet(repo), args[1])
Yuya Nishihara
revset: move 'only' so that functions are sorted alphabetically
r23466
results = set(cl.findmissingrevs(common=exclude, heads=include))
Pierre-Yves David
revset: mark spots that use 'set' instead of 'smartset'...
r25554 # XXX we should turn this into a baseset instead of a set, smartset may do
Mads Kiilerich
spelling: fixes of non-dictionary words
r30332 # some optimizations from the fact this is a baseset.
Yuya Nishihara
revset: move 'only' so that functions are sorted alphabetically
r23466 return subset & results
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('origin([set])', safe=True)
Matt Harbison
revset: add origin() predicate...
r17185 def origin(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """
Matt Harbison
revset: add origin() predicate...
r17185 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:
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 dests = getset(repo, fullreposet(repo), x)
Matt Harbison
revset: add origin() predicate...
r17185 else:
Yuya Nishihara
revset: drop unnecessary calls of getall() with empty argument...
r24201 dests = fullreposet(repo)
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
Mads Kiilerich
revset: better naming of variables containing the value of a single argument...
r22944 o = set([_firstsrc(r) for r in dests])
Pierre-Yves David
revset: remove invalid value in the origin set...
r22498 o -= set([None])
Pierre-Yves David
revset: mark spots that use 'set' instead of 'smartset'...
r25554 # XXX we should turn this into a baseset instead of a set, smartset may do
Mads Kiilerich
spelling: fixes of non-dictionary words
r30332 # some optimizations from the fact this is a baseset.
Pierre-Yves David
revset: use `subset &` in `origin`...
r22536 return subset & o
Matt Harbison
revset: add origin() predicate...
r17185
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('outgoing([path])', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def outgoing(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changesets not found in the specified destination repository, or the
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 default push location.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Gregory Szorc
revset: don't import discovery at module level...
r24722 # Avoid cycles.
Gregory Szorc
revset: use absolute_import
r25971 from . import (
discovery,
hg,
)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 # 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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('p1([set])', safe=True)
Matt Mackall
revset: introduce revset core
r11275 def p1(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 for r in getset(repo, fullreposet(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])
Pierre-Yves David
revset: mark spots that use 'set' instead of 'smartset'...
r25554 # XXX we should turn this into a baseset instead of a set, smartset may do
Mads Kiilerich
spelling: fixes of non-dictionary words
r30332 # some optimizations from the fact this is a baseset.
Lucas Moscovicz
revset: added intersection to baseset class...
r20367 return subset & ps
Matt Mackall
revset: introduce revset core
r11275
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('p2([set])', safe=True)
Matt Mackall
revset: introduce revset core
r11275 def p2(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 for r in getset(repo, fullreposet(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])
Pierre-Yves David
revset: mark spots that use 'set' instead of 'smartset'...
r25554 # XXX we should turn this into a baseset instead of a set, smartset may do
Mads Kiilerich
spelling: fixes of non-dictionary words
r30332 # some optimizations from the fact this is a baseset.
Lucas Moscovicz
revset: added intersection to baseset class...
r20367 return subset & ps
Matt Mackall
revset: introduce revset core
r11275
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 def parentpost(repo, subset, x, order):
Yuya Nishihara
revset: add stub to handle parentpost operation...
r29931 return p1(repo, subset, x)
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('parents([set])', safe=True)
Matt Mackall
revset: introduce revset core
r11275 def parents(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """
Kevin Bullock
revsets: let parents() return parents of working dir...
r12929 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
Pierre-Yves David
revset: prefetch method in "parents"...
r25716 up = ps.update
parentrevs = cl.parentrevs
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 for r in getset(repo, fullreposet(repo), x):
Yuya Nishihara
revset: use integer representation of wdir() in revset...
r25765 if r == node.wdirrev:
Pierre-Yves David
revset: prefetch method in "parents"...
r25716 up(p.rev() for p in repo[r].parents())
Matt Harbison
revset: fix a crash in parents() when 'wdir()' is in the set...
r25689 else:
Pierre-Yves David
revset: prefetch method in "parents"...
r25716 up(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
Pierre-Yves David
revset: refactor the non-public phase code...
r25621 def _phase(repo, subset, target):
"""helper to select all rev in phase <target>"""
Pierre-Yves David
revset: make use of natively-computed set for 'draft()' and 'secret()'...
r25622 repo._phasecache.loadphaserevs(repo) # ensure phase's sets are loaded
if repo._phasecache._phasesets:
s = repo._phasecache._phasesets[target] - repo.changelog.filteredrevs
s = baseset(s)
s.sort() # set are non ordered, so we enforce ascending
return subset & s
else:
phase = repo._phasecache.phase
condition = lambda r: phase(repo, r) == target
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(condition, condrepr=('<phase %r>', target),
cache=False)
Pierre-Yves David
revset: refactor the non-public phase code...
r25621
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('draft()', safe=True)
Pierre-Yves David
revset: refactor the non-public phase code...
r25621 def draft(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changeset in draft phase."""
Pierre-Yves David
revset: refactor the non-public phase code...
r25621 # i18n: "draft" is a keyword
getargs(x, 0, 0, _("draft takes no arguments"))
target = phases.draft
return _phase(repo, subset, target)
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('secret()', safe=True)
Pierre-Yves David
revset: refactor the non-public phase code...
r25621 def secret(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changeset in secret phase."""
Pierre-Yves David
revset: refactor the non-public phase code...
r25621 # i18n: "secret" is a keyword
getargs(x, 0, 0, _("secret takes no arguments"))
target = phases.secret
return _phase(repo, subset, target)
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 def parentspec(repo, subset, x, n, order):
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 """``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
Pierre-Yves David
revset-parentspec: call 'getset' on a 'fullreposet'...
r23165 for r in getset(repo, fullreposet(repo), 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)
Yuya Nishihara
revset: for x^2, do not take null as a valid p2 revision...
r30179 if parents[1] != node.nullrev:
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 ps.add(parents[1])
Lucas Moscovicz
revset: added intersection to baseset class...
r20367 return subset & ps
Matt Mackall
revset: introduce revset core
r11275
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('present(set)', safe=True)
Wagner Bruna
revset: predicate to avoid lookup errors...
r11944 def present(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """An empty set, if any revision in set isn't found; otherwise,
Patrick Mezard
revsets: generate predicate help dynamically
r12821 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
Yuya Nishihara
revset: drop docstring from internal _notpublic() function...
r25224 # for internal use
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('_notpublic', safe=True)
Laurent Charignon
revset: optimize not public revset...
r25191 def _notpublic(repo, subset, x):
Yuya Nishihara
revset: drop translation marker from error message of _notpublic()...
r25225 getargs(x, 0, 0, "_notpublic takes no arguments")
Pierre-Yves David
revset: ensure we have loaded phases data in '_notpublic()'...
r25612 repo._phasecache.loadphaserevs(repo) # ensure phase's sets are loaded
Laurent Charignon
revset: optimize not public revset...
r25191 if repo._phasecache._phasesets:
s = set()
for u in repo._phasecache._phasesets[1:]:
s.update(u)
Pierre-Yves David
revset: use a baseset in _notpublic()...
r25619 s = baseset(s - repo.changelog.filteredrevs)
s.sort()
Laurent Charignon
revset: optimize not public revset...
r25191 return subset & s
else:
phase = repo._phasecache.phase
target = phases.public
condition = lambda r: phase(repo, r) != target
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(condition, condrepr=('<phase %r>', target),
cache=False)
Laurent Charignon
revset: optimize not public revset...
r25191
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('public()', safe=True)
Pierre-Yves David
phases: implements simple revset symbol...
r15819 def public(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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"))
Pierre-Yves David
revset-phases: prefetch attributes in phasesrelated revsets...
r23019 phase = repo._phasecache.phase
target = phases.public
condition = lambda r: phase(repo, r) == target
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(condition, condrepr=('<phase %r>', target),
cache=False)
Pierre-Yves David
phases: implements simple revset symbol...
r15819
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('remote([id [,path]])', safe=True)
Matt Mackall
revset: add remote() predicate to lookup remote revisions
r15936 def remote(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Local revision that corresponds to the given identifier in a
Matt Mackall
revset: add remote() predicate to lookup remote revisions
r15936 remote repository, if present. Here, the '.' identifier is a
synonym for the current local branch.
"""
Gregory Szorc
revset: use absolute_import
r25971 from . import hg # avoid start-up nasties
Matt Mackall
revset: add remote() predicate to lookup remote revisions
r15936 # i18n: "remote" is a keyword
timeless
grammar: favor zero, one, two over ... or no
r27293 l = getargs(x, 0, 2, _("remote takes zero, one, or two 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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('removes(pattern)', safe=True)
Matt Mackall
revset: introduce revset core
r11275 def removes(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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)
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('rev(number)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def rev(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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"))
Yuya Nishihara
revset: have rev() validate input by repo.changelog.__contains__()...
r24031 if l not in repo.changelog and l != node.nullrev:
Yuya Nishihara
revset: have rev() drop out-of-range or filtered rev explicitly (issue4396)...
r23062 return baseset()
Pierre-Yves David
revset: use `subset &` in `rev`...
r22537 return subset & baseset([l])
Matt Mackall
revset: introduce revset core
r11275
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('matching(revision [, field])', safe=True)
Angel Ezquerra
revset: add "matching" keyword...
r16402 def matching(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changesets in which a given set of fields match the set of fields in the
Angel Ezquerra
revset: add "matching" keyword...
r16402 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"))
Pierre-Yves David
revset-matching: call 'getset' on a 'fullreposet'...
r23166 revs = getset(repo, fullreposet(repo), 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
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs))
Angel Ezquerra
revset: add "matching" keyword...
r16402
Yuya Nishihara
revset: make reverse() noop depending on ordering requirement (BC)...
r29945 @predicate('reverse(set)', safe=True, takeorder=True)
def reverse(repo, subset, x, order):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Reverse order of set.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Matt Mackall
revset: introduce revset core
r11275 l = getset(repo, subset, x)
Yuya Nishihara
revset: make reverse() noop depending on ordering requirement (BC)...
r29945 if order == defineorder:
l.reverse()
Matt Mackall
revset: introduce revset core
r11275 return l
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('roots(set)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def roots(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changesets in set with no parent changeset in set.
Patrick Mezard
revsets: generate predicate help dynamically
r12821 """
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 s = getset(repo, fullreposet(repo), x)
Pierre-Yves David
revset: improves time complexity of 'roots(xxx)'...
r25647 parents = repo.changelog.parentrevs
def filter(r):
for p in parents(r):
if 0 <= p and p in s:
return False
return True
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset & s.filter(filter, condrepr='<roots>')
Wagner Bruna
revset: predicate to avoid lookup errors...
r11944
Yuya Nishihara
revset: define table of sort() key functions...
r29265 _sortkeyfuncs = {
'rev': lambda c: c.rev(),
'branch': lambda c: c.branch(),
'desc': lambda c: c.description(),
'user': lambda c: c.user(),
'author': lambda c: c.user(),
'date': lambda c: c.date()[0],
}
Yuya Nishihara
revset: extract function that validates sort() arguments...
r29365 def _getsortargs(x):
"""Parse sort options into (set, [(key, reverse)], opts)"""
Martijn Pieters
revset: add new topographical sort...
r29348 args = getargsdict(x, 'sort', 'set keys topo.firstbranch')
Martijn Pieters
revset: use getargsdict for sort()...
r29238 if 'set' not in args:
# i18n: "sort" is a keyword
raise error.ParseError(_('sort requires one or two arguments'))
Matt Mackall
revset: introduce revset core
r11275 keys = "rev"
Martijn Pieters
revset: use getargsdict for sort()...
r29238 if 'keys' in args:
FUJIWARA Katsunori
i18n: add/relocate "i18n keyword" comments for i18n messages in revset.py
r17259 # i18n: "sort" is a keyword
Martijn Pieters
revset: use getargsdict for sort()...
r29238 keys = getstring(args['keys'], _("sort spec must be a string"))
Yuya Nishihara
revset: build list of (key, reverse) pairs before sorting...
r29363 keyflags = []
for k in keys.split():
fk = k
reverse = (k[0] == '-')
if reverse:
k = k[1:]
if k not in _sortkeyfuncs and k != 'topo':
raise error.ParseError(_("unknown sort key %r") % fk)
keyflags.append((k, reverse))
if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags):
Martijn Pieters
revset: add new topographical sort...
r29348 # i18n: "topo" is a keyword
FUJIWARA Katsunori
revset: refactor to make xgettext put i18n comments into hg.pot file...
r29646 raise error.ParseError(_('topo sort order cannot be combined '
'with other sort keys'))
Martijn Pieters
revset: add new topographical sort...
r29348
Yuya Nishihara
revset: build dict of extra sort options before evaluating set...
r29364 opts = {}
Martijn Pieters
revset: add new topographical sort...
r29348 if 'topo.firstbranch' in args:
Yuya Nishihara
revset: build list of (key, reverse) pairs before sorting...
r29363 if any(k == 'topo' for k, reverse in keyflags):
Yuya Nishihara
revset: build dict of extra sort options before evaluating set...
r29364 opts['topo.firstbranch'] = args['topo.firstbranch']
Martijn Pieters
revset: add new topographical sort...
r29348 else:
# i18n: "topo" and "topo.firstbranch" are keywords
FUJIWARA Katsunori
revset: refactor to make xgettext put i18n comments into hg.pot file...
r29646 raise error.ParseError(_('topo.firstbranch can only be used '
'when using the topo sort key'))
Martijn Pieters
revset: add new topographical sort...
r29348
Yuya Nishihara
revset: extract function that validates sort() arguments...
r29365 return args['set'], keyflags, opts
Yuya Nishihara
revset: make sort() noop depending on ordering requirement (BC)...
r29946 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True)
def sort(repo, subset, x, order):
Yuya Nishihara
revset: extract function that validates sort() arguments...
r29365 """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
- ``topo`` for a reverse topographical sort
The ``topo`` sort order cannot be combined with other sort keys. This sort
takes one optional argument, ``topo.firstbranch``, which takes a revset that
specifies what topographical branches to prioritize in the sort.
"""
s, keyflags, opts = _getsortargs(x)
Yuya Nishihara
revset: build dict of extra sort options before evaluating set...
r29364 revs = getset(repo, subset, s)
Yuya Nishihara
revset: make sort() noop depending on ordering requirement (BC)...
r29946 if not keyflags or order != defineorder:
Lucas Moscovicz
revset: changed sort method to use native sort implementation of smartsets...
r20719 return revs
Yuya Nishihara
revset: build list of (key, reverse) pairs before sorting...
r29363 if len(keyflags) == 1 and keyflags[0][0] == "rev":
revs.sort(reverse=keyflags[0][1])
Lucas Moscovicz
revset: changed sort method to use native sort implementation of smartsets...
r20719 return revs
Yuya Nishihara
revset: build list of (key, reverse) pairs before sorting...
r29363 elif keyflags[0][0] == "topo":
Yuya Nishihara
revset: build dict of extra sort options before evaluating set...
r29364 firstbranch = ()
if 'topo.firstbranch' in opts:
firstbranch = getset(repo, subset, opts['topo.firstbranch'])
Martijn Pieters
revset: add new topographical sort...
r29348 revs = baseset(_toposort(revs, repo.changelog.parentrevs, firstbranch),
istopo=True)
Yuya Nishihara
revset: build list of (key, reverse) pairs before sorting...
r29363 if keyflags[0][1]:
Martijn Pieters
revset: add new topographical sort...
r29348 revs.reverse()
return revs
Yuya Nishihara
revset: make sort() do dumb multi-pass sorting for multiple keys (issue5218)...
r29001 # sort() is guaranteed to be stable
ctxs = [repo[r] for r in revs]
Yuya Nishihara
revset: build list of (key, reverse) pairs before sorting...
r29363 for k, reverse in reversed(keyflags):
ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
Yuya Nishihara
revset: make sort() do dumb multi-pass sorting for multiple keys (issue5218)...
r29001 return baseset([c.rev() for c in ctxs])
Matt Mackall
revset: introduce revset core
r11275
Martijn Pieters
revset: add new topographical sort...
r29348 def _toposort(revs, parentsfunc, firstbranch=()):
Martijn Pieters
revset: move groupbranchiter over from graphmod...
r29347 """Yield revisions from heads to roots one (topo) branch at a time.
This function aims to be used by a graph generator that wishes to minimize
the number of parallel branches and their interleaving.
Example iteration order (numbers show the "true" order in a changelog):
o 4
|
o 1
|
| o 3
| |
| o 2
|/
o 0
Note that the ancestors of merges are understood by the current
algorithm to be on the same branch. This means no reordering will
occur behind a merge.
"""
### Quick summary of the algorithm
#
# This function is based around a "retention" principle. We keep revisions
# in memory until we are ready to emit a whole branch that immediately
# "merges" into an existing one. This reduces the number of parallel
# branches with interleaved revisions.
#
# During iteration revs are split into two groups:
# A) revision already emitted
# B) revision in "retention". They are stored as different subgroups.
#
# for each REV, we do the following logic:
#
# 1) if REV is a parent of (A), we will emit it. If there is a
# retention group ((B) above) that is blocked on REV being
# available, we emit all the revisions out of that retention
# group first.
#
# 2) else, we'll search for a subgroup in (B) awaiting for REV to be
# available, if such subgroup exist, we add REV to it and the subgroup is
# now awaiting for REV.parents() to be available.
#
# 3) finally if no such group existed in (B), we create a new subgroup.
#
#
# To bootstrap the algorithm, we emit the tipmost revision (which
# puts it in group (A) from above).
revs.sort(reverse=True)
# Set of parents of revision that have been emitted. They can be considered
# unblocked as the graph generator is already aware of them so there is no
# need to delay the revisions that reference them.
#
# If someone wants to prioritize a branch over the others, pre-filling this
# set will force all other branches to wait until this branch is ready to be
# emitted.
unblocked = set(firstbranch)
# list of groups waiting to be displayed, each group is defined by:
#
# (revs: lists of revs waiting to be displayed,
# blocked: set of that cannot be displayed before those in 'revs')
#
# The second value ('blocked') correspond to parents of any revision in the
# group ('revs') that is not itself contained in the group. The main idea
# of this algorithm is to delay as much as possible the emission of any
# revision. This means waiting for the moment we are about to display
# these parents to display the revs in a group.
#
# This first implementation is smart until it encounters a merge: it will
# emit revs as soon as any parent is about to be emitted and can grow an
# arbitrary number of revs in 'blocked'. In practice this mean we properly
# retains new branches but gives up on any special ordering for ancestors
# of merges. The implementation can be improved to handle this better.
#
# The first subgroup is special. It corresponds to all the revision that
# were already emitted. The 'revs' lists is expected to be empty and the
# 'blocked' set contains the parents revisions of already emitted revision.
#
# You could pre-seed the <parents> set of groups[0] to a specific
# changesets to select what the first emitted branch should be.
groups = [([], unblocked)]
pendingheap = []
pendingset = set()
heapq.heapify(pendingheap)
heappop = heapq.heappop
heappush = heapq.heappush
for currentrev in revs:
# Heap works with smallest element, we want highest so we invert
if currentrev not in pendingset:
heappush(pendingheap, -currentrev)
pendingset.add(currentrev)
# iterates on pending rev until after the current rev have been
# processed.
rev = None
while rev != currentrev:
rev = -heappop(pendingheap)
pendingset.remove(rev)
# Seek for a subgroup blocked, waiting for the current revision.
matching = [i for i, g in enumerate(groups) if rev in g[1]]
if matching:
# The main idea is to gather together all sets that are blocked
# on the same revision.
#
# Groups are merged when a common blocking ancestor is
# observed. For example, given two groups:
#
# revs [5, 4] waiting for 1
# revs [3, 2] waiting for 1
#
# These two groups will be merged when we process
# 1. In theory, we could have merged the groups when
# we added 2 to the group it is now in (we could have
# noticed the groups were both blocked on 1 then), but
# the way it works now makes the algorithm simpler.
#
# We also always keep the oldest subgroup first. We can
# probably improve the behavior by having the longest set
# first. That way, graph algorithms could minimise the length
# of parallel lines their drawing. This is currently not done.
targetidx = matching.pop(0)
trevs, tparents = groups[targetidx]
for i in matching:
gr = groups[i]
trevs.extend(gr[0])
tparents |= gr[1]
# delete all merged subgroups (except the one we kept)
# (starting from the last subgroup for performance and
# sanity reasons)
for i in reversed(matching):
del groups[i]
else:
# This is a new head. We create a new subgroup for it.
targetidx = len(groups)
groups.append(([], set([rev])))
gr = groups[targetidx]
# We now add the current nodes to this subgroups. This is done
# after the subgroup merging because all elements from a subgroup
# that relied on this rev must precede it.
#
# we also update the <parents> set to include the parents of the
# new nodes.
if rev == currentrev: # only display stuff in rev
gr[0].append(rev)
gr[1].remove(rev)
parents = [p for p in parentsfunc(rev) if p > node.nullrev]
gr[1].update(parents)
for p in parents:
if p not in pendingset:
pendingset.add(p)
heappush(pendingheap, -p)
# Look for a subgroup to display
#
# When unblocked is empty (if clause), we were not waiting for any
# revisions during the first iteration (if no priority was given) or
# if we emitted a whole disconnected set of the graph (reached a
# root). In that case we arbitrarily take the oldest known
# subgroup. The heuristic could probably be better.
#
# Otherwise (elif clause) if the subgroup is blocked on
# a revision we just emitted, we can safely emit it as
# well.
if not unblocked:
if len(groups) > 1: # display other subset
targetidx = 1
gr = groups[1]
elif not gr[1] & unblocked:
gr = None
if gr is not None:
# update the set of awaited revisions with the one from the
# subgroup
unblocked |= gr[1]
# output all revisions in the subgroup
for r in gr[0]:
yield r
# delete the subgroup that you just output
# unless it is groups[0] in which case you just empty it.
if targetidx:
del groups[targetidx]
else:
gr[0][:] = []
# Check if we have some subgroup waiting for revisions we are not going to
# iterate over
for g in groups:
for r in g[0]:
yield r
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 @predicate('subrepo([pattern])')
Matt Harbison
revset: add the 'subrepo' symbol...
r24446 def subrepo(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Changesets that add, modify or remove the given subrepo. If no subrepo
Matt Harbison
revset: add the 'subrepo' symbol...
r24446 pattern is named, any subrepo changes are returned.
"""
# i18n: "subrepo" is a keyword
args = getargs(x, 0, 1, _('subrepo takes at most one argument'))
Yuya Nishihara
revset: define "pat" variable unconditionally in subrepo()...
r28272 pat = None
Matt Harbison
revset: add the 'subrepo' symbol...
r24446 if len(args) != 0:
pat = getstring(args[0], _("subrepo requires a pattern"))
m = matchmod.exact(repo.root, repo.root, ['.hgsubstate'])
def submatches(names):
Matt Harbison
util: extract stringmatcher() from revset...
r26481 k, p, m = util.stringmatcher(pat)
Matt Harbison
revset: add the 'subrepo' symbol...
r24446 for name in names:
if m(name):
yield name
def matches(x):
c = repo[x]
s = repo.status(c.p1().node(), c.node(), match=m)
Yuya Nishihara
revset: define "pat" variable unconditionally in subrepo()...
r28272 if pat is None:
Matt Harbison
revset: add the 'subrepo' symbol...
r24446 return s.added or s.modified or s.removed
if s.added:
Augie Fackler
cleanup: use __builtins__.any instead of util.any...
r25149 return any(submatches(c.substate.keys()))
Matt Harbison
revset: add the 'subrepo' symbol...
r24446
if s.modified:
subs = set(c.p1().substate.keys())
subs.update(c.substate.keys())
for path in submatches(subs):
if c.p1().substate.get(path) != c.substate.get(path):
return True
if s.removed:
Augie Fackler
cleanup: use __builtins__.any instead of util.any...
r25149 return any(submatches(c.p1().substate.keys()))
Matt Harbison
revset: add the 'subrepo' symbol...
r24446
return False
Yuya Nishihara
revset: add inspection data to all filter() calls...
r28424 return subset.filter(matches, condrepr=('<subrepo %r>', pat))
Matt Harbison
revset: add the 'subrepo' symbol...
r24446
Simon King
revset: add pattern matching to the 'user' revset expression
r16823 def _substringmatcher(pattern):
Matt Harbison
util: extract stringmatcher() from revset...
r26481 kind, pattern, matcher = util.stringmatcher(pattern)
Simon King
revset: add pattern matching to the 'user' revset expression
r16823 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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('tag([name])', safe=True)
Augie Fackler
revset: rename tagged() to tag() and allow it to take an optional tag name
r12715 def tag(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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'))
Matt Harbison
util: extract stringmatcher() from revset...
r26481 kind, pattern, matcher = util.stringmatcher(pattern)
Simon King
revset: add pattern matching to 'tag' revset expression...
r16820 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:
FUJIWARA Katsunori
revset: raise RepoLookupError to make present() predicate continue the query...
r23978 raise error.RepoLookupError(_("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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('tagged', safe=True)
Patrick Mezard
revsets: generate predicate help dynamically
r12821 def tagged(repo, subset, x):
return tag(repo, subset, x)
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('unstable()', safe=True)
Pierre-Yves David
obsolete: compute unstable changeset...
r17171 def unstable(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """Non-obsolete changesets with obsolete ancestors.
Patrick Mezard
revset: minor doc fixes on obsolete related revsets
r17291 """
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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('user(string)', safe=True)
Idan Kamara
revset: rearrange code so functions are sorted alphabetically
r13915 def user(repo, subset, x):
FUJIWARA Katsunori
revset: use decorator to register a function as revset predicate...
r27584 """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
FUJIWARA Katsunori
revset: use decorator to mark a predicate as safe...
r27587 @predicate('wdir', safe=True)
Yuya Nishihara
revset: add wdir() function to specify workingctx revision by command...
r24419 def wdir(repo, subset, x):
Yuya Nishihara
revset: document wdir() as an experimental function...
r30701 """Working directory. (EXPERIMENTAL)"""
Yuya Nishihara
revset: add wdir() function to specify workingctx revision by command...
r24419 # i18n: "wdir" is a keyword
getargs(x, 0, 0, _("wdir takes no arguments"))
Yuya Nishihara
revset: use integer representation of wdir() in revset...
r25765 if node.wdirrev in subset or isinstance(subset, fullreposet):
return baseset([node.wdirrev])
Yuya Nishihara
revset: add wdir() function to specify workingctx revision by command...
r24419 return baseset()
Yuya Nishihara
revset: fix order of nested '_(|int|hex)list' expression (BC)...
r29935 def _orderedlist(repo, subset, x):
Matt Mackall
revset: optimize building large lists in formatrevspec...
r15898 s = getstring(x, "internal error")
if not s:
Pierre-Yves David
baseset: use default value instead of [] when possible...
r22802 return baseset()
Yuya Nishihara
revset: make internal _list() expression remove duplicated revisions...
r25341 # remove duplicates here. it's difficult for caller to deduplicate sets
# because different symbols can point to the same rev.
Yuya Nishihara
revset: add fast path for _list() of integer revisions...
r25344 cl = repo.changelog
Yuya Nishihara
revset: make internal _list() expression remove duplicated revisions...
r25341 ls = []
seen = set()
for t in s.split('\0'):
Yuya Nishihara
revset: add fast path for _list() of integer revisions...
r25344 try:
# fast path for integer revision
r = int(t)
if str(r) != t or r not in cl:
raise ValueError
Durham Goode
revset: fix resolving strings from a list...
r26143 revs = [r]
Yuya Nishihara
revset: add fast path for _list() of integer revisions...
r25344 except ValueError:
Durham Goode
revset: fix resolving strings from a list...
r26143 revs = stringset(repo, subset, t)
for r in revs:
if r in seen:
continue
if (r in subset
or r == node.nullrev and isinstance(subset, fullreposet)):
ls.append(r)
seen.add(r)
Yuya Nishihara
revset: make internal _list() expression remove duplicated revisions...
r25341 return baseset(ls)
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
Yuya Nishihara
revset: fix order of nested '_(|int|hex)list' expression (BC)...
r29935 @predicate('_list', safe=True, takeorder=True)
def _list(repo, subset, x, order):
if order == followorder:
# slow path to take the subset order
return subset & _orderedlist(repo, fullreposet(repo), x)
else:
return _orderedlist(repo, subset, x)
def _orderedintlist(repo, subset, x):
Lucas Moscovicz
revset: added _intlist method to replace _list for %ld...
r20566 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')]
Pierre-Yves David
revset-_intlist: remove usage of `set()`...
r22876 s = subset
Lucas Moscovicz
revset: added _intlist method to replace _list for %ld...
r20566 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
Yuya Nishihara
revset: fix order of nested '_(|int|hex)list' expression (BC)...
r29935 @predicate('_intlist', safe=True, takeorder=True)
def _intlist(repo, subset, x, order):
if order == followorder:
# slow path to take the subset order
return subset & _orderedintlist(repo, fullreposet(repo), x)
else:
return _orderedintlist(repo, subset, x)
def _orderedhexlist(repo, subset, x):
Lucas Moscovicz
revset: added _hexlist method to replace _list for %ln...
r20569 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')]
Pierre-Yves David
revset-_hexlist: remove usage of `set()`...
r22877 s = subset
Lucas Moscovicz
revset: added _hexlist method to replace _list for %ln...
r20569 return baseset([r for r in ls if r in s])
Matt Mackall
revset: optimize building large lists in formatrevspec...
r15898
Yuya Nishihara
revset: fix order of nested '_(|int|hex)list' expression (BC)...
r29935 # for internal use
@predicate('_hexlist', safe=True, takeorder=True)
def _hexlist(repo, subset, x, order):
if order == followorder:
# slow path to take the subset order
return subset & _orderedhexlist(repo, fullreposet(repo), x)
else:
return _orderedhexlist(repo, subset, x)
Matt Mackall
revset: introduce revset core
r11275 methods = {
"range": rangeset,
Yuya Nishihara
revset: do not rewrite ':y' to '0:y' (issue5385)...
r30044 "rangepre": rangepre,
Bryan O'Sullivan
revset: turn dagrange into a function
r16860 "dagrange": dagrange,
Matt Mackall
revset: introduce revset core
r11275 "string": stringset,
Jordi Gutiérrez Hermoso
revset: don't error out if tokens parse as existing symbols...
r24932 "symbol": stringset,
Matt Mackall
revset: introduce revset core
r11275 "and": andset,
"or": orset,
"not": notset,
Durham Goode
revset: use smartset minus operator...
r28217 "difference": differenceset,
Matt Mackall
revset: introduce revset core
r11275 "list": listset,
Yuya Nishihara
revset: add parsing rule for key=value pair...
r25704 "keyvalue": keyvaluepair,
Matt Mackall
revset: introduce revset core
r11275 "func": func,
Kevin Gessner
revset: add ^ and ~ operators from parentrevspec extension...
r14070 "ancestor": ancestorspec,
"parent": parentspec,
Yuya Nishihara
revset: add stub to handle parentpost operation...
r29931 "parentpost": parentpost,
Matt Mackall
revset: introduce revset core
r11275 }
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 # Constants for ordering requirement, used in _analyze():
#
# If 'define', any nested functions and operations can change the ordering of
# the entries in the set. If 'follow', any nested functions and operations
# should take the ordering specified by the first operand to the '&' operator.
#
# For instance,
#
# X & (Y | Z)
# ^ ^^^^^^^
# | follow
# define
#
# will be evaluated as 'or(y(x()), z(x()))', where 'x()' can change the order
# of the entries in the set, but 'y()', 'z()' and 'or()' shouldn't.
#
# 'any' means the order doesn't matter. For instance,
#
# X & !Y
# ^
# any
#
# 'y()' can either enforce its ordering requirement or take the ordering
# specified by 'x()' because 'not()' doesn't care the order.
#
# Transition of ordering requirement:
#
# 1. starts with 'define'
# 2. shifts to 'follow' by 'x & y'
# 3. changes back to 'define' on function call 'f(x)' or function-like
# operation 'x (f) y' because 'f' may have its own ordering requirement
# for 'x' and 'y' (e.g. 'first(x)')
#
anyorder = 'any' # don't care the order
defineorder = 'define' # should define the order
followorder = 'follow' # must follow the current order
# transition table for 'x & y', from the current expression 'x' to 'y'
_tofolloworder = {
anyorder: anyorder,
defineorder: followorder,
followorder: followorder,
}
Yuya Nishihara
revset: construct arguments of only() against matched tree...
r29117 def _matchonly(revs, bases):
"""
>>> f = lambda *args: _matchonly(*map(parse, args))
>>> f('ancestors(A)', 'not ancestors(B)')
('list', ('symbol', 'A'), ('symbol', 'B'))
"""
if (revs is not None
Yuya Nishihara
revset: unnest isonly() closure from optimize()...
r29116 and revs[0] == 'func'
Yuya Nishihara
revset: check invalid function syntax "func-name"() explicitly...
r29441 and getsymbol(revs[1]) == 'ancestors'
Yuya Nishihara
revset: unnest isonly() closure from optimize()...
r29116 and bases is not None
and bases[0] == 'not'
and bases[1][0] == 'func'
Yuya Nishihara
revset: check invalid function syntax "func-name"() explicitly...
r29441 and getsymbol(bases[1][1]) == 'ancestors'):
Yuya Nishihara
revset: construct arguments of only() against matched tree...
r29117 return ('list', revs[2], bases[1][2])
Yuya Nishihara
revset: unnest isonly() closure from optimize()...
r29116
Yuya Nishihara
revset: resolve ambiguity of x^:y before alias expansion...
r29769 def _fixops(x):
"""Rewrite raw parsed tree to resolve ambiguous syntax which cannot be
handled well by our simple top-down parser"""
if not isinstance(x, tuple):
return x
op = x[0]
if op == 'parent':
# x^:y means (x^) : y, not x ^ (:y)
Yuya Nishihara
revset: also parse x^: as (x^):...
r29770 # x^: means (x^) :, not x ^ (:)
Yuya Nishihara
revset: resolve ambiguity of x^:y before alias expansion...
r29769 post = ('parentpost', x[1])
if x[2][0] == 'dagrangepre':
return _fixops(('dagrange', post, x[2][1]))
elif x[2][0] == 'rangepre':
return _fixops(('range', post, x[2][1]))
Yuya Nishihara
revset: also parse x^: as (x^):...
r29770 elif x[2][0] == 'rangeall':
return _fixops(('rangepost', post))
Yuya Nishihara
revset: wrap arguments of 'or' by 'list' node...
r29929 elif op == 'or':
# make number of arguments deterministic:
# x + y + z -> (or x y z) -> (or (list x y z))
return (op, _fixops(('list',) + x[1:]))
Yuya Nishihara
revset: resolve ambiguity of x^:y before alias expansion...
r29769
return (op,) + tuple(_fixops(y) for y in x[1:])
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 def _analyze(x, order):
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 if x is None:
return x
op = x[0]
if op == 'minus':
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 return _analyze(('and', x[1], ('not', x[2])), order)
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 elif op == 'only':
t = ('func', ('symbol', 'only'), ('list', x[1], x[2]))
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 return _analyze(t, order)
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 elif op == 'onlypost':
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 return _analyze(('func', ('symbol', 'only'), x[1]), order)
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 elif op == 'dagrangepre':
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 return _analyze(('func', ('symbol', 'ancestors'), x[1]), order)
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 elif op == 'dagrangepost':
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 return _analyze(('func', ('symbol', 'descendants'), x[1]), order)
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 elif op == 'rangeall':
Yuya Nishihara
revset: do not rewrite ':y' to '0:y' (issue5385)...
r30044 return _analyze(('rangepre', ('string', 'tip')), order)
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 elif op == 'rangepost':
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 return _analyze(('range', x[1], ('string', 'tip')), order)
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 elif op == 'negate':
s = getstring(x[1], _("can't negate that"))
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 return _analyze(('string', '-' + s), order)
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 elif op in ('string', 'symbol'):
return x
elif op == 'and':
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 ta = _analyze(x[1], order)
tb = _analyze(x[2], _tofolloworder[order])
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 return (op, ta, tb, order)
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 elif op == 'or':
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 return (op, _analyze(x[1], order), order)
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 elif op == 'not':
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 return (op, _analyze(x[1], anyorder), order)
Yuya Nishihara
revset: do not rewrite ':y' to '0:y' (issue5385)...
r30044 elif op in ('rangepre', 'parentpost'):
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 return (op, _analyze(x[1], defineorder), order)
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 elif op == 'group':
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 return _analyze(x[1], order)
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 elif op in ('dagrange', 'range', 'parent', 'ancestor'):
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 ta = _analyze(x[1], defineorder)
tb = _analyze(x[2], defineorder)
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 return (op, ta, tb, order)
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 elif op == 'list':
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 return (op,) + tuple(_analyze(y, order) for y in x[1:])
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 elif op == 'keyvalue':
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 return (op, x[1], _analyze(x[2], order))
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 elif op == 'func':
Yuya Nishihara
revset: forward ordering requirement to argument of present()...
r29943 f = getsymbol(x[1])
d = defineorder
if f == 'present':
# 'present(set)' is known to return the argument set with no
# modification, so forward the current order to its argument
d = order
return (op, x[1], _analyze(x[2], d), order)
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 raise ValueError('invalid operator %r' % op)
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 def analyze(x, order=defineorder):
Yuya Nishihara
revset: make analyze() a separate step from optimize()...
r29905 """Transform raw parsed tree to evaluatable tree which can be fed to
optimize() or getset()
All pseudo operations should be mapped to real operations or functions
defined in methods or symbols table respectively.
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930
'order' specifies how the current expression 'x' is ordered (see the
constants defined above.)
Yuya Nishihara
revset: make analyze() a separate step from optimize()...
r29905 """
Yuya Nishihara
revset: infer ordering flag to teach if operation should define/follow order...
r29930 return _analyze(x, order)
Yuya Nishihara
revset: make analyze() a separate step from optimize()...
r29905
Yuya Nishihara
revset: factor out public optimize() function from recursion...
r29119 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]
Yuya Nishihara
revset: extract tree transformation from optimize()...
r29904 if op in ('string', 'symbol'):
Matt Mackall
revset: optimize the parse tree directly...
r11279 return smallbonus, x # single revisions are small
Bryan O'Sullivan
revset: drop unreachable code
r16859 elif op == 'and':
Yuya Nishihara
revset: factor out public optimize() function from recursion...
r29119 wa, ta = _optimize(x[1], True)
wb, tb = _optimize(x[2], True)
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 order = x[3]
Yuya Nishihara
revset: unnest isonly() closure from optimize()...
r29116 w = min(wa, wb)
Siddharth Agarwal
revset: optimize missing ancestor expressions...
r20499
# (::x and not ::y)/(not ::y and ::x) have a fast path
Yuya Nishihara
revset: construct arguments of only() against matched tree...
r29117 tm = _matchonly(ta, tb) or _matchonly(tb, ta)
if tm:
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 return w, ('func', ('symbol', 'only'), tm, order)
Siddharth Agarwal
revset: optimize missing ancestor expressions...
r20499
Durham Goode
revset: use smartset minus operator...
r28217 if tb is not None and tb[0] == 'not':
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 return wa, ('difference', ta, tb[1], order)
Durham Goode
revset: use smartset minus operator...
r28217
Matt Mackall
revset: optimize the parse tree directly...
r11279 if wa > wb:
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 return w, (op, tb, ta, order)
return w, (op, ta, tb, order)
Matt Mackall
revset: optimize the parse tree directly...
r11279 elif op == 'or':
Yuya Nishihara
revset: optimize 'or' operation of trivial revisions to a list...
r25343 # fast path for machine-generated expression, that is likely to have
# lots of trivial revisions: 'a + b + c()' to '_list(a b) + c()'
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 order = x[2]
Yuya Nishihara
revset: optimize 'or' operation of trivial revisions to a list...
r25343 ws, ts, ss = [], [], []
def flushss():
if not ss:
return
if len(ss) == 1:
w, t = ss[0]
else:
s = '\0'.join(t[1] for w, t in ss)
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 y = ('func', ('symbol', '_list'), ('string', s), order)
Yuya Nishihara
revset: factor out public optimize() function from recursion...
r29119 w, t = _optimize(y, False)
Yuya Nishihara
revset: optimize 'or' operation of trivial revisions to a list...
r25343 ws.append(w)
ts.append(t)
del ss[:]
Yuya Nishihara
revset: wrap arguments of 'or' by 'list' node...
r29929 for y in getlist(x[1]):
Yuya Nishihara
revset: factor out public optimize() function from recursion...
r29119 w, t = _optimize(y, False)
Yuya Nishihara
revset: prevent crash caused by empty group expression while optimizing "or"...
r25996 if t is not None and (t[0] == 'string' or t[0] == 'symbol'):
Yuya Nishihara
revset: optimize 'or' operation of trivial revisions to a list...
r25343 ss.append((w, t))
continue
flushss()
ws.append(w)
ts.append(t)
flushss()
if len(ts) == 1:
return ws[0], ts[0] # 'or' operation is fully optimized out
Yuya Nishihara
revset: comment that we can't swap 'or' operands by weight...
r25307 # we can't reorder trees by weight because it would change the order.
# ("sort(a + b)" == "sort(b + a)", but "a + b" != "b + a")
Yuya Nishihara
revset: reduce nesting of chained 'or' operations (issue4624)...
r25309 # ts = tuple(t for w, t in sorted(zip(ws, ts), key=lambda wt: wt[0]))
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 return max(ws), (op, ('list',) + tuple(ts), order)
Matt Mackall
revset: introduce revset core
r11275 elif op == 'not':
Laurent Charignon
revset: optimize not public revset...
r25191 # Optimize not public() to _notpublic() because we have a fast version
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 if x[1][:3] == ('func', ('symbol', 'public'), None):
order = x[1][3]
newsym = ('func', ('symbol', '_notpublic'), None, order)
Yuya Nishihara
revset: factor out public optimize() function from recursion...
r29119 o = _optimize(newsym, not small)
Laurent Charignon
revset: optimize not public revset...
r25191 return o[0], o[1]
else:
Yuya Nishihara
revset: factor out public optimize() function from recursion...
r29119 o = _optimize(x[1], not small)
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 order = x[2]
return o[0], (op, o[1], order)
Yuya Nishihara
revset: do not rewrite ':y' to '0:y' (issue5385)...
r30044 elif op in ('rangepre', 'parentpost'):
Yuya Nishihara
revset: factor out public optimize() function from recursion...
r29119 o = _optimize(x[1], small)
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 order = x[2]
return o[0], (op, o[1], order)
Yuya Nishihara
revset: do not partial-match operator and function names in optimize()...
r29898 elif op in ('dagrange', 'range', 'parent', 'ancestor'):
Yuya Nishihara
revset: factor out public optimize() function from recursion...
r29119 wa, ta = _optimize(x[1], small)
wb, tb = _optimize(x[2], small)
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 order = x[3]
return wa + wb, (op, ta, tb, order)
Yuya Nishihara
revset: flatten chained 'list' operations (aka function args) (issue5072)...
r27987 elif op == 'list':
Yuya Nishihara
revset: factor out public optimize() function from recursion...
r29119 ws, ts = zip(*(_optimize(y, small) for y in x[1:]))
Yuya Nishihara
revset: flatten chained 'list' operations (aka function args) (issue5072)...
r27987 return sum(ws), (op,) + ts
Yuya Nishihara
revset: fix keyword arguments to go through optimization process...
r29766 elif op == 'keyvalue':
w, t = _optimize(x[2], small)
return w, (op, x[1], t)
Matt Mackall
revset: introduce revset core
r11275 elif op == 'func':
Yuya Nishihara
revset: check invalid function syntax "func-name"() explicitly...
r29441 f = getsymbol(x[1])
Yuya Nishihara
revset: factor out public optimize() function from recursion...
r29119 wa, ta = _optimize(x[2], small)
Yuya Nishihara
revset: do not partial-match operator and function names in optimize()...
r29898 if f in ('author', 'branch', 'closed', 'date', 'desc', 'file', 'grep',
Mads Kiilerich
revset: optimize for destination() being "inefficient"...
r30205 'keyword', 'outgoing', 'user', 'destination'):
Matt Mackall
revset: optimize the parse tree directly...
r11279 w = 10 # slow
Yuya Nishihara
revset: do not partial-match operator and function names in optimize()...
r29898 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
Yuya Nishihara
revset: categorize wdir() as very fast function...
r30700 elif f in ('reverse', 'limit', 'first', 'wdir', '_intlist'):
Matt Mackall
revset: optimize the parse tree directly...
r11279 w = 0
Yuya Nishihara
revset: do not partial-match operator and function names in optimize()...
r29898 elif f == "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
Yuya Nishihara
revset: pass around ordering flags to operations...
r29932 order = x[3]
return w + wa, (op, x[1], ta, order)
Yuya Nishihara
revset: make optimize() reject unknown operators...
r29896 raise ValueError('invalid operator %r' % op)
Matt Mackall
revset: introduce revset core
r11275
Yuya Nishihara
revset: factor out public optimize() function from recursion...
r29119 def optimize(tree):
Yuya Nishihara
revset: make analyze() a separate step from optimize()...
r29905 """Optimize evaluatable tree
All pseudo operations should be transformed beforehand.
"""
Yuya Nishihara
revset: factor out public optimize() function from recursion...
r29119 _weight, newtree = _optimize(tree, small=True)
return newtree
FUJIWARA Katsunori
revset: introduce "_parsealiasdecl" to parse alias declarations strictly...
r23845 # the set of valid characters for the initial letter of symbols in
# alias declarations and definitions
Augie Fackler
revset: build _syminitletters from a saner source: the string module...
r30071 _aliassyminitletters = _syminitletters | set(pycompat.sysstr('$'))
FUJIWARA Katsunori
revset: introduce "_parsealiasdecl" to parse alias declarations strictly...
r23845
Yuya Nishihara
revset: factor out common parsing function
r29073 def _parsewith(spec, lookup=None, syminitletters=None):
"""Generate a parse tree of given spec with given tokenizing options
>>> _parsewith('foo($1)', syminitletters=_aliassyminitletters)
('func', ('symbol', 'foo'), ('symbol', '$1'))
>>> _parsewith('$1')
Traceback (most recent call last):
...
ParseError: ("syntax error in revset '$1'", 0)
>>> _parsewith('foo bar')
Traceback (most recent call last):
...
ParseError: ('invalid token', 4)
"""
p = parser.parser(elements)
tree, pos = p.parse(tokenize(spec, lookup=lookup,
syminitletters=syminitletters))
if pos != len(spec):
raise error.ParseError(_('invalid token'), pos)
Yuya Nishihara
revset: resolve ambiguity of x^:y before alias expansion...
r29769 return _fixops(parser.simplifyinfixops(tree, ('list', 'or')))
Yuya Nishihara
revset: factor out common parsing function
r29073
Yuya Nishihara
parser: add stub class that will host alias parsing and expansion...
r28870 class _aliasrules(parser.basealiasrules):
"""Parsing and expansion rule set of revset aliases"""
_section = _('revset alias')
Yuya Nishihara
revset: define _parsealias() in _aliasrules class...
r29074
@staticmethod
def _parse(spec):
"""Parse alias declaration/definition ``spec``
This allows symbol names to use also ``$`` as an initial letter
(for backward compatibility), and callers of this function should
examine whether ``$`` is used also for unexpected symbols or not.
"""
return _parsewith(spec, syminitletters=_aliassyminitletters)
Yuya Nishihara
parser: factor out _trygetfunc() that extracts function name and arguments...
r28910
@staticmethod
def _trygetfunc(tree):
if tree[0] == 'func' and tree[1][0] == 'symbol':
return tree[1][1], getlist(tree[2])
Yuya Nishihara
parser: add stub class that will host alias parsing and expansion...
r28870
Yuya Nishihara
revset: remove showwarning option from expandaliases()...
r29922 def expandaliases(ui, tree):
Yuya Nishihara
parser: extract helper that creates a dict of aliases...
r28893 aliases = _aliasrules.buildmap(ui.configitems('revsetalias'))
Yuya Nishihara
parser: move functions that process alias expansion to rule-set class...
r28895 tree = _aliasrules.expand(aliases, tree)
Yuya Nishihara
revset: remove showwarning option from expandaliases()...
r29922 # warn about problematic (but not referred) aliases
for name, alias in sorted(aliases.iteritems()):
if alias.error and not alias.warned:
ui.warn(_('warning: %s\n') % (alias.error))
alias.warned = True
FUJIWARA Katsunori
revset: delay showing parse error for the revset alias until it is referred...
r23725 return tree
Alexander Solovyov
revset aliases
r14098
FUJIWARA Katsunori
revset: introduce new operator "##" to concatenate strings/symbols at runtime...
r23742 def foldconcat(tree):
"""Fold elements to be concatenated by `##`
"""
if not isinstance(tree, tuple) or tree[0] in ('string', 'symbol'):
return tree
if tree[0] == '_concat':
pending = [tree]
l = []
while pending:
e = pending.pop()
if e[0] == '_concat':
pending.extend(reversed(e[1:]))
elif e[0] in ('string', 'symbol'):
l.append(e[1])
else:
msg = _("\"##\" can't concatenate \"%s\" element") % (e[0])
raise error.ParseError(msg)
return ('string', ''.join(l))
else:
return tuple(foldconcat(t) for t in tree)
Alexander Solovyov
revset aliases
r14098
Matt Mackall
revset: pass a lookup function to the tokenizer
r20779 def parse(spec, lookup=None):
Yuya Nishihara
revset: factor out common parsing function
r29073 return _parsewith(spec, lookup=lookup)
Matt Mackall
revset: pass a lookup function to the tokenizer
r20779
Laurent Charignon
revset: add hook after tree parsing...
r24518 def posttreebuilthook(tree, repo):
# hook for extensions to execute code on the optimized tree
pass
Yuya Nishihara
revset: add option to make matcher takes the ordering of the input set...
r29955 def match(ui, spec, repo=None, order=defineorder):
"""Create a matcher for a single revision spec
If order=followorder, a matcher takes the ordering specified by the input
set.
"""
return matchany(ui, [spec], repo=repo, order=order)
def matchany(ui, specs, repo=None, order=defineorder):
Yuya Nishihara
revset: add matchany() to construct OR expression from a list of specs...
r25927 """Create a matcher that will include any revisions matching one of the
Yuya Nishihara
revset: add option to make matcher takes the ordering of the input set...
r29955 given specs
If order=followorder, a matcher takes the ordering specified by the input
set.
"""
Yuya Nishihara
revset: add matchany() to construct OR expression from a list of specs...
r25927 if not specs:
def mfunc(repo, subset=None):
return baseset()
return mfunc
if not all(specs):
raise error.ParseError(_("empty query"))
lookup = None
if repo:
lookup = repo.__contains__
if len(specs) == 1:
tree = parse(specs[0], lookup)
else:
Yuya Nishihara
revset: wrap arguments of 'or' by 'list' node...
r29929 tree = ('or', ('list',) + tuple(parse(s, lookup) for s in specs))
Yuya Nishihara
revset: add public function to create matcher from evaluatable tree...
r29906
Matt Mackall
revset: allow bypassing alias expansion...
r14900 if ui:
Yuya Nishihara
revset: remove showwarning option from expandaliases()...
r29922 tree = expandaliases(ui, tree)
FUJIWARA Katsunori
revset: introduce new operator "##" to concatenate strings/symbols at runtime...
r23742 tree = foldconcat(tree)
Yuya Nishihara
revset: add option to make matcher takes the ordering of the input set...
r29955 tree = analyze(tree, order)
Yuya Nishihara
revset: factor out public optimize() function from recursion...
r29119 tree = optimize(tree)
Laurent Charignon
revset: add hook after tree parsing...
r24518 posttreebuilthook(tree, repo)
Yuya Nishihara
revset: add public function to create matcher from evaluatable tree...
r29906 return makematcher(tree)
def makematcher(tree):
"""Create a matcher from an evaluatable tree"""
Yuya Nishihara
revset: make match function initiate query from full set by default...
r24114 def mfunc(repo, subset=None):
if subset is None:
Yuya Nishihara
revset: specify fullreposet without using spanset factory...
r24115 subset = fullreposet(repo)
Pierre-Yves David
match: check if an object is a baseset using `isascending` instead of `set`...
r22885 if util.safehasattr(subset, 'isascending'):
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:
liscju
i18n: translate abort messages...
r29389 raise error.Abort(_('unexpected revspec format character %s')
% d)
Matt Mackall
revset: add formatspec convenience query builder
r14901 else:
ret += c
pos += 1
return ret
Patrick Mezard
debugrevspec: pretty print output...
r16218 def prettyformat(tree):
Yuya Nishihara
parser: move prettyformat() function from revset module...
r25253 return parser.prettyformat(tree, ('string', 'symbol'))
Patrick Mezard
debugrevspec: pretty print output...
r16218
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
Yuya Nishihara
revset: add extra data to filteredset for better inspection...
r28423 def _formatsetrepr(r):
"""Format an optional printable representation of a set
======== =================================
type(r) example
======== =================================
tuple ('<not %r>', other)
str '<branch closed>'
callable lambda: '<branch %r>' % sorted(b)
object other
======== =================================
"""
if r is None:
return ''
elif isinstance(r, tuple):
return r[0] % r[1:]
elif isinstance(r, str):
return r
elif callable(r):
return r()
else:
return repr(r)
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 __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 isdescending(self):
"""True if the set will iterate in descending order"""
raise NotImplementedError()
Martijn Pieters
revset: record if a set is in topographical order...
r29346 def istopo(self):
"""True if the set will iterate in topographical order"""
raise NotImplementedError()
Pierre-Yves David
revset: introduce an abstractsmartset class...
r22692 def min(self):
"""return the minimum element in the set"""
Mads Kiilerich
revset: don't cache abstractsmartset min/max invocations infinitely...
r30227 if self.fastasc is None:
v = min(self)
else:
for v in self.fastasc():
break
else:
raise ValueError('arg is an empty sequence')
self.min = lambda: v
return v
Pierre-Yves David
revset: introduce an abstractsmartset class...
r22692 def max(self):
"""return the maximum element in the set"""
Mads Kiilerich
revset: don't cache abstractsmartset min/max invocations infinitely...
r30227 if self.fastdesc is None:
return max(self)
else:
for v in self.fastdesc():
break
else:
raise ValueError('arg is an empty sequence')
self.max = lambda: v
return v
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: make __len__ part of the offical API...
r22995 def __len__(self):
"""return the length of the smartsets
This can be expensive on smartset that could be lazy otherwise."""
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."""
Yuya Nishihara
revset: optimize "x & fullreposet" case...
r24459 if isinstance(other, fullreposet):
return self
Yuya Nishihara
revset: add extra data to filteredset for better inspection...
r28423 return self.filter(other.__contains__, condrepr=other, cache=False)
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
revset: restore order of `or` operation as in Mercurial 2.9...
r22861 return addset(self, other)
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__
Yuya Nishihara
revset: add extra data to filteredset for better inspection...
r28423 return self.filter(lambda r: not c(r), condrepr=('<not %r>', other),
cache=False)
def filter(self, condition, condrepr=None, cache=True):
Pierre-Yves David
revset: introduce an abstractsmartset class...
r22692 """Returns this smartset filtered by condition as a new smartset.
`condition` is a callable which takes a revision number and returns a
Yuya Nishihara
revset: add extra data to filteredset for better inspection...
r28423 boolean. Optional `condrepr` provides a printable representation of
the given `condition`.
Pierre-Yves David
revset: introduce an abstractsmartset class...
r22692
This is part of the mandatory API for smartset."""
Pierre-Yves David
revset: cache most conditions used in `filter`...
r22864 # builtin cannot be cached. but do not needs to
if cache and util.safehasattr(condition, 'func_code'):
condition = util.cachefunc(condition)
Yuya Nishihara
revset: add extra data to filteredset for better inspection...
r28423 return filteredset(self, condition, condrepr)
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 """
Martijn Pieters
revset: record if a set is in topographical order...
r29346 def __init__(self, data=(), datarepr=None, istopo=False):
Yuya Nishihara
revset: stub to add extra data to baseset for better inspection...
r28425 """
datarepr: a tuple of (format, obj, ...), a function or an object that
provides a printable representation of the given data.
"""
Pierre-Yves David
revset: force ascending order for baseset initialized from a set...
r28786 self._ascending = None
Martijn Pieters
revset: record if a set is in topographical order...
r29346 self._istopo = istopo
Pierre-Yves David
baseset: stop inheriting from built-in list class...
r22825 if not isinstance(data, list):
Pierre-Yves David
baseset: keep the input set around...
r26060 if isinstance(data, set):
self._set = data
Pierre-Yves David
revset: force ascending order for baseset initialized from a set...
r28786 # set has no order we pick one for stability purpose
self._ascending = True
Pierre-Yves David
baseset: stop inheriting from built-in list class...
r22825 data = list(data)
self._list = data
Yuya Nishihara
revset: stub to add extra data to baseset for better inspection...
r28425 self._datarepr = datarepr
Lucas Moscovicz
revset: implemented set caching for revset evaluation...
r20365
Pierre-Yves David
baseset: implement a fastasc and fastdesc...
r22826 @util.propertycache
Pierre-Yves David
baseset: make `_set` a property cache...
r22879 def _set(self):
return set(self._list)
@util.propertycache
Pierre-Yves David
baseset: implement a fastasc and fastdesc...
r22826 def _asclist(self):
asclist = self._list[:]
asclist.sort()
return asclist
Pierre-Yves David
baseset: prepare lazy ordering in __iter__...
r22827 def __iter__(self):
if self._ascending is None:
return iter(self._list)
elif self._ascending:
return iter(self._asclist)
else:
return reversed(self._asclist)
Pierre-Yves David
baseset: implement a fastasc and fastdesc...
r22826 def fastasc(self):
return iter(self._asclist)
def fastdesc(self):
return reversed(self._asclist)
Pierre-Yves David
revset: add an optimised baseset.__contains__ (issue4371)...
r22503 @util.propertycache
def __contains__(self):
Pierre-Yves David
baseset: access `_set` directly for containment check...
r22880 return self._set.__contains__
Pierre-Yves David
revset: add an optimised baseset.__contains__ (issue4371)...
r22503
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):
Pierre-Yves David
baseset: explicitly track order of the baseset...
r22829 self._ascending = not bool(reverse)
Martijn Pieters
revset: record if a set is in topographical order...
r29346 self._istopo = False
Pierre-Yves David
baseset: stop inheriting from built-in list class...
r22825
def reverse(self):
Pierre-Yves David
baseset: explicitly track order of the baseset...
r22829 if self._ascending is None:
self._list.reverse()
else:
self._ascending = not self._ascending
Martijn Pieters
revset: record if a set is in topographical order...
r29346 self._istopo = False
Pierre-Yves David
baseset: stop inheriting from built-in list class...
r22825
def __len__(self):
return len(self._list)
Pierre-Yves David
revset: add a `__nonzero__` to baseset...
r22691
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."""
Pierre-Yves David
baseset: empty or one-element sets are ascending and descending...
r22863 if len(self) <= 1:
return True
Pierre-Yves David
baseset: fix isascending and isdescending...
r22828 return self._ascending is not None and self._ascending
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725
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."""
Pierre-Yves David
baseset: empty or one-element sets are ascending and descending...
r22863 if len(self) <= 1:
return True
Pierre-Yves David
baseset: fix isascending and isdescending...
r22828 return self._ascending is not None and not self._ascending
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725
Martijn Pieters
revset: record if a set is in topographical order...
r29346 def istopo(self):
"""Is the collection is in topographical order or not.
This is part of the mandatory API for smartset."""
if len(self) <= 1:
return True
return self._istopo
Pierre-Yves David
baseset: implement `first` and `last` methods
r22812 def first(self):
if self:
Pierre-Yves David
baseset: explicitly track order of the baseset...
r22829 if self._ascending is None:
return self._list[0]
elif self._ascending:
return self._asclist[0]
else:
return self._asclist[-1]
Pierre-Yves David
baseset: implement `first` and `last` methods
r22812 return None
def last(self):
if self:
Pierre-Yves David
baseset: explicitly track order of the baseset...
r22829 if self._ascending is None:
return self._list[-1]
elif self._ascending:
return self._asclist[-1]
else:
return self._asclist[0]
Pierre-Yves David
baseset: implement `first` and `last` methods
r22812 return None
Yuya Nishihara
revset: add __repr__ to all smartset classes...
r24457 def __repr__(self):
d = {None: '', False: '-', True: '+'}[self._ascending]
Yuya Nishihara
revset: stub to add extra data to baseset for better inspection...
r28425 s = _formatsetrepr(self._datarepr)
if not s:
Pierre-Yves David
revset: stabilize repr of baseset initialized with a set...
r28785 l = self._list
# if _list has been built from a set, it might have a different
# order from one python implementation to another.
# We fallback to the sorted version for a stable output.
if self._ascending is not None:
l = self._asclist
s = repr(l)
Yuya Nishihara
revset: stub to add extra data to baseset for better inspection...
r28425 return '<%s%s %s>' % (type(self).__name__, d, s)
Yuya Nishihara
revset: add __repr__ to all smartset classes...
r24457
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
"""
Yuya Nishihara
revset: add extra data to filteredset for better inspection...
r28423 def __init__(self, subset, condition=lambda x: True, condrepr=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.
Yuya Nishihara
revset: add extra data to filteredset for better inspection...
r28423 condrepr: a tuple of (format, obj, ...), a function or an object that
provides a printable representation of the given condition.
Pierre-Yves David
revset: add some documentation for lazyset
r20738 """
Lucas Moscovicz
revset: added lazyset class with basic operations...
r20427 self._subset = subset
self._condition = condition
Yuya Nishihara
revset: add extra data to filteredset for better inspection...
r28423 self._condrepr = condrepr
Lucas Moscovicz
revset: added lazyset class with basic operations...
r20427
def __contains__(self, x):
Yuya Nishihara
revset: uncache filteredset.__contains__...
r26212 return x in self._subset and self._condition(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):
Kostia Balytskyi
revset: make filteredset.__nonzero__ respect the order of the filteredset...
r29304 fast = None
candidates = [self.fastasc if self.isascending() else None,
self.fastdesc if self.isdescending() else None,
self.fastasc,
self.fastdesc]
for candidate in candidates:
if candidate is not None:
fast = candidate
break
Pierre-Yves David
revset: avoid implicit None testing in revset...
r26307 if fast is not None:
Durham Goode
revset: speed up existence checks for ordered filtered sets...
r26306 it = fast()
Pierre-Yves David
revset: avoid implicit None testing in revset...
r26307 else:
it = self
Durham Goode
revset: speed up existence checks for ordered filtered sets...
r26306
for r in it:
Lucas Moscovicz
revset: added __nonzero__ method to lazyset...
r20552 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.
Maciej Fijalkowski
revset: prevent infinite recursion on pypy...
r28718 # until this gets improved, we use generator expression
Mads Kiilerich
spelling: fixes of non-dictionary words
r30332 # here, since list comprehensions are free to call __len__ again
Maciej Fijalkowski
revset: prevent infinite recursion on pypy...
r28718 # causing infinite recursion
l = baseset(r for r in self)
Lucas Moscovicz
revset: added operations to duck type baseset...
r20429 return len(l)
def sort(self, reverse=False):
Pierre-Yves David
filteredset: drop explicit order management...
r22862 self._subset.sort(reverse=reverse)
Lucas Moscovicz
revset: added operations to duck type baseset...
r20429
def reverse(self):
self._subset.reverse()
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725 def isascending(self):
Pierre-Yves David
filteredset: drop explicit order management...
r22862 return self._subset.isascending()
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725
def isdescending(self):
Pierre-Yves David
filteredset: drop explicit order management...
r22862 return self._subset.isdescending()
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725
Martijn Pieters
revset: record if a set is in topographical order...
r29346 def istopo(self):
return self._subset.istopo()
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
Pierre-Yves David
revset: rework 'filteredset.last'...
r25648 if self.isascending():
Pierre-Yves David
filteredset: drop explicit order management...
r22862 it = self.fastdesc
Pierre-Yves David
revset: rework 'filteredset.last'...
r25648 elif self.isdescending():
it = self.fastasc
if it is not None:
for x in it():
return x
return None #empty case
else:
x = None
for x in self:
pass
Pierre-Yves David
filteredset: implement `first` and `last`
r22813 return x
Yuya Nishihara
revset: add __repr__ to all smartset classes...
r24457 def __repr__(self):
Yuya Nishihara
revset: add extra data to filteredset for better inspection...
r28423 xs = [repr(self._subset)]
s = _formatsetrepr(self._condrepr)
if s:
xs.append(s)
return '<%s %s>' % (type(self).__name__, ', '.join(xs))
Yuya Nishihara
revset: add __repr__ to all smartset classes...
r24457
Yuya Nishihara
revset: extract addset._iterordered to free function...
r25131 def _iterordered(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
try:
# Consume both iterators in an ordered way until one is empty
while True:
if val1 is None:
timeless
py3: convert to next() function...
r29216 val1 = next(iter1)
Yuya Nishihara
revset: extract addset._iterordered to free function...
r25131 if val2 is None:
timeless
py3: convert to next() function...
r29216 val2 = next(iter2)
timeless
revset: rename variable to avoid shadowing with builtin next() function...
r29215 n = choice(val1, val2)
yield n
if val1 == n:
Yuya Nishihara
revset: extract addset._iterordered to free function...
r25131 val1 = None
timeless
revset: rename variable to avoid shadowing with builtin next() function...
r29215 if val2 == n:
Yuya Nishihara
revset: extract addset._iterordered to free function...
r25131 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
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
Yuya Nishihara
revset: test current behavior of addset class...
r25024
>>> xs = baseset([0, 3, 2])
>>> ys = baseset([5, 2, 4])
>>> rs = addset(xs, ys)
>>> bool(rs), 0 in rs, 1 in rs, 5 in rs, rs.first(), rs.last()
(True, True, False, True, 0, 4)
>>> rs = addset(xs, baseset([]))
>>> bool(rs), 0 in rs, 1 in rs, rs.first(), rs.last()
(True, True, False, 0, 2)
>>> rs = addset(baseset([]), baseset([]))
>>> bool(rs), 0 in rs, rs.first(), rs.last()
(False, False, None, None)
iterate unsorted:
>>> rs = addset(xs, ys)
Maciej Fijalkowski
pypy: fix doctests for pypy optimizations...
r28717 >>> # (use generator because pypy could call len())
>>> list(x for x in rs) # without _genlist
Yuya Nishihara
revset: test current behavior of addset class...
r25024 [0, 3, 2, 5, 4]
>>> assert not rs._genlist
>>> len(rs)
5
>>> [x for x in rs] # with _genlist
[0, 3, 2, 5, 4]
>>> assert rs._genlist
iterate ascending:
>>> rs = addset(xs, ys, ascending=True)
Maciej Fijalkowski
pypy: fix doctests for pypy optimizations...
r28717 >>> # (use generator because pypy could call len())
>>> list(x for x in rs), list(x for x in rs.fastasc()) # without _asclist
Yuya Nishihara
revset: test current behavior of addset class...
r25024 ([0, 2, 3, 4, 5], [0, 2, 3, 4, 5])
>>> assert not rs._asclist
Pierre-Yves David
revset: fix iteration over ordered addset composed of non-ordered operands...
r25115 >>> len(rs)
5
>>> [x for x in rs], [x for x in rs.fastasc()]
([0, 2, 3, 4, 5], [0, 2, 3, 4, 5])
Yuya Nishihara
revset: test current behavior of addset class...
r25024 >>> assert rs._asclist
iterate descending:
>>> rs = addset(xs, ys, ascending=False)
Maciej Fijalkowski
pypy: fix doctests for pypy optimizations...
r28717 >>> # (use generator because pypy could call len())
>>> list(x for x in rs), list(x for x in rs.fastdesc()) # without _asclist
Yuya Nishihara
revset: test current behavior of addset class...
r25024 ([5, 4, 3, 2, 0], [5, 4, 3, 2, 0])
>>> assert not rs._asclist
Pierre-Yves David
revset: fix iteration over ordered addset composed of non-ordered operands...
r25115 >>> len(rs)
5
>>> [x for x in rs], [x for x in rs.fastdesc()]
([5, 4, 3, 2, 0], [5, 4, 3, 2, 0])
Yuya Nishihara
revset: test current behavior of addset class...
r25024 >>> assert rs._asclist
iterate ascending without fastasc:
>>> rs = addset(xs, generatorset(ys), ascending=True)
>>> assert rs.fastasc is None
Pierre-Yves David
revset: fix iteration over ordered addset composed of non-ordered operands...
r25115 >>> [x for x in rs]
[0, 2, 3, 4, 5]
Yuya Nishihara
revset: test current behavior of addset class...
r25024
iterate descending without fastdesc:
>>> rs = addset(generatorset(xs), ys, ascending=False)
>>> assert rs.fastdesc is None
Pierre-Yves David
revset: fix iteration over ordered addset composed of non-ordered operands...
r25115 >>> [x for x in rs]
[5, 4, 3, 2, 0]
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: do lazy sorting...
r22859 self._asclist = None
Lucas Moscovicz
revset: added cached generated list to addset...
r20720
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):
Durham Goode
revset: fix O(2^n) perf regression in addset...
r23100 return bool(self._r1) or bool(self._r2)
Pierre-Yves David
addset: add a __nonzero__ method...
r22743
Lucas Moscovicz
revset: added cached generated list to addset...
r20720 @util.propertycache
def _list(self):
if not self._genlist:
Pierre-Yves David
revset: fix iteration over ordered addset composed of non-ordered operands...
r25115 self._genlist = baseset(iter(self))
Lucas Moscovicz
revset: added cached generated list to addset...
r20720 return self._genlist
Lucas Moscovicz
revset: added addset class with its basic methods...
r20694
Pierre-Yves David
revset: fix iteration over ordered addset composed of non-ordered operands...
r25115 def __iter__(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:
Pierre-Yves David
revset: fix iteration over ordered addset composed of non-ordered operands...
r25115 if self._genlist:
return iter(self._genlist)
def arbitraryordergen():
Pierre-Yves David
addset: drop caching through generatorset...
r22799 for r in self._r1:
yield r
Pierre-Yves David
addset: drop `.set()` usage during iteration...
r22881 inr1 = self._r1.__contains__
Pierre-Yves David
addset: drop caching through generatorset...
r22799 for r in self._r2:
Pierre-Yves David
addset: drop `.set()` usage during iteration...
r22881 if not inr1(r):
Lucas Moscovicz
revset: added addset class with its basic methods...
r20694 yield r
Pierre-Yves David
revset: fix iteration over ordered addset composed of non-ordered operands...
r25115 return arbitraryordergen()
# try to use our own fast iterator if it exists
Pierre-Yves David
addset: do lazy sorting...
r22859 self._trysetasclist()
if self._ascending:
Yuya Nishihara
revset: use fastasc/fastdesc switch consistently in addset.__iter__
r25130 attr = 'fastasc'
Pierre-Yves David
addset: do lazy sorting...
r22859 else:
Yuya Nishihara
revset: use fastasc/fastdesc switch consistently in addset.__iter__
r25130 attr = 'fastdesc'
it = getattr(self, attr)
Pierre-Yves David
revset: fix iteration over ordered addset composed of non-ordered operands...
r25115 if it is not None:
return it()
# maybe half of the component supports fast
# get iterator for _r1
iter1 = getattr(self._r1, attr)
if iter1 is None:
# let's avoid side effect (not sure it matters)
iter1 = iter(sorted(self._r1, reverse=not self._ascending))
else:
iter1 = iter1()
# get iterator for _r2
iter2 = getattr(self._r2, attr)
if iter2 is None:
# let's avoid side effect (not sure it matters)
iter2 = iter(sorted(self._r2, reverse=not self._ascending))
else:
iter2 = iter2()
Yuya Nishihara
revset: extract addset._iterordered to free function...
r25131 return _iterordered(self._ascending, iter1, iter2)
Pierre-Yves David
addset: do lazy sorting...
r22859
def _trysetasclist(self):
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r23139 """populate the _asclist attribute if possible and necessary"""
Pierre-Yves David
addset: do lazy sorting...
r22859 if self._genlist is not None and self._asclist is None:
self._asclist = sorted(self._genlist)
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):
Pierre-Yves David
addset: do lazy sorting...
r22859 self._trysetasclist()
if self._asclist is not None:
return self._asclist.__iter__
Pierre-Yves David
addset: offer a fastasc and fastdesc methods...
r22742 iter1 = self._r1.fastasc
iter2 = self._r2.fastasc
if None in (iter1, iter2):
return None
Yuya Nishihara
revset: extract addset._iterordered to free function...
r25131 return lambda: _iterordered(True, iter1(), iter2())
Pierre-Yves David
addset: offer a fastasc and fastdesc methods...
r22742
@property
def fastdesc(self):
Pierre-Yves David
addset: do lazy sorting...
r22859 self._trysetasclist()
if self._asclist is not None:
return self._asclist.__reversed__
Pierre-Yves David
addset: offer a fastasc and fastdesc methods...
r22742 iter1 = self._r1.fastdesc
iter2 = self._r2.fastdesc
if None in (iter1, iter2):
return None
Yuya Nishihara
revset: extract addset._iterordered to free function...
r25131 return lambda: _iterordered(False, iter1(), iter2())
Pierre-Yves David
addset: split simple and ordered iteration...
r22741
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 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.
"""
Pierre-Yves David
addset: do lazy sorting...
r22859 self._ascending = not reverse
Lucas Moscovicz
revset: added sort method in addset...
r20724
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
Martijn Pieters
revset: record if a set is in topographical order...
r29346 def istopo(self):
# not worth the trouble asserting if the two sets combined are still
# in topographical order. Use the sort() predicate to explicitly sort
# again instead.
return False
Lucas Moscovicz
revset: added reverse method to addset...
r20723 def reverse(self):
Pierre-Yves David
addset: do lazy sorting...
r22859 if self._ascending is None:
self._list.reverse()
else:
Lucas Moscovicz
revset: added reverse method to addset...
r20723 self._ascending = not self._ascending
Pierre-Yves David
addset: implement first and last methods...
r22810 def first(self):
Pierre-Yves David
addset: fix `first` and `last` on sorted addset (issue4426)...
r23127 for x in self:
return x
Pierre-Yves David
addset: implement first and last methods...
r22810 return None
def last(self):
Pierre-Yves David
addset: fix `first` and `last` on sorted addset (issue4426)...
r23127 self.reverse()
val = self.first()
self.reverse()
return val
Pierre-Yves David
addset: implement first and last methods...
r22810
Yuya Nishihara
revset: add __repr__ to all smartset classes...
r24457 def __repr__(self):
d = {None: '', False: '-', True: '+'}[self._ascending]
return '<%s%s %r, %r>' % (type(self).__name__, d, self._r1, self._r2)
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):
Pierre-Yves David
revset: make generatorset.__nonzero__ lazy...
r24936 # Do not use 'for r in self' because it will enforce the iteration
# order (default ascending), possibly unrolling a whole descending
# iterator.
if self._genlist:
return True
for r in self._consumegen():
Pierre-Yves David
generatorset: implement __nonzero__...
r22739 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
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r23139 # removed from _consumegen and added to genlist in another instance.
Pierre-Yves David
revset: document the choice made in __generatorset.__iter__...
r22494 #
# 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
Pierre-Yves David
generatorset: implement __len__...
r22996 def __len__(self):
for x in self._consumegen():
pass
return len(self._genlist)
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
Martijn Pieters
revset: record if a set is in topographical order...
r29346 def istopo(self):
# not worth the trouble asserting if the two sets combined are still
# in topographical order. Use the sort() predicate to explicitly sort
# again instead.
return False
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()
Pierre-Yves David
generatorset: use 'next()' to simplify the code...
r25146 return next(it(), None)
Pierre-Yves David
generatorset: implement first and last methods
r22811
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()
Pierre-Yves David
generatorset: use 'next()' to simplify the code...
r25146 return next(it(), None)
Pierre-Yves David
generatorset: implement first and last methods
r22811
Yuya Nishihara
revset: add __repr__ to all smartset classes...
r24457 def __repr__(self):
d = {False: '-', True: '+'}[self._ascending]
return '<%s%s>' % (type(self).__name__, d)
Yuya Nishihara
revset: drop factory that promotes spanset to fullreposet...
r24116 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
Martijn Pieters
revset: record if a set is in topographical order...
r29346 def istopo(self):
# not worth the trouble asserting if the two sets combined are still
# in topographical order. Use the sort() predicate to explicitly sort
# again instead.
return False
Pierre-Yves David
spanset: enforce the order lazily to gain `fastasc` and `fastdesc` methods...
r22717 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
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725 def isascending(self):
Yuya Nishihara
revset: fix spanset.isascending() to honor sort() or reverse() request...
r23826 return self._ascending
Lucas Moscovicz
revset: added isascending and isdescending methods to smartset classes...
r20725
def isdescending(self):
Yuya Nishihara
revset: fix spanset.isascending() to honor sort() or reverse() request...
r23826 return not self._ascending
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
Yuya Nishihara
revset: add __repr__ to all smartset classes...
r24457 def __repr__(self):
d = {False: '-', True: '+'}[self._ascending]
return '<%s%s %d:%d>' % (type(self).__name__, d,
self._start, self._end - 1)
Yuya Nishihara
revset: drop factory that promotes spanset to fullreposet...
r24116 class fullreposet(spanset):
Pierre-Yves David
revert: add a fullreposet class...
r22508 """a set containing all revisions in the repo
Yuya Nishihara
revset: extend fullreposet to make "null" revision magically appears in set...
r24204 This class exists to host special optimization and magic to handle virtual
revisions such as "null".
Pierre-Yves David
revert: add a fullreposet class...
r22508 """
def __init__(self, repo):
super(fullreposet, self).__init__(repo)
Pierre-Yves David
revset: fast implementation for fullreposet.__and__...
r22510 def __and__(self, other):
Mads Kiilerich
spelling: fixes from proofreading of spell checker issues
r23139 """As self contains the whole repo, all of the other set should also be
in self. Therefore `self & other = other`.
Pierre-Yves David
revset: fast implementation for fullreposet.__and__...
r22510
This boldly assumes the other contains valid revs only.
"""
# other not a smartset, make is so
Pierre-Yves David
fullreposet: detect smartset using "isascending" instead of "set"...
r22883 if not util.safehasattr(other, 'isascending'):
Pierre-Yves David
revset: fast implementation for fullreposet.__and__...
r22510 # 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)
Yuya Nishihara
revset: simplify fullreposet.__and__ to call sort() with boolean flag...
r23827 other.sort(reverse=self.isdescending())
Pierre-Yves David
revset: fast implementation for fullreposet.__and__...
r22510 return other
Yuya Nishihara
debugrevspec: show nesting structure of smartsets if verbose...
r24458 def prettyformatset(revs):
lines = []
rs = repr(revs)
p = 0
while p < len(rs):
q = rs.find('<', p + 1)
if q < 0:
q = len(rs)
l = rs.count('<', 0, p) - rs.count('>', 0, p)
assert l >= 0
lines.append((l, rs[p:q].rstrip()))
p = q
return '\n'.join(' ' * l + s for l, s in lines)
FUJIWARA Katsunori
registrar: define revsetpredicate to decorate revset predicate...
r28393 def loadpredicate(ui, extname, registrarobj):
"""Load revset predicates from specified registrarobj
"""
for name, func in registrarobj._table.iteritems():
symbols[name] = func
if func._safe:
safesymbols.add(name)
FUJIWARA Katsunori
revset: replace predicate by revsetpredicate of registrar...
r28395 # load built-in predicates explicitly to setup safesymbols
loadpredicate(None, None, predicate)
Patrick Mezard
hggettext: handle i18nfunctions declaration for docstrings translations
r12823 # tell hggettext to extract docstrings from these functions:
i18nfunctions = symbols.values()