Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/revset.py @ 34029:1b28525e6698
revset: remove order information from tree (API)
Keeping `order` in tree makes AST operation harder. And there could be
invalid cases if trees could be generated and compounded freely, like:
SetA(order=define) & SetB(order=define)
^^^^^^ couldn't be satisfied
This patch changes the code to calculate order on the fly, during tree
traversal. Optimization of reordering `and` arguments is preserved by
introducing a new internal operation `flipand`.
.. api::
revset.stringset() now takes 'order' as the last argument.
Differential Revision: https://phab.mercurial-scm.org/D451
author | Jun Wu <quark@fb.com> |
---|---|
date | Sun, 20 Aug 2017 10:55:11 -0700 |
parents | 457d1ebf151b |
children | 96f249dce03e |
comparison
equal
deleted
inserted
replaced
34028:72b5f4d53c58 | 34029:1b28525e6698 |
---|---|
50 spanset = smartset.spanset | 50 spanset = smartset.spanset |
51 fullreposet = smartset.fullreposet | 51 fullreposet = smartset.fullreposet |
52 | 52 |
53 # helpers | 53 # helpers |
54 | 54 |
55 def getset(repo, subset, x): | 55 def getset(repo, subset, x, order=defineorder): |
56 if not x: | 56 if not x: |
57 raise error.ParseError(_("missing argument")) | 57 raise error.ParseError(_("missing argument")) |
58 return methods[x[0]](repo, subset, *x[1:]) | 58 return methods[x[0]](repo, subset, *x[1:], order=order) |
59 | 59 |
60 def _getrevsource(repo, r): | 60 def _getrevsource(repo, r): |
61 extra = repo[r].extra() | 61 extra = repo[r].extra() |
62 for label in ('source', 'transplant_source', 'rebase_source'): | 62 for label in ('source', 'transplant_source', 'rebase_source'): |
63 if label in extra: | 63 if label in extra: |
67 pass | 67 pass |
68 return None | 68 return None |
69 | 69 |
70 # operator methods | 70 # operator methods |
71 | 71 |
72 def stringset(repo, subset, x): | 72 def stringset(repo, subset, x, order): |
73 x = scmutil.intrev(repo[x]) | 73 x = scmutil.intrev(repo[x]) |
74 if (x in subset | 74 if (x in subset |
75 or x == node.nullrev and isinstance(subset, fullreposet)): | 75 or x == node.nullrev and isinstance(subset, fullreposet)): |
76 return baseset([x]) | 76 return baseset([x]) |
77 return baseset() | 77 return baseset() |
124 xs = dagop.reachableroots(repo, getset(repo, r, x), getset(repo, r, y), | 124 xs = dagop.reachableroots(repo, getset(repo, r, x), getset(repo, r, y), |
125 includepath=True) | 125 includepath=True) |
126 return subset & xs | 126 return subset & xs |
127 | 127 |
128 def andset(repo, subset, x, y, order): | 128 def andset(repo, subset, x, y, order): |
129 return getset(repo, getset(repo, subset, x), y) | 129 if order == anyorder: |
130 yorder = anyorder | |
131 else: | |
132 yorder = followorder | |
133 return getset(repo, getset(repo, subset, x, order), y, yorder) | |
134 | |
135 def flipandset(repo, subset, y, x, order): | |
136 # 'flipand(y, x)' is equivalent to 'and(x, y)', but faster when y is small | |
137 if order == anyorder: | |
138 yorder = anyorder | |
139 else: | |
140 yorder = followorder | |
141 return getset(repo, getset(repo, subset, y, yorder), x, order) | |
130 | 142 |
131 def differenceset(repo, subset, x, y, order): | 143 def differenceset(repo, subset, x, y, order): |
132 return getset(repo, subset, x) - getset(repo, subset, y) | 144 return getset(repo, subset, x, order) - getset(repo, subset, y, anyorder) |
133 | 145 |
134 def _orsetlist(repo, subset, xs): | 146 def _orsetlist(repo, subset, xs, order): |
135 assert xs | 147 assert xs |
136 if len(xs) == 1: | 148 if len(xs) == 1: |
137 return getset(repo, subset, xs[0]) | 149 return getset(repo, subset, xs[0], order) |
138 p = len(xs) // 2 | 150 p = len(xs) // 2 |
139 a = _orsetlist(repo, subset, xs[:p]) | 151 a = _orsetlist(repo, subset, xs[:p], order) |
140 b = _orsetlist(repo, subset, xs[p:]) | 152 b = _orsetlist(repo, subset, xs[p:], order) |
141 return a + b | 153 return a + b |
142 | 154 |
143 def orset(repo, subset, x, order): | 155 def orset(repo, subset, x, order): |
144 xs = getlist(x) | 156 xs = getlist(x) |
145 if order == followorder: | 157 if order == followorder: |
146 # slow path to take the subset order | 158 # slow path to take the subset order |
147 return subset & _orsetlist(repo, fullreposet(repo), xs) | 159 return subset & _orsetlist(repo, fullreposet(repo), xs, anyorder) |
148 else: | 160 else: |
149 return _orsetlist(repo, subset, xs) | 161 return _orsetlist(repo, subset, xs, order) |
150 | 162 |
151 def notset(repo, subset, x, order): | 163 def notset(repo, subset, x, order): |
152 return subset - getset(repo, subset, x) | 164 return subset - getset(repo, subset, x, anyorder) |
153 | 165 |
154 def relationset(repo, subset, x, y, order): | 166 def relationset(repo, subset, x, y, order): |
155 raise error.ParseError(_("can't use a relation in this context")) | 167 raise error.ParseError(_("can't use a relation in this context")) |
156 | 168 |
157 def relsubscriptset(repo, subset, x, y, z, order): | 169 def relsubscriptset(repo, subset, x, y, z, order): |
174 raise error.UnknownIdentifier(rel, ['generations']) | 186 raise error.UnknownIdentifier(rel, ['generations']) |
175 | 187 |
176 def subscriptset(repo, subset, x, y, order): | 188 def subscriptset(repo, subset, x, y, order): |
177 raise error.ParseError(_("can't use a subscript in this context")) | 189 raise error.ParseError(_("can't use a subscript in this context")) |
178 | 190 |
179 def listset(repo, subset, *xs): | 191 def listset(repo, subset, *xs, **opts): |
180 raise error.ParseError(_("can't use a list in this context"), | 192 raise error.ParseError(_("can't use a list in this context"), |
181 hint=_('see hg help "revsets.x or y"')) | 193 hint=_('see hg help "revsets.x or y"')) |
182 | 194 |
183 def keyvaluepair(repo, subset, k, v): | 195 def keyvaluepair(repo, subset, k, v, order): |
184 raise error.ParseError(_("can't use a key-value pair in this context")) | 196 raise error.ParseError(_("can't use a key-value pair in this context")) |
185 | 197 |
186 def func(repo, subset, a, b, order): | 198 def func(repo, subset, a, b, order): |
187 f = getsymbol(a) | 199 f = getsymbol(a) |
188 if f in symbols: | 200 if f in symbols: |
1506 parents = repo[r].parents() | 1518 parents = repo[r].parents() |
1507 if len(parents) == 2: | 1519 if len(parents) == 2: |
1508 ps.add(parents[1].rev()) | 1520 ps.add(parents[1].rev()) |
1509 return subset & ps | 1521 return subset & ps |
1510 | 1522 |
1511 @predicate('present(set)', safe=True) | 1523 @predicate('present(set)', safe=True, takeorder=True) |
1512 def present(repo, subset, x): | 1524 def present(repo, subset, x, order): |
1513 """An empty set, if any revision in set isn't found; otherwise, | 1525 """An empty set, if any revision in set isn't found; otherwise, |
1514 all revisions in set. | 1526 all revisions in set. |
1515 | 1527 |
1516 If any of specified revisions is not present in the local repository, | 1528 If any of specified revisions is not present in the local repository, |
1517 the query is normally aborted. But this predicate allows the query | 1529 the query is normally aborted. But this predicate allows the query |
1518 to continue even in such cases. | 1530 to continue even in such cases. |
1519 """ | 1531 """ |
1520 try: | 1532 try: |
1521 return getset(repo, subset, x) | 1533 return getset(repo, subset, x, order) |
1522 except error.RepoLookupError: | 1534 except error.RepoLookupError: |
1523 return baseset() | 1535 return baseset() |
1524 | 1536 |
1525 # for internal use | 1537 # for internal use |
1526 @predicate('_notpublic', safe=True) | 1538 @predicate('_notpublic', safe=True) |
1716 | 1728 |
1717 @predicate('reverse(set)', safe=True, takeorder=True) | 1729 @predicate('reverse(set)', safe=True, takeorder=True) |
1718 def reverse(repo, subset, x, order): | 1730 def reverse(repo, subset, x, order): |
1719 """Reverse order of set. | 1731 """Reverse order of set. |
1720 """ | 1732 """ |
1721 l = getset(repo, subset, x) | 1733 l = getset(repo, subset, x, order) |
1722 if order == defineorder: | 1734 if order == defineorder: |
1723 l.reverse() | 1735 l.reverse() |
1724 return l | 1736 return l |
1725 | 1737 |
1726 @predicate('roots(set)', safe=True) | 1738 @predicate('roots(set)', safe=True) |
1800 takes one optional argument, ``topo.firstbranch``, which takes a revset that | 1812 takes one optional argument, ``topo.firstbranch``, which takes a revset that |
1801 specifies what topographical branches to prioritize in the sort. | 1813 specifies what topographical branches to prioritize in the sort. |
1802 | 1814 |
1803 """ | 1815 """ |
1804 s, keyflags, opts = _getsortargs(x) | 1816 s, keyflags, opts = _getsortargs(x) |
1805 revs = getset(repo, subset, s) | 1817 revs = getset(repo, subset, s, order) |
1806 | 1818 |
1807 if not keyflags or order != defineorder: | 1819 if not keyflags or order != defineorder: |
1808 return revs | 1820 return revs |
1809 if len(keyflags) == 1 and keyflags[0][0] == "rev": | 1821 if len(keyflags) == 1 and keyflags[0][0] == "rev": |
1810 revs.sort(reverse=keyflags[0][1]) | 1822 revs.sort(reverse=keyflags[0][1]) |
1986 r = int(t) | 1998 r = int(t) |
1987 if str(r) != t or r not in cl: | 1999 if str(r) != t or r not in cl: |
1988 raise ValueError | 2000 raise ValueError |
1989 revs = [r] | 2001 revs = [r] |
1990 except ValueError: | 2002 except ValueError: |
1991 revs = stringset(repo, subset, t) | 2003 revs = stringset(repo, subset, t, defineorder) |
1992 | 2004 |
1993 for r in revs: | 2005 for r in revs: |
1994 if r in seen: | 2006 if r in seen: |
1995 continue | 2007 continue |
1996 if (r in subset | 2008 if (r in subset |
2050 "rangepost": rangepost, | 2062 "rangepost": rangepost, |
2051 "dagrange": dagrange, | 2063 "dagrange": dagrange, |
2052 "string": stringset, | 2064 "string": stringset, |
2053 "symbol": stringset, | 2065 "symbol": stringset, |
2054 "and": andset, | 2066 "and": andset, |
2067 "flipand": flipandset, | |
2055 "or": orset, | 2068 "or": orset, |
2056 "not": notset, | 2069 "not": notset, |
2057 "difference": differenceset, | 2070 "difference": differenceset, |
2058 "relation": relationset, | 2071 "relation": relationset, |
2059 "relsubscript": relsubscriptset, | 2072 "relsubscript": relsubscriptset, |
2111 if localalias: | 2124 if localalias: |
2112 aliases.extend(localalias.items()) | 2125 aliases.extend(localalias.items()) |
2113 if aliases: | 2126 if aliases: |
2114 tree = revsetlang.expandaliases(tree, aliases, warn=warn) | 2127 tree = revsetlang.expandaliases(tree, aliases, warn=warn) |
2115 tree = revsetlang.foldconcat(tree) | 2128 tree = revsetlang.foldconcat(tree) |
2116 tree = revsetlang.analyze(tree, order) | 2129 tree = revsetlang.analyze(tree) |
2117 tree = revsetlang.optimize(tree) | 2130 tree = revsetlang.optimize(tree) |
2118 posttreebuilthook(tree, repo) | 2131 posttreebuilthook(tree, repo) |
2119 return makematcher(tree) | 2132 return makematcher(tree, order) |
2120 | 2133 |
2121 def makematcher(tree): | 2134 def makematcher(tree, order=defineorder): |
2122 """Create a matcher from an evaluatable tree""" | 2135 """Create a matcher from an evaluatable tree""" |
2123 def mfunc(repo, subset=None): | 2136 def mfunc(repo, subset=None): |
2124 if subset is None: | 2137 if subset is None: |
2125 subset = fullreposet(repo) | 2138 subset = fullreposet(repo) |
2126 return getset(repo, subset, tree) | 2139 return getset(repo, subset, tree, order) |
2127 return mfunc | 2140 return mfunc |
2128 | 2141 |
2129 def loadpredicate(ui, extname, registrarobj): | 2142 def loadpredicate(ui, extname, registrarobj): |
2130 """Load revset predicates from specified registrarobj | 2143 """Load revset predicates from specified registrarobj |
2131 """ | 2144 """ |