Mercurial > public > mercurial-scm > hg-stable
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: |