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 """