comparison mercurial/revset.py @ 34280:b0790bebfcf8

revset: move weight information to predicate Previously revset weight is hardcoded and cannot be modified. This patch moves it to predicate so newly registered revsets could define their weight to properly give static optimization some hint. Differential Revision: https://phab.mercurial-scm.org/D657
author Jun Wu <quark@fb.com>
date Fri, 01 Sep 2017 19:42:09 -0700
parents c6c8a52e28c9
children 2c3b8fa3211b
comparison
equal deleted inserted replaced
34279:53fb09c73ba8 34280:b0790bebfcf8
251 # fn(repo, subset, x) 251 # fn(repo, subset, x)
252 # with: 252 # with:
253 # repo - current repository instance 253 # repo - current repository instance
254 # subset - of revisions to be examined 254 # subset - of revisions to be examined
255 # x - argument in tree form 255 # x - argument in tree form
256 symbols = {} 256 symbols = revsetlang.symbols
257 257
258 # symbols which can't be used for a DoS attack for any given input 258 # symbols which can't be used for a DoS attack for any given input
259 # (e.g. those which accept regexes as plain strings shouldn't be included) 259 # (e.g. those which accept regexes as plain strings shouldn't be included)
260 # functions that just return a lot of changesets (like all) don't count here 260 # functions that just return a lot of changesets (like all) don't count here
261 safesymbols = set() 261 safesymbols = set()
274 sourceset = None 274 sourceset = None
275 if x is not None: 275 if x is not None:
276 sourceset = getset(repo, fullreposet(repo), x) 276 sourceset = getset(repo, fullreposet(repo), x)
277 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)]) 277 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
278 278
279 @predicate('adds(pattern)', safe=True) 279 @predicate('adds(pattern)', safe=True, weight=30)
280 def adds(repo, subset, x): 280 def adds(repo, subset, x):
281 """Changesets that add a file matching pattern. 281 """Changesets that add a file matching pattern.
282 282
283 The pattern without explicit kind like ``glob:`` is expected to be 283 The pattern without explicit kind like ``glob:`` is expected to be
284 relative to the current directory and match against a file or a 284 relative to the current directory and match against a file or a
286 """ 286 """
287 # i18n: "adds" is a keyword 287 # i18n: "adds" is a keyword
288 pat = getstring(x, _("adds requires a pattern")) 288 pat = getstring(x, _("adds requires a pattern"))
289 return checkstatus(repo, subset, pat, 1) 289 return checkstatus(repo, subset, pat, 1)
290 290
291 @predicate('ancestor(*changeset)', safe=True) 291 @predicate('ancestor(*changeset)', safe=True, weight=0.5)
292 def ancestor(repo, subset, x): 292 def ancestor(repo, subset, x):
293 """A greatest common ancestor of the changesets. 293 """A greatest common ancestor of the changesets.
294 294
295 Accepts 0 or more changesets. 295 Accepts 0 or more changesets.
296 Will return empty list when passed no args. 296 Will return empty list when passed no args.
392 except error.WdirUnsupported: 392 except error.WdirUnsupported:
393 r = repo[r].parents()[0].rev() 393 r = repo[r].parents()[0].rev()
394 ps.add(r) 394 ps.add(r)
395 return subset & ps 395 return subset & ps
396 396
397 @predicate('author(string)', safe=True) 397 @predicate('author(string)', safe=True, weight=10)
398 def author(repo, subset, x): 398 def author(repo, subset, x):
399 """Alias for ``user(string)``. 399 """Alias for ``user(string)``.
400 """ 400 """
401 # i18n: "author" is a keyword 401 # i18n: "author" is a keyword
402 n = getstring(x, _("author requires a string")) 402 n = getstring(x, _("author requires a string"))
460 else: 460 else:
461 bms = {repo[r].rev() for r in repo._bookmarks.values()} 461 bms = {repo[r].rev() for r in repo._bookmarks.values()}
462 bms -= {node.nullrev} 462 bms -= {node.nullrev}
463 return subset & bms 463 return subset & bms
464 464
465 @predicate('branch(string or set)', safe=True) 465 @predicate('branch(string or set)', safe=True, weight=10)
466 def branch(repo, subset, x): 466 def branch(repo, subset, x):
467 """ 467 """
468 All changesets belonging to the given branch or the branches of the given 468 All changesets belonging to the given branch or the branches of the given
469 changesets. 469 changesets.
470 470
593 """ 593 """
594 s = getset(repo, fullreposet(repo), x) 594 s = getset(repo, fullreposet(repo), x)
595 cs = _children(repo, subset, s) 595 cs = _children(repo, subset, s)
596 return subset & cs 596 return subset & cs
597 597
598 @predicate('closed()', safe=True) 598 @predicate('closed()', safe=True, weight=10)
599 def closed(repo, subset, x): 599 def closed(repo, subset, x):
600 """Changeset is closed. 600 """Changeset is closed.
601 """ 601 """
602 # i18n: "closed" is a keyword 602 # i18n: "closed" is a keyword
603 getargs(x, 0, 0, _("closed takes no arguments")) 603 getargs(x, 0, 0, _("closed takes no arguments"))
604 return subset.filter(lambda r: repo[r].closesbranch(), 604 return subset.filter(lambda r: repo[r].closesbranch(),
605 condrepr='<branch closed>') 605 condrepr='<branch closed>')
606 606
607 @predicate('contains(pattern)') 607 @predicate('contains(pattern)', weight=100)
608 def contains(repo, subset, x): 608 def contains(repo, subset, x):
609 """The revision's manifest contains a file matching pattern (but might not 609 """The revision's manifest contains a file matching pattern (but might not
610 modify it). See :hg:`help patterns` for information about file patterns. 610 modify it). See :hg:`help patterns` for information about file patterns.
611 611
612 The pattern without explicit kind like ``glob:`` is expected to be 612 The pattern without explicit kind like ``glob:`` is expected to be
652 return source is not None and (rev is None or source.startswith(rev)) 652 return source is not None and (rev is None or source.startswith(rev))
653 653
654 return subset.filter(lambda r: _matchvalue(r), 654 return subset.filter(lambda r: _matchvalue(r),
655 condrepr=('<converted %r>', rev)) 655 condrepr=('<converted %r>', rev))
656 656
657 @predicate('date(interval)', safe=True) 657 @predicate('date(interval)', safe=True, weight=10)
658 def date(repo, subset, x): 658 def date(repo, subset, x):
659 """Changesets within the interval, see :hg:`help dates`. 659 """Changesets within the interval, see :hg:`help dates`.
660 """ 660 """
661 # i18n: "date" is a keyword 661 # i18n: "date" is a keyword
662 ds = getstring(x, _("date requires a string")) 662 ds = getstring(x, _("date requires a string"))
663 dm = util.matchdate(ds) 663 dm = util.matchdate(ds)
664 return subset.filter(lambda x: dm(repo[x].date()[0]), 664 return subset.filter(lambda x: dm(repo[x].date()[0]),
665 condrepr=('<date %r>', ds)) 665 condrepr=('<date %r>', ds))
666 666
667 @predicate('desc(string)', safe=True) 667 @predicate('desc(string)', safe=True, weight=10)
668 def desc(repo, subset, x): 668 def desc(repo, subset, x):
669 """Search commit message for string. The match is case-insensitive. 669 """Search commit message for string. The match is case-insensitive.
670 670
671 Pattern matching is supported for `string`. See 671 Pattern matching is supported for `string`. See
672 :hg:`help revisions.patterns`. 672 :hg:`help revisions.patterns`.
720 def _firstdescendants(repo, subset, x): 720 def _firstdescendants(repo, subset, x):
721 # ``_firstdescendants(set)`` 721 # ``_firstdescendants(set)``
722 # Like ``descendants(set)`` but follows only the first parents. 722 # Like ``descendants(set)`` but follows only the first parents.
723 return _descendants(repo, subset, x, followfirst=True) 723 return _descendants(repo, subset, x, followfirst=True)
724 724
725 @predicate('destination([set])', safe=True) 725 @predicate('destination([set])', safe=True, weight=10)
726 def destination(repo, subset, x): 726 def destination(repo, subset, x):
727 """Changesets that were created by a graft, transplant or rebase operation, 727 """Changesets that were created by a graft, transplant or rebase operation,
728 with the given revisions specified as the source. Omitting the optional set 728 with the given revisions specified as the source. Omitting the optional set
729 is the same as passing all(). 729 is the same as passing all().
730 """ 730 """
889 # deletion in changelog 889 # deletion in changelog
890 continue 890 continue
891 891
892 return subset & s 892 return subset & s
893 893
894 @predicate('first(set, [n])', safe=True, takeorder=True) 894 @predicate('first(set, [n])', safe=True, takeorder=True, weight=0)
895 def first(repo, subset, x, order): 895 def first(repo, subset, x, order):
896 """An alias for limit(). 896 """An alias for limit().
897 """ 897 """
898 return limit(repo, subset, x, order) 898 return limit(repo, subset, x, order)
899 899
1010 """ 1010 """
1011 # i18n: "all" is a keyword 1011 # i18n: "all" is a keyword
1012 getargs(x, 0, 0, _("all takes no arguments")) 1012 getargs(x, 0, 0, _("all takes no arguments"))
1013 return subset & spanset(repo) # drop "null" if any 1013 return subset & spanset(repo) # drop "null" if any
1014 1014
1015 @predicate('grep(regex)') 1015 @predicate('grep(regex)', weight=10)
1016 def grep(repo, subset, x): 1016 def grep(repo, subset, x):
1017 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')`` 1017 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1018 to ensure special escape characters are handled correctly. Unlike 1018 to ensure special escape characters are handled correctly. Unlike
1019 ``keyword(string)``, the match is case-sensitive. 1019 ``keyword(string)``, the match is case-sensitive.
1020 """ 1020 """
1095 return subset.filter(matches, 1095 return subset.filter(matches,
1096 condrepr=('<matchfiles patterns=%r, include=%r ' 1096 condrepr=('<matchfiles patterns=%r, include=%r '
1097 'exclude=%r, default=%r, rev=%r>', 1097 'exclude=%r, default=%r, rev=%r>',
1098 pats, inc, exc, default, rev)) 1098 pats, inc, exc, default, rev))
1099 1099
1100 @predicate('file(pattern)', safe=True) 1100 @predicate('file(pattern)', safe=True, weight=10)
1101 def hasfile(repo, subset, x): 1101 def hasfile(repo, subset, x):
1102 """Changesets affecting files matched by pattern. 1102 """Changesets affecting files matched by pattern.
1103 1103
1104 For a faster but less accurate result, consider using ``filelog()`` 1104 For a faster but less accurate result, consider using ``filelog()``
1105 instead. 1105 instead.
1137 # i18n: "hidden" is a keyword 1137 # i18n: "hidden" is a keyword
1138 getargs(x, 0, 0, _("hidden takes no arguments")) 1138 getargs(x, 0, 0, _("hidden takes no arguments"))
1139 hiddenrevs = repoview.filterrevs(repo, 'visible') 1139 hiddenrevs = repoview.filterrevs(repo, 'visible')
1140 return subset & hiddenrevs 1140 return subset & hiddenrevs
1141 1141
1142 @predicate('keyword(string)', safe=True) 1142 @predicate('keyword(string)', safe=True, weight=10)
1143 def keyword(repo, subset, x): 1143 def keyword(repo, subset, x):
1144 """Search commit message, user name, and names of changed files for 1144 """Search commit message, user name, and names of changed files for
1145 string. The match is case-insensitive. 1145 string. The match is case-insensitive.
1146 1146
1147 For a regular expression or case sensitive search of these fields, use 1147 For a regular expression or case sensitive search of these fields, use
1155 return any(kw in encoding.lower(t) 1155 return any(kw in encoding.lower(t)
1156 for t in c.files() + [c.user(), c.description()]) 1156 for t in c.files() + [c.user(), c.description()])
1157 1157
1158 return subset.filter(matches, condrepr=('<keyword %r>', kw)) 1158 return subset.filter(matches, condrepr=('<keyword %r>', kw))
1159 1159
1160 @predicate('limit(set[, n[, offset]])', safe=True, takeorder=True) 1160 @predicate('limit(set[, n[, offset]])', safe=True, takeorder=True, weight=0)
1161 def limit(repo, subset, x, order): 1161 def limit(repo, subset, x, order):
1162 """First n members of set, defaulting to 1, starting from offset. 1162 """First n members of set, defaulting to 1, starting from offset.
1163 """ 1163 """
1164 args = getargsdict(x, 'limit', 'set n offset') 1164 args = getargsdict(x, 'limit', 'set n offset')
1165 if 'set' not in args: 1165 if 'set' not in args:
1257 # os.min() throws a ValueError when the collection is empty. 1257 # os.min() throws a ValueError when the collection is empty.
1258 # Same as python's min(). 1258 # Same as python's min().
1259 pass 1259 pass
1260 return baseset(datarepr=('<min %r, %r>', subset, os)) 1260 return baseset(datarepr=('<min %r, %r>', subset, os))
1261 1261
1262 @predicate('modifies(pattern)', safe=True) 1262 @predicate('modifies(pattern)', safe=True, weight=30)
1263 def modifies(repo, subset, x): 1263 def modifies(repo, subset, x):
1264 """Changesets modifying files matched by pattern. 1264 """Changesets modifying files matched by pattern.
1265 1265
1266 The pattern without explicit kind like ``glob:`` is expected to be 1266 The pattern without explicit kind like ``glob:`` is expected to be
1267 relative to the current directory and match against a file or a 1267 relative to the current directory and match against a file or a
1401 o -= {None} 1401 o -= {None}
1402 # XXX we should turn this into a baseset instead of a set, smartset may do 1402 # XXX we should turn this into a baseset instead of a set, smartset may do
1403 # some optimizations from the fact this is a baseset. 1403 # some optimizations from the fact this is a baseset.
1404 return subset & o 1404 return subset & o
1405 1405
1406 @predicate('outgoing([path])', safe=False) 1406 @predicate('outgoing([path])', safe=False, weight=10)
1407 def outgoing(repo, subset, x): 1407 def outgoing(repo, subset, x):
1408 """Changesets not found in the specified destination repository, or the 1408 """Changesets not found in the specified destination repository, or the
1409 default push location. 1409 default push location.
1410 """ 1410 """
1411 # Avoid cycles. 1411 # Avoid cycles.
1652 r = repo[n].rev() 1652 r = repo[n].rev()
1653 if r in subset: 1653 if r in subset:
1654 return baseset([r]) 1654 return baseset([r])
1655 return baseset() 1655 return baseset()
1656 1656
1657 @predicate('removes(pattern)', safe=True) 1657 @predicate('removes(pattern)', safe=True, weight=30)
1658 def removes(repo, subset, x): 1658 def removes(repo, subset, x):
1659 """Changesets which remove files matching pattern. 1659 """Changesets which remove files matching pattern.
1660 1660
1661 The pattern without explicit kind like ``glob:`` is expected to be 1661 The pattern without explicit kind like ``glob:`` is expected to be
1662 relative to the current directory and match against a file or a 1662 relative to the current directory and match against a file or a
1792 return True 1792 return True
1793 return False 1793 return False
1794 1794
1795 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs)) 1795 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs))
1796 1796
1797 @predicate('reverse(set)', safe=True, takeorder=True) 1797 @predicate('reverse(set)', safe=True, takeorder=True, weight=0)
1798 def reverse(repo, subset, x, order): 1798 def reverse(repo, subset, x, order):
1799 """Reverse order of set. 1799 """Reverse order of set.
1800 """ 1800 """
1801 l = getset(repo, subset, x, order) 1801 l = getset(repo, subset, x, order)
1802 if order == defineorder: 1802 if order == defineorder:
1860 raise error.ParseError(_('topo.firstbranch can only be used ' 1860 raise error.ParseError(_('topo.firstbranch can only be used '
1861 'when using the topo sort key')) 1861 'when using the topo sort key'))
1862 1862
1863 return args['set'], keyflags, opts 1863 return args['set'], keyflags, opts
1864 1864
1865 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True) 1865 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True,
1866 weight=10)
1866 def sort(repo, subset, x, order): 1867 def sort(repo, subset, x, order):
1867 """Sort set by keys. The default sort order is ascending, specify a key 1868 """Sort set by keys. The default sort order is ascending, specify a key
1868 as ``-key`` to sort in descending order. 1869 as ``-key`` to sort in descending order.
1869 1870
1870 The keys can be: 1871 The keys can be:
2031 getargs(x, 0, 0, _("orphan takes no arguments")) 2032 getargs(x, 0, 0, _("orphan takes no arguments"))
2032 orphan = obsmod.getrevs(repo, 'orphan') 2033 orphan = obsmod.getrevs(repo, 'orphan')
2033 return subset & orphan 2034 return subset & orphan
2034 2035
2035 2036
2036 @predicate('user(string)', safe=True) 2037 @predicate('user(string)', safe=True, weight=10)
2037 def user(repo, subset, x): 2038 def user(repo, subset, x):
2038 """User name contains string. The match is case-insensitive. 2039 """User name contains string. The match is case-insensitive.
2039 2040
2040 Pattern matching is supported for `string`. See 2041 Pattern matching is supported for `string`. See
2041 :hg:`help revisions.patterns`. 2042 :hg:`help revisions.patterns`.
2042 """ 2043 """
2043 return author(repo, subset, x) 2044 return author(repo, subset, x)
2044 2045
2045 @predicate('wdir()', safe=True) 2046 @predicate('wdir()', safe=True, weight=0)
2046 def wdir(repo, subset, x): 2047 def wdir(repo, subset, x):
2047 """Working directory. (EXPERIMENTAL)""" 2048 """Working directory. (EXPERIMENTAL)"""
2048 # i18n: "wdir" is a keyword 2049 # i18n: "wdir" is a keyword
2049 getargs(x, 0, 0, _("wdir takes no arguments")) 2050 getargs(x, 0, 0, _("wdir takes no arguments"))
2050 if node.wdirrev in subset or isinstance(subset, fullreposet): 2051 if node.wdirrev in subset or isinstance(subset, fullreposet):
2095 ls = [int(r) for r in s.split('\0')] 2096 ls = [int(r) for r in s.split('\0')]
2096 s = subset 2097 s = subset
2097 return baseset([r for r in ls if r in s]) 2098 return baseset([r for r in ls if r in s])
2098 2099
2099 # for internal use 2100 # for internal use
2100 @predicate('_intlist', safe=True, takeorder=True) 2101 @predicate('_intlist', safe=True, takeorder=True, weight=0)
2101 def _intlist(repo, subset, x, order): 2102 def _intlist(repo, subset, x, order):
2102 if order == followorder: 2103 if order == followorder:
2103 # slow path to take the subset order 2104 # slow path to take the subset order
2104 return subset & _orderedintlist(repo, fullreposet(repo), x) 2105 return subset & _orderedintlist(repo, fullreposet(repo), x)
2105 else: 2106 else: