comparison mercurial/revset.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents 911e25dc9d8c
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
91 # ^^^^^^ 91 # ^^^^^^
92 # For most revsets, 'define' means using the order this subset provides 92 # For most revsets, 'define' means using the order this subset provides
93 # 93 #
94 # There are a few revsets that always redefine the order if 'define' is 94 # There are a few revsets that always redefine the order if 'define' is
95 # specified: 'sort(X)', 'reverse(X)', 'x:y'. 95 # specified: 'sort(X)', 'reverse(X)', 'x:y'.
96 anyorder = 'any' # don't care the order, could be even random-shuffled 96 anyorder = 'any' # don't care the order, could be even random-shuffled
97 defineorder = 'define' # ALWAYS redefine, or ALWAYS follow the current order 97 defineorder = 'define' # ALWAYS redefine, or ALWAYS follow the current order
98 followorder = 'follow' # MUST follow the current order 98 followorder = 'follow' # MUST follow the current order
99 99
100 # helpers 100 # helpers
101
101 102
102 def getset(repo, subset, x, order=defineorder): 103 def getset(repo, subset, x, order=defineorder):
103 if not x: 104 if not x:
104 raise error.ParseError(_("missing argument")) 105 raise error.ParseError(_("missing argument"))
105 return methods[x[0]](repo, subset, *x[1:], order=order) 106 return methods[x[0]](repo, subset, *x[1:], order=order)
107
106 108
107 def _getrevsource(repo, r): 109 def _getrevsource(repo, r):
108 extra = repo[r].extra() 110 extra = repo[r].extra()
109 for label in ('source', 'transplant_source', 'rebase_source'): 111 for label in ('source', 'transplant_source', 'rebase_source'):
110 if label in extra: 112 if label in extra:
112 return repo[extra[label]].rev() 114 return repo[extra[label]].rev()
113 except error.RepoLookupError: 115 except error.RepoLookupError:
114 pass 116 pass
115 return None 117 return None
116 118
119
117 def _sortedb(xs): 120 def _sortedb(xs):
118 return sorted(pycompat.rapply(pycompat.maybebytestr, xs)) 121 return sorted(pycompat.rapply(pycompat.maybebytestr, xs))
119 122
123
120 # operator methods 124 # operator methods
125
121 126
122 def stringset(repo, subset, x, order): 127 def stringset(repo, subset, x, order):
123 if not x: 128 if not x:
124 raise error.ParseError(_("empty string is not a valid revision")) 129 raise error.ParseError(_("empty string is not a valid revision"))
125 x = scmutil.intrev(scmutil.revsymbol(repo, x)) 130 x = scmutil.intrev(scmutil.revsymbol(repo, x))
126 if x in subset or x in _virtualrevs and isinstance(subset, fullreposet): 131 if x in subset or x in _virtualrevs and isinstance(subset, fullreposet):
127 return baseset([x]) 132 return baseset([x])
128 return baseset() 133 return baseset()
129 134
135
130 def rawsmartset(repo, subset, x, order): 136 def rawsmartset(repo, subset, x, order):
131 """argument is already a smartset, use that directly""" 137 """argument is already a smartset, use that directly"""
132 if order == followorder: 138 if order == followorder:
133 return subset & x 139 return subset & x
134 else: 140 else:
135 return x & subset 141 return x & subset
136 142
143
137 def rangeset(repo, subset, x, y, order): 144 def rangeset(repo, subset, x, y, order):
138 m = getset(repo, fullreposet(repo), x) 145 m = getset(repo, fullreposet(repo), x)
139 n = getset(repo, fullreposet(repo), y) 146 n = getset(repo, fullreposet(repo), y)
140 147
141 if not m or not n: 148 if not m or not n:
142 return baseset() 149 return baseset()
143 return _makerangeset(repo, subset, m.first(), n.last(), order) 150 return _makerangeset(repo, subset, m.first(), n.last(), order)
144 151
152
145 def rangeall(repo, subset, x, order): 153 def rangeall(repo, subset, x, order):
146 assert x is None 154 assert x is None
147 return _makerangeset(repo, subset, 0, repo.changelog.tiprev(), order) 155 return _makerangeset(repo, subset, 0, repo.changelog.tiprev(), order)
156
148 157
149 def rangepre(repo, subset, y, order): 158 def rangepre(repo, subset, y, order):
150 # ':y' can't be rewritten to '0:y' since '0' may be hidden 159 # ':y' can't be rewritten to '0:y' since '0' may be hidden
151 n = getset(repo, fullreposet(repo), y) 160 n = getset(repo, fullreposet(repo), y)
152 if not n: 161 if not n:
153 return baseset() 162 return baseset()
154 return _makerangeset(repo, subset, 0, n.last(), order) 163 return _makerangeset(repo, subset, 0, n.last(), order)
155 164
165
156 def rangepost(repo, subset, x, order): 166 def rangepost(repo, subset, x, order):
157 m = getset(repo, fullreposet(repo), x) 167 m = getset(repo, fullreposet(repo), x)
158 if not m: 168 if not m:
159 return baseset() 169 return baseset()
160 return _makerangeset(repo, subset, m.first(), repo.changelog.tiprev(), 170 return _makerangeset(
161 order) 171 repo, subset, m.first(), repo.changelog.tiprev(), order
172 )
173
162 174
163 def _makerangeset(repo, subset, m, n, order): 175 def _makerangeset(repo, subset, m, n, order):
164 if m == n: 176 if m == n:
165 r = baseset([m]) 177 r = baseset([m])
166 elif n == node.wdirrev: 178 elif n == node.wdirrev:
176 return r & subset 188 return r & subset
177 else: 189 else:
178 # carrying the sorting over when possible would be more efficient 190 # carrying the sorting over when possible would be more efficient
179 return subset & r 191 return subset & r
180 192
193
181 def dagrange(repo, subset, x, y, order): 194 def dagrange(repo, subset, x, y, order):
182 r = fullreposet(repo) 195 r = fullreposet(repo)
183 xs = dagop.reachableroots(repo, getset(repo, r, x), getset(repo, r, y), 196 xs = dagop.reachableroots(
184 includepath=True) 197 repo, getset(repo, r, x), getset(repo, r, y), includepath=True
198 )
185 return subset & xs 199 return subset & xs
200
186 201
187 def andset(repo, subset, x, y, order): 202 def andset(repo, subset, x, y, order):
188 if order == anyorder: 203 if order == anyorder:
189 yorder = anyorder 204 yorder = anyorder
190 else: 205 else:
191 yorder = followorder 206 yorder = followorder
192 return getset(repo, getset(repo, subset, x, order), y, yorder) 207 return getset(repo, getset(repo, subset, x, order), y, yorder)
208
193 209
194 def andsmallyset(repo, subset, x, y, order): 210 def andsmallyset(repo, subset, x, y, order):
195 # 'andsmally(x, y)' is equivalent to 'and(x, y)', but faster when y is small 211 # 'andsmally(x, y)' is equivalent to 'and(x, y)', but faster when y is small
196 if order == anyorder: 212 if order == anyorder:
197 yorder = anyorder 213 yorder = anyorder
198 else: 214 else:
199 yorder = followorder 215 yorder = followorder
200 return getset(repo, getset(repo, subset, y, yorder), x, order) 216 return getset(repo, getset(repo, subset, y, yorder), x, order)
201 217
218
202 def differenceset(repo, subset, x, y, order): 219 def differenceset(repo, subset, x, y, order):
203 return getset(repo, subset, x, order) - getset(repo, subset, y, anyorder) 220 return getset(repo, subset, x, order) - getset(repo, subset, y, anyorder)
221
204 222
205 def _orsetlist(repo, subset, xs, order): 223 def _orsetlist(repo, subset, xs, order):
206 assert xs 224 assert xs
207 if len(xs) == 1: 225 if len(xs) == 1:
208 return getset(repo, subset, xs[0], order) 226 return getset(repo, subset, xs[0], order)
209 p = len(xs) // 2 227 p = len(xs) // 2
210 a = _orsetlist(repo, subset, xs[:p], order) 228 a = _orsetlist(repo, subset, xs[:p], order)
211 b = _orsetlist(repo, subset, xs[p:], order) 229 b = _orsetlist(repo, subset, xs[p:], order)
212 return a + b 230 return a + b
231
213 232
214 def orset(repo, subset, x, order): 233 def orset(repo, subset, x, order):
215 xs = getlist(x) 234 xs = getlist(x)
216 if not xs: 235 if not xs:
217 return baseset() 236 return baseset()
219 # slow path to take the subset order 238 # slow path to take the subset order
220 return subset & _orsetlist(repo, fullreposet(repo), xs, anyorder) 239 return subset & _orsetlist(repo, fullreposet(repo), xs, anyorder)
221 else: 240 else:
222 return _orsetlist(repo, subset, xs, order) 241 return _orsetlist(repo, subset, xs, order)
223 242
243
224 def notset(repo, subset, x, order): 244 def notset(repo, subset, x, order):
225 return subset - getset(repo, subset, x, anyorder) 245 return subset - getset(repo, subset, x, anyorder)
226 246
247
227 def relationset(repo, subset, x, y, order): 248 def relationset(repo, subset, x, y, order):
228 raise error.ParseError(_("can't use a relation in this context")) 249 raise error.ParseError(_("can't use a relation in this context"))
250
229 251
230 def _splitrange(a, b): 252 def _splitrange(a, b):
231 """Split range with bounds a and b into two ranges at 0 and return two 253 """Split range with bounds a and b into two ranges at 0 and return two
232 tuples of numbers for use as startdepth and stopdepth arguments of 254 tuples of numbers for use as startdepth and stopdepth arguments of
233 revancestors and revdescendants. 255 revancestors and revdescendants.
255 ancdepths = (-min(b, 0), -a + 1) 277 ancdepths = (-min(b, 0), -a + 1)
256 if b > 0: 278 if b > 0:
257 descdepths = (max(a, 0), b + 1) 279 descdepths = (max(a, 0), b + 1)
258 return ancdepths, descdepths 280 return ancdepths, descdepths
259 281
282
260 def generationsrel(repo, subset, x, rel, z, order): 283 def generationsrel(repo, subset, x, rel, z, order):
261 # TODO: rewrite tests, and drop startdepth argument from ancestors() and 284 # TODO: rewrite tests, and drop startdepth argument from ancestors() and
262 # descendants() predicates 285 # descendants() predicates
263 a, b = getintrange(z, 286 a, b = getintrange(
264 _('relation subscript must be an integer or a range'), 287 z,
265 _('relation subscript bounds must be integers'), 288 _('relation subscript must be an integer or a range'),
266 deffirst=-(dagop.maxlogdepth - 1), 289 _('relation subscript bounds must be integers'),
267 deflast=+(dagop.maxlogdepth - 1)) 290 deffirst=-(dagop.maxlogdepth - 1),
291 deflast=+(dagop.maxlogdepth - 1),
292 )
268 (ancstart, ancstop), (descstart, descstop) = _splitrange(a, b) 293 (ancstart, ancstop), (descstart, descstop) = _splitrange(a, b)
269 294
270 if ancstart is None and descstart is None: 295 if ancstart is None and descstart is None:
271 return baseset() 296 return baseset()
272 297
282 elif descstart is not None: 307 elif descstart is not None:
283 s = dagop.revdescendants(repo, revs, False, descstart, descstop) 308 s = dagop.revdescendants(repo, revs, False, descstart, descstop)
284 309
285 return subset & s 310 return subset & s
286 311
312
287 def relsubscriptset(repo, subset, x, y, z, order): 313 def relsubscriptset(repo, subset, x, y, z, order):
288 # this is pretty basic implementation of 'x#y[z]' operator, still 314 # this is pretty basic implementation of 'x#y[z]' operator, still
289 # experimental so undocumented. see the wiki for further ideas. 315 # experimental so undocumented. see the wiki for further ideas.
290 # https://www.mercurial-scm.org/wiki/RevsetOperatorPlan 316 # https://www.mercurial-scm.org/wiki/RevsetOperatorPlan
291 rel = getsymbol(y) 317 rel = getsymbol(y)
293 return subscriptrelations[rel](repo, subset, x, rel, z, order) 319 return subscriptrelations[rel](repo, subset, x, rel, z, order)
294 320
295 relnames = [r for r in subscriptrelations.keys() if len(r) > 1] 321 relnames = [r for r in subscriptrelations.keys() if len(r) > 1]
296 raise error.UnknownIdentifier(rel, relnames) 322 raise error.UnknownIdentifier(rel, relnames)
297 323
324
298 def subscriptset(repo, subset, x, y, order): 325 def subscriptset(repo, subset, x, y, order):
299 raise error.ParseError(_("can't use a subscript in this context")) 326 raise error.ParseError(_("can't use a subscript in this context"))
300 327
328
301 def listset(repo, subset, *xs, **opts): 329 def listset(repo, subset, *xs, **opts):
302 raise error.ParseError(_("can't use a list in this context"), 330 raise error.ParseError(
303 hint=_('see \'hg help "revsets.x or y"\'')) 331 _("can't use a list in this context"),
332 hint=_('see \'hg help "revsets.x or y"\''),
333 )
334
304 335
305 def keyvaluepair(repo, subset, k, v, order): 336 def keyvaluepair(repo, subset, k, v, order):
306 raise error.ParseError(_("can't use a key-value pair in this context")) 337 raise error.ParseError(_("can't use a key-value pair in this context"))
338
307 339
308 def func(repo, subset, a, b, order): 340 def func(repo, subset, a, b, order):
309 f = getsymbol(a) 341 f = getsymbol(a)
310 if f in symbols: 342 if f in symbols:
311 func = symbols[f] 343 func = symbols[f]
316 keep = lambda fn: getattr(fn, '__doc__', None) is not None 348 keep = lambda fn: getattr(fn, '__doc__', None) is not None
317 349
318 syms = [s for (s, fn) in symbols.items() if keep(fn)] 350 syms = [s for (s, fn) in symbols.items() if keep(fn)]
319 raise error.UnknownIdentifier(f, syms) 351 raise error.UnknownIdentifier(f, syms)
320 352
353
321 # functions 354 # functions
322 355
323 # symbols are callables like: 356 # symbols are callables like:
324 # fn(repo, subset, x) 357 # fn(repo, subset, x)
325 # with: 358 # with:
333 # functions that just return a lot of changesets (like all) don't count here 366 # functions that just return a lot of changesets (like all) don't count here
334 safesymbols = set() 367 safesymbols = set()
335 368
336 predicate = registrar.revsetpredicate() 369 predicate = registrar.revsetpredicate()
337 370
371
338 @predicate('_destupdate') 372 @predicate('_destupdate')
339 def _destupdate(repo, subset, x): 373 def _destupdate(repo, subset, x):
340 # experimental revset for update destination 374 # experimental revset for update destination
341 args = getargsdict(x, 'limit', 'clean') 375 args = getargsdict(x, 'limit', 'clean')
342 return subset & baseset([destutil.destupdate(repo, 376 return subset & baseset(
343 **pycompat.strkwargs(args))[0]]) 377 [destutil.destupdate(repo, **pycompat.strkwargs(args))[0]]
378 )
379
344 380
345 @predicate('_destmerge') 381 @predicate('_destmerge')
346 def _destmerge(repo, subset, x): 382 def _destmerge(repo, subset, x):
347 # experimental revset for merge destination 383 # experimental revset for merge destination
348 sourceset = None 384 sourceset = None
349 if x is not None: 385 if x is not None:
350 sourceset = getset(repo, fullreposet(repo), x) 386 sourceset = getset(repo, fullreposet(repo), x)
351 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)]) 387 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)])
352 388
389
353 @predicate('adds(pattern)', safe=True, weight=30) 390 @predicate('adds(pattern)', safe=True, weight=30)
354 def adds(repo, subset, x): 391 def adds(repo, subset, x):
355 """Changesets that add a file matching pattern. 392 """Changesets that add a file matching pattern.
356 393
357 The pattern without explicit kind like ``glob:`` is expected to be 394 The pattern without explicit kind like ``glob:`` is expected to be
359 directory. 396 directory.
360 """ 397 """
361 # i18n: "adds" is a keyword 398 # i18n: "adds" is a keyword
362 pat = getstring(x, _("adds requires a pattern")) 399 pat = getstring(x, _("adds requires a pattern"))
363 return checkstatus(repo, subset, pat, 1) 400 return checkstatus(repo, subset, pat, 1)
401
364 402
365 @predicate('ancestor(*changeset)', safe=True, weight=0.5) 403 @predicate('ancestor(*changeset)', safe=True, weight=0.5)
366 def ancestor(repo, subset, x): 404 def ancestor(repo, subset, x):
367 """A greatest common ancestor of the changesets. 405 """A greatest common ancestor of the changesets.
368 406
381 r = scmutil.intrev(anc) 419 r = scmutil.intrev(anc)
382 if r in subset: 420 if r in subset:
383 return baseset([r]) 421 return baseset([r])
384 return baseset() 422 return baseset()
385 423
386 def _ancestors(repo, subset, x, followfirst=False, startdepth=None, 424
387 stopdepth=None): 425 def _ancestors(
426 repo, subset, x, followfirst=False, startdepth=None, stopdepth=None
427 ):
388 heads = getset(repo, fullreposet(repo), x) 428 heads = getset(repo, fullreposet(repo), x)
389 if not heads: 429 if not heads:
390 return baseset() 430 return baseset()
391 s = dagop.revancestors(repo, heads, followfirst, startdepth, stopdepth) 431 s = dagop.revancestors(repo, heads, followfirst, startdepth, stopdepth)
392 return subset & s 432 return subset & s
433
393 434
394 @predicate('ancestors(set[, depth])', safe=True) 435 @predicate('ancestors(set[, depth])', safe=True)
395 def ancestors(repo, subset, x): 436 def ancestors(repo, subset, x):
396 """Changesets that are ancestors of changesets in set, including the 437 """Changesets that are ancestors of changesets in set, including the
397 given changesets themselves. 438 given changesets themselves.
404 if 'set' not in args: 445 if 'set' not in args:
405 # i18n: "ancestors" is a keyword 446 # i18n: "ancestors" is a keyword
406 raise error.ParseError(_('ancestors takes at least 1 argument')) 447 raise error.ParseError(_('ancestors takes at least 1 argument'))
407 startdepth = stopdepth = None 448 startdepth = stopdepth = None
408 if 'startdepth' in args: 449 if 'startdepth' in args:
409 n = getinteger(args['startdepth'], 450 n = getinteger(
410 "ancestors expects an integer startdepth") 451 args['startdepth'], "ancestors expects an integer startdepth"
452 )
411 if n < 0: 453 if n < 0:
412 raise error.ParseError("negative startdepth") 454 raise error.ParseError("negative startdepth")
413 startdepth = n 455 startdepth = n
414 if 'depth' in args: 456 if 'depth' in args:
415 # i18n: "ancestors" is a keyword 457 # i18n: "ancestors" is a keyword
416 n = getinteger(args['depth'], _("ancestors expects an integer depth")) 458 n = getinteger(args['depth'], _("ancestors expects an integer depth"))
417 if n < 0: 459 if n < 0:
418 raise error.ParseError(_("negative depth")) 460 raise error.ParseError(_("negative depth"))
419 stopdepth = n + 1 461 stopdepth = n + 1
420 return _ancestors(repo, subset, args['set'], 462 return _ancestors(
421 startdepth=startdepth, stopdepth=stopdepth) 463 repo, subset, args['set'], startdepth=startdepth, stopdepth=stopdepth
464 )
465
422 466
423 @predicate('_firstancestors', safe=True) 467 @predicate('_firstancestors', safe=True)
424 def _firstancestors(repo, subset, x): 468 def _firstancestors(repo, subset, x):
425 # ``_firstancestors(set)`` 469 # ``_firstancestors(set)``
426 # Like ``ancestors(set)`` but follows only the first parents. 470 # Like ``ancestors(set)`` but follows only the first parents.
427 return _ancestors(repo, subset, x, followfirst=True) 471 return _ancestors(repo, subset, x, followfirst=True)
472
428 473
429 def _childrenspec(repo, subset, x, n, order): 474 def _childrenspec(repo, subset, x, n, order):
430 """Changesets that are the Nth child of a changeset 475 """Changesets that are the Nth child of a changeset
431 in set. 476 in set.
432 """ 477 """
436 c = repo[r].children() 481 c = repo[r].children()
437 if len(c) == 0: 482 if len(c) == 0:
438 break 483 break
439 if len(c) > 1: 484 if len(c) > 1:
440 raise error.RepoLookupError( 485 raise error.RepoLookupError(
441 _("revision in set has more than one child")) 486 _("revision in set has more than one child")
487 )
442 r = c[0].rev() 488 r = c[0].rev()
443 else: 489 else:
444 cs.add(r) 490 cs.add(r)
445 return subset & cs 491 return subset & cs
492
446 493
447 def ancestorspec(repo, subset, x, n, order): 494 def ancestorspec(repo, subset, x, n, order):
448 """``set~n`` 495 """``set~n``
449 Changesets that are the Nth ancestor (first parents only) of a changeset 496 Changesets that are the Nth ancestor (first parents only) of a changeset
450 in set. 497 in set.
462 except error.WdirUnsupported: 509 except error.WdirUnsupported:
463 r = repo[r].p1().rev() 510 r = repo[r].p1().rev()
464 ps.add(r) 511 ps.add(r)
465 return subset & ps 512 return subset & ps
466 513
514
467 @predicate('author(string)', safe=True, weight=10) 515 @predicate('author(string)', safe=True, weight=10)
468 def author(repo, subset, x): 516 def author(repo, subset, x):
469 """Alias for ``user(string)``. 517 """Alias for ``user(string)``.
470 """ 518 """
471 # i18n: "author" is a keyword 519 # i18n: "author" is a keyword
472 n = getstring(x, _("author requires a string")) 520 n = getstring(x, _("author requires a string"))
473 kind, pattern, matcher = _substringmatcher(n, casesensitive=False) 521 kind, pattern, matcher = _substringmatcher(n, casesensitive=False)
474 return subset.filter(lambda x: matcher(repo[x].user()), 522 return subset.filter(
475 condrepr=('<user %r>', n)) 523 lambda x: matcher(repo[x].user()), condrepr=('<user %r>', n)
524 )
525
476 526
477 @predicate('bisect(string)', safe=True) 527 @predicate('bisect(string)', safe=True)
478 def bisect(repo, subset, x): 528 def bisect(repo, subset, x):
479 """Changesets marked in the specified bisect status: 529 """Changesets marked in the specified bisect status:
480 530
489 # i18n: "bisect" is a keyword 539 # i18n: "bisect" is a keyword
490 status = getstring(x, _("bisect requires a string")).lower() 540 status = getstring(x, _("bisect requires a string")).lower()
491 state = set(hbisect.get(repo, status)) 541 state = set(hbisect.get(repo, status))
492 return subset & state 542 return subset & state
493 543
544
494 # Backward-compatibility 545 # Backward-compatibility
495 # - no help entry so that we do not advertise it any more 546 # - no help entry so that we do not advertise it any more
496 @predicate('bisected', safe=True) 547 @predicate('bisected', safe=True)
497 def bisected(repo, subset, x): 548 def bisected(repo, subset, x):
498 return bisect(repo, subset, x) 549 return bisect(repo, subset, x)
499 550
551
500 @predicate('bookmark([name])', safe=True) 552 @predicate('bookmark([name])', safe=True)
501 def bookmark(repo, subset, x): 553 def bookmark(repo, subset, x):
502 """The named bookmark or all bookmarks. 554 """The named bookmark or all bookmarks.
503 555
504 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`. 556 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`.
505 """ 557 """
506 # i18n: "bookmark" is a keyword 558 # i18n: "bookmark" is a keyword
507 args = getargs(x, 0, 1, _('bookmark takes one or no arguments')) 559 args = getargs(x, 0, 1, _('bookmark takes one or no arguments'))
508 if args: 560 if args:
509 bm = getstring(args[0], 561 bm = getstring(
510 # i18n: "bookmark" is a keyword 562 args[0],
511 _('the argument to bookmark must be a string')) 563 # i18n: "bookmark" is a keyword
564 _('the argument to bookmark must be a string'),
565 )
512 kind, pattern, matcher = stringutil.stringmatcher(bm) 566 kind, pattern, matcher = stringutil.stringmatcher(bm)
513 bms = set() 567 bms = set()
514 if kind == 'literal': 568 if kind == 'literal':
515 if bm == pattern: 569 if bm == pattern:
516 pattern = repo._bookmarks.expandname(pattern) 570 pattern = repo._bookmarks.expandname(pattern)
517 bmrev = repo._bookmarks.get(pattern, None) 571 bmrev = repo._bookmarks.get(pattern, None)
518 if not bmrev: 572 if not bmrev:
519 raise error.RepoLookupError(_("bookmark '%s' does not exist") 573 raise error.RepoLookupError(
520 % pattern) 574 _("bookmark '%s' does not exist") % pattern
575 )
521 bms.add(repo[bmrev].rev()) 576 bms.add(repo[bmrev].rev())
522 else: 577 else:
523 matchrevs = set() 578 matchrevs = set()
524 for name, bmrev in repo._bookmarks.iteritems(): 579 for name, bmrev in repo._bookmarks.iteritems():
525 if matcher(name): 580 if matcher(name):
529 else: 584 else:
530 bms = {repo[r].rev() for r in repo._bookmarks.values()} 585 bms = {repo[r].rev() for r in repo._bookmarks.values()}
531 bms -= {node.nullrev} 586 bms -= {node.nullrev}
532 return subset & bms 587 return subset & bms
533 588
589
534 @predicate('branch(string or set)', safe=True, weight=10) 590 @predicate('branch(string or set)', safe=True, weight=10)
535 def branch(repo, subset, x): 591 def branch(repo, subset, x):
536 """ 592 """
537 All changesets belonging to the given branch or the branches of the given 593 All changesets belonging to the given branch or the branches of the given
538 changesets. 594 changesets.
539 595
540 Pattern matching is supported for `string`. See 596 Pattern matching is supported for `string`. See
541 :hg:`help revisions.patterns`. 597 :hg:`help revisions.patterns`.
542 """ 598 """
543 getbi = repo.revbranchcache().branchinfo 599 getbi = repo.revbranchcache().branchinfo
600
544 def getbranch(r): 601 def getbranch(r):
545 try: 602 try:
546 return getbi(r)[0] 603 return getbi(r)[0]
547 except error.WdirUnsupported: 604 except error.WdirUnsupported:
548 return repo[r].branch() 605 return repo[r].branch()
556 kind, pattern, matcher = stringutil.stringmatcher(b) 613 kind, pattern, matcher = stringutil.stringmatcher(b)
557 if kind == 'literal': 614 if kind == 'literal':
558 # note: falls through to the revspec case if no branch with 615 # note: falls through to the revspec case if no branch with
559 # this name exists and pattern kind is not specified explicitly 616 # this name exists and pattern kind is not specified explicitly
560 if repo.branchmap().hasbranch(pattern): 617 if repo.branchmap().hasbranch(pattern):
561 return subset.filter(lambda r: matcher(getbranch(r)), 618 return subset.filter(
562 condrepr=('<branch %r>', b)) 619 lambda r: matcher(getbranch(r)), condrepr=('<branch %r>', b)
620 )
563 if b.startswith('literal:'): 621 if b.startswith('literal:'):
564 raise error.RepoLookupError(_("branch '%s' does not exist") 622 raise error.RepoLookupError(
565 % pattern) 623 _("branch '%s' does not exist") % pattern
624 )
566 else: 625 else:
567 return subset.filter(lambda r: matcher(getbranch(r)), 626 return subset.filter(
568 condrepr=('<branch %r>', b)) 627 lambda r: matcher(getbranch(r)), condrepr=('<branch %r>', b)
628 )
569 629
570 s = getset(repo, fullreposet(repo), x) 630 s = getset(repo, fullreposet(repo), x)
571 b = set() 631 b = set()
572 for r in s: 632 for r in s:
573 b.add(getbranch(r)) 633 b.add(getbranch(r))
574 c = s.__contains__ 634 c = s.__contains__
575 return subset.filter(lambda r: c(r) or getbranch(r) in b, 635 return subset.filter(
576 condrepr=lambda: '<branch %r>' % _sortedb(b)) 636 lambda r: c(r) or getbranch(r) in b,
637 condrepr=lambda: '<branch %r>' % _sortedb(b),
638 )
639
577 640
578 @predicate('phasedivergent()', safe=True) 641 @predicate('phasedivergent()', safe=True)
579 def phasedivergent(repo, subset, x): 642 def phasedivergent(repo, subset, x):
580 """Mutable changesets marked as successors of public changesets. 643 """Mutable changesets marked as successors of public changesets.
581 644
584 """ 647 """
585 # i18n: "phasedivergent" is a keyword 648 # i18n: "phasedivergent" is a keyword
586 getargs(x, 0, 0, _("phasedivergent takes no arguments")) 649 getargs(x, 0, 0, _("phasedivergent takes no arguments"))
587 phasedivergent = obsmod.getrevs(repo, 'phasedivergent') 650 phasedivergent = obsmod.getrevs(repo, 'phasedivergent')
588 return subset & phasedivergent 651 return subset & phasedivergent
652
589 653
590 @predicate('bundle()', safe=True) 654 @predicate('bundle()', safe=True)
591 def bundle(repo, subset, x): 655 def bundle(repo, subset, x):
592 """Changesets in the bundle. 656 """Changesets in the bundle.
593 657
596 try: 660 try:
597 bundlerevs = repo.changelog.bundlerevs 661 bundlerevs = repo.changelog.bundlerevs
598 except AttributeError: 662 except AttributeError:
599 raise error.Abort(_("no bundle provided - specify with -R")) 663 raise error.Abort(_("no bundle provided - specify with -R"))
600 return subset & bundlerevs 664 return subset & bundlerevs
665
601 666
602 def checkstatus(repo, subset, pat, field): 667 def checkstatus(repo, subset, pat, field):
603 """Helper for status-related revsets (adds, removes, modifies). 668 """Helper for status-related revsets (adds, removes, modifies).
604 The field parameter says which kind is desired: 669 The field parameter says which kind is desired:
605 0: modified 670 0: modified
607 2: removed 672 2: removed
608 """ 673 """
609 hasset = matchmod.patkind(pat) == 'set' 674 hasset = matchmod.patkind(pat) == 'set'
610 675
611 mcache = [None] 676 mcache = [None]
677
612 def matches(x): 678 def matches(x):
613 c = repo[x] 679 c = repo[x]
614 if not mcache[0] or hasset: 680 if not mcache[0] or hasset:
615 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c) 681 mcache[0] = matchmod.match(repo.root, repo.getcwd(), [pat], ctx=c)
616 m = mcache[0] 682 m = mcache[0]
635 if m(f): 701 if m(f):
636 return True 702 return True
637 703
638 return subset.filter(matches, condrepr=('<status[%r] %r>', field, pat)) 704 return subset.filter(matches, condrepr=('<status[%r] %r>', field, pat))
639 705
706
640 def _children(repo, subset, parentset): 707 def _children(repo, subset, parentset):
641 if not parentset: 708 if not parentset:
642 return baseset() 709 return baseset()
643 cs = set() 710 cs = set()
644 pr = repo.changelog.parentrevs 711 pr = repo.changelog.parentrevs
652 cs.add(r) 719 cs.add(r)
653 if p2 != nullrev and p2 in parentset: 720 if p2 != nullrev and p2 in parentset:
654 cs.add(r) 721 cs.add(r)
655 return baseset(cs) 722 return baseset(cs)
656 723
724
657 @predicate('children(set)', safe=True) 725 @predicate('children(set)', safe=True)
658 def children(repo, subset, x): 726 def children(repo, subset, x):
659 """Child changesets of changesets in set. 727 """Child changesets of changesets in set.
660 """ 728 """
661 s = getset(repo, fullreposet(repo), x) 729 s = getset(repo, fullreposet(repo), x)
662 cs = _children(repo, subset, s) 730 cs = _children(repo, subset, s)
663 return subset & cs 731 return subset & cs
664 732
733
665 @predicate('closed()', safe=True, weight=10) 734 @predicate('closed()', safe=True, weight=10)
666 def closed(repo, subset, x): 735 def closed(repo, subset, x):
667 """Changeset is closed. 736 """Changeset is closed.
668 """ 737 """
669 # i18n: "closed" is a keyword 738 # i18n: "closed" is a keyword
670 getargs(x, 0, 0, _("closed takes no arguments")) 739 getargs(x, 0, 0, _("closed takes no arguments"))
671 return subset.filter(lambda r: repo[r].closesbranch(), 740 return subset.filter(
672 condrepr='<branch closed>') 741 lambda r: repo[r].closesbranch(), condrepr='<branch closed>'
742 )
743
673 744
674 # for internal use 745 # for internal use
675 @predicate('_commonancestorheads(set)', safe=True) 746 @predicate('_commonancestorheads(set)', safe=True)
676 def _commonancestorheads(repo, subset, x): 747 def _commonancestorheads(repo, subset, x):
677 # This is an internal method is for quickly calculating "heads(::x and 748 # This is an internal method is for quickly calculating "heads(::x and
681 # merge will find. 752 # merge will find.
682 startrevs = getset(repo, fullreposet(repo), x, order=anyorder) 753 startrevs = getset(repo, fullreposet(repo), x, order=anyorder)
683 754
684 ancs = repo.changelog._commonancestorsheads(*list(startrevs)) 755 ancs = repo.changelog._commonancestorsheads(*list(startrevs))
685 return subset & baseset(ancs) 756 return subset & baseset(ancs)
757
686 758
687 @predicate('commonancestors(set)', safe=True) 759 @predicate('commonancestors(set)', safe=True)
688 def commonancestors(repo, subset, x): 760 def commonancestors(repo, subset, x):
689 """Changesets that are ancestors of every changeset in set. 761 """Changesets that are ancestors of every changeset in set.
690 """ 762 """
692 if not startrevs: 764 if not startrevs:
693 return baseset() 765 return baseset()
694 for r in startrevs: 766 for r in startrevs:
695 subset &= dagop.revancestors(repo, baseset([r])) 767 subset &= dagop.revancestors(repo, baseset([r]))
696 return subset 768 return subset
769
697 770
698 @predicate('contains(pattern)', weight=100) 771 @predicate('contains(pattern)', weight=100)
699 def contains(repo, subset, x): 772 def contains(repo, subset, x):
700 """The revision's manifest contains a file matching pattern (but might not 773 """The revision's manifest contains a file matching pattern (but might not
701 modify it). See :hg:`help patterns` for information about file patterns. 774 modify it). See :hg:`help patterns` for information about file patterns.
720 return True 793 return True
721 return False 794 return False
722 795
723 return subset.filter(matches, condrepr=('<contains %r>', pat)) 796 return subset.filter(matches, condrepr=('<contains %r>', pat))
724 797
798
725 @predicate('converted([id])', safe=True) 799 @predicate('converted([id])', safe=True)
726 def converted(repo, subset, x): 800 def converted(repo, subset, x):
727 """Changesets converted from the given identifier in the old repository if 801 """Changesets converted from the given identifier in the old repository if
728 present, or all converted changesets if no identifier is specified. 802 present, or all converted changesets if no identifier is specified.
729 """ 803 """
740 814
741 def _matchvalue(r): 815 def _matchvalue(r):
742 source = repo[r].extra().get('convert_revision', None) 816 source = repo[r].extra().get('convert_revision', None)
743 return source is not None and (rev is None or source.startswith(rev)) 817 return source is not None and (rev is None or source.startswith(rev))
744 818
745 return subset.filter(lambda r: _matchvalue(r), 819 return subset.filter(
746 condrepr=('<converted %r>', rev)) 820 lambda r: _matchvalue(r), condrepr=('<converted %r>', rev)
821 )
822
747 823
748 @predicate('date(interval)', safe=True, weight=10) 824 @predicate('date(interval)', safe=True, weight=10)
749 def date(repo, subset, x): 825 def date(repo, subset, x):
750 """Changesets within the interval, see :hg:`help dates`. 826 """Changesets within the interval, see :hg:`help dates`.
751 """ 827 """
752 # i18n: "date" is a keyword 828 # i18n: "date" is a keyword
753 ds = getstring(x, _("date requires a string")) 829 ds = getstring(x, _("date requires a string"))
754 dm = dateutil.matchdate(ds) 830 dm = dateutil.matchdate(ds)
755 return subset.filter(lambda x: dm(repo[x].date()[0]), 831 return subset.filter(
756 condrepr=('<date %r>', ds)) 832 lambda x: dm(repo[x].date()[0]), condrepr=('<date %r>', ds)
833 )
834
757 835
758 @predicate('desc(string)', safe=True, weight=10) 836 @predicate('desc(string)', safe=True, weight=10)
759 def desc(repo, subset, x): 837 def desc(repo, subset, x):
760 """Search commit message for string. The match is case-insensitive. 838 """Search commit message for string. The match is case-insensitive.
761 839
765 # i18n: "desc" is a keyword 843 # i18n: "desc" is a keyword
766 ds = getstring(x, _("desc requires a string")) 844 ds = getstring(x, _("desc requires a string"))
767 845
768 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False) 846 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False)
769 847
770 return subset.filter(lambda r: matcher(repo[r].description()), 848 return subset.filter(
771 condrepr=('<desc %r>', ds)) 849 lambda r: matcher(repo[r].description()), condrepr=('<desc %r>', ds)
772 850 )
773 def _descendants(repo, subset, x, followfirst=False, startdepth=None, 851
774 stopdepth=None): 852
853 def _descendants(
854 repo, subset, x, followfirst=False, startdepth=None, stopdepth=None
855 ):
775 roots = getset(repo, fullreposet(repo), x) 856 roots = getset(repo, fullreposet(repo), x)
776 if not roots: 857 if not roots:
777 return baseset() 858 return baseset()
778 s = dagop.revdescendants(repo, roots, followfirst, startdepth, stopdepth) 859 s = dagop.revdescendants(repo, roots, followfirst, startdepth, stopdepth)
779 return subset & s 860 return subset & s
861
780 862
781 @predicate('descendants(set[, depth])', safe=True) 863 @predicate('descendants(set[, depth])', safe=True)
782 def descendants(repo, subset, x): 864 def descendants(repo, subset, x):
783 """Changesets which are descendants of changesets in set, including the 865 """Changesets which are descendants of changesets in set, including the
784 given changesets themselves. 866 given changesets themselves.
791 if 'set' not in args: 873 if 'set' not in args:
792 # i18n: "descendants" is a keyword 874 # i18n: "descendants" is a keyword
793 raise error.ParseError(_('descendants takes at least 1 argument')) 875 raise error.ParseError(_('descendants takes at least 1 argument'))
794 startdepth = stopdepth = None 876 startdepth = stopdepth = None
795 if 'startdepth' in args: 877 if 'startdepth' in args:
796 n = getinteger(args['startdepth'], 878 n = getinteger(
797 "descendants expects an integer startdepth") 879 args['startdepth'], "descendants expects an integer startdepth"
880 )
798 if n < 0: 881 if n < 0:
799 raise error.ParseError("negative startdepth") 882 raise error.ParseError("negative startdepth")
800 startdepth = n 883 startdepth = n
801 if 'depth' in args: 884 if 'depth' in args:
802 # i18n: "descendants" is a keyword 885 # i18n: "descendants" is a keyword
803 n = getinteger(args['depth'], _("descendants expects an integer depth")) 886 n = getinteger(args['depth'], _("descendants expects an integer depth"))
804 if n < 0: 887 if n < 0:
805 raise error.ParseError(_("negative depth")) 888 raise error.ParseError(_("negative depth"))
806 stopdepth = n + 1 889 stopdepth = n + 1
807 return _descendants(repo, subset, args['set'], 890 return _descendants(
808 startdepth=startdepth, stopdepth=stopdepth) 891 repo, subset, args['set'], startdepth=startdepth, stopdepth=stopdepth
892 )
893
809 894
810 @predicate('_firstdescendants', safe=True) 895 @predicate('_firstdescendants', safe=True)
811 def _firstdescendants(repo, subset, x): 896 def _firstdescendants(repo, subset, x):
812 # ``_firstdescendants(set)`` 897 # ``_firstdescendants(set)``
813 # Like ``descendants(set)`` but follows only the first parents. 898 # Like ``descendants(set)`` but follows only the first parents.
814 return _descendants(repo, subset, x, followfirst=True) 899 return _descendants(repo, subset, x, followfirst=True)
900
815 901
816 @predicate('destination([set])', safe=True, weight=10) 902 @predicate('destination([set])', safe=True, weight=10)
817 def destination(repo, subset, x): 903 def destination(repo, subset, x):
818 """Changesets that were created by a graft, transplant or rebase operation, 904 """Changesets that were created by a graft, transplant or rebase operation,
819 with the given revisions specified as the source. Omitting the optional set 905 with the given revisions specified as the source. Omitting the optional set
853 break 939 break
854 940
855 r = src 941 r = src
856 src = _getrevsource(repo, r) 942 src = _getrevsource(repo, r)
857 943
858 return subset.filter(dests.__contains__, 944 return subset.filter(
859 condrepr=lambda: '<destination %r>' % _sortedb(dests)) 945 dests.__contains__,
946 condrepr=lambda: '<destination %r>' % _sortedb(dests),
947 )
948
860 949
861 @predicate('contentdivergent()', safe=True) 950 @predicate('contentdivergent()', safe=True)
862 def contentdivergent(repo, subset, x): 951 def contentdivergent(repo, subset, x):
863 """ 952 """
864 Final successors of changesets with an alternative set of final 953 Final successors of changesets with an alternative set of final
866 """ 955 """
867 # i18n: "contentdivergent" is a keyword 956 # i18n: "contentdivergent" is a keyword
868 getargs(x, 0, 0, _("contentdivergent takes no arguments")) 957 getargs(x, 0, 0, _("contentdivergent takes no arguments"))
869 contentdivergent = obsmod.getrevs(repo, 'contentdivergent') 958 contentdivergent = obsmod.getrevs(repo, 'contentdivergent')
870 return subset & contentdivergent 959 return subset & contentdivergent
960
871 961
872 @predicate('expectsize(set[, size])', safe=True, takeorder=True) 962 @predicate('expectsize(set[, size])', safe=True, takeorder=True)
873 def expectsize(repo, subset, x, order): 963 def expectsize(repo, subset, x, order):
874 """Return the given revset if size matches the revset size. 964 """Return the given revset if size matches the revset size.
875 Abort if the revset doesn't expect given size. 965 Abort if the revset doesn't expect given size.
882 minsize = 0 972 minsize = 0
883 maxsize = len(repo) + 1 973 maxsize = len(repo) + 1
884 err = '' 974 err = ''
885 if 'size' not in args or 'set' not in args: 975 if 'size' not in args or 'set' not in args:
886 raise error.ParseError(_('invalid set of arguments')) 976 raise error.ParseError(_('invalid set of arguments'))
887 minsize, maxsize = getintrange(args['size'], 977 minsize, maxsize = getintrange(
888 _('expectsize requires a size range' 978 args['size'],
889 ' or a positive integer'), 979 _('expectsize requires a size range' ' or a positive integer'),
890 _('size range bounds must be integers'), 980 _('size range bounds must be integers'),
891 minsize, maxsize) 981 minsize,
982 maxsize,
983 )
892 if minsize < 0 or maxsize < 0: 984 if minsize < 0 or maxsize < 0:
893 raise error.ParseError(_('negative size')) 985 raise error.ParseError(_('negative size'))
894 rev = getset(repo, fullreposet(repo), args['set'], order=order) 986 rev = getset(repo, fullreposet(repo), args['set'], order=order)
895 if minsize != maxsize and (len(rev) < minsize or len(rev) > maxsize): 987 if minsize != maxsize and (len(rev) < minsize or len(rev) > maxsize):
896 err = _('revset size mismatch.' 988 err = _(
897 ' expected between %d and %d, got %d') % (minsize, maxsize, 989 'revset size mismatch.' ' expected between %d and %d, got %d'
898 len(rev)) 990 ) % (minsize, maxsize, len(rev))
899 elif minsize == maxsize and len(rev) != minsize: 991 elif minsize == maxsize and len(rev) != minsize:
900 err = _('revset size mismatch.' 992 err = _('revset size mismatch.' ' expected %d, got %d') % (
901 ' expected %d, got %d') % (minsize, len(rev)) 993 minsize,
994 len(rev),
995 )
902 if err: 996 if err:
903 raise error.RepoLookupError(err) 997 raise error.RepoLookupError(err)
904 if order == followorder: 998 if order == followorder:
905 return subset & rev 999 return subset & rev
906 else: 1000 else:
907 return rev & subset 1001 return rev & subset
908 1002
1003
909 @predicate('extdata(source)', safe=False, weight=100) 1004 @predicate('extdata(source)', safe=False, weight=100)
910 def extdata(repo, subset, x): 1005 def extdata(repo, subset, x):
911 """Changesets in the specified extdata source. (EXPERIMENTAL)""" 1006 """Changesets in the specified extdata source. (EXPERIMENTAL)"""
912 # i18n: "extdata" is a keyword 1007 # i18n: "extdata" is a keyword
913 args = getargsdict(x, 'extdata', 'source') 1008 args = getargsdict(x, 'extdata', 'source')
914 source = getstring(args.get('source'), 1009 source = getstring(
915 # i18n: "extdata" is a keyword 1010 args.get('source'),
916 _('extdata takes at least 1 string argument')) 1011 # i18n: "extdata" is a keyword
1012 _('extdata takes at least 1 string argument'),
1013 )
917 data = scmutil.extdatasource(repo, source) 1014 data = scmutil.extdatasource(repo, source)
918 return subset & baseset(data) 1015 return subset & baseset(data)
1016
919 1017
920 @predicate('extinct()', safe=True) 1018 @predicate('extinct()', safe=True)
921 def extinct(repo, subset, x): 1019 def extinct(repo, subset, x):
922 """Obsolete changesets with obsolete descendants only. 1020 """Obsolete changesets with obsolete descendants only.
923 """ 1021 """
924 # i18n: "extinct" is a keyword 1022 # i18n: "extinct" is a keyword
925 getargs(x, 0, 0, _("extinct takes no arguments")) 1023 getargs(x, 0, 0, _("extinct takes no arguments"))
926 extincts = obsmod.getrevs(repo, 'extinct') 1024 extincts = obsmod.getrevs(repo, 'extinct')
927 return subset & extincts 1025 return subset & extincts
1026
928 1027
929 @predicate('extra(label, [value])', safe=True) 1028 @predicate('extra(label, [value])', safe=True)
930 def extra(repo, subset, x): 1029 def extra(repo, subset, x):
931 """Changesets with the given label in the extra metadata, with the given 1030 """Changesets with the given label in the extra metadata, with the given
932 optional value. 1031 optional value.
937 args = getargsdict(x, 'extra', 'label value') 1036 args = getargsdict(x, 'extra', 'label value')
938 if 'label' not in args: 1037 if 'label' not in args:
939 # i18n: "extra" is a keyword 1038 # i18n: "extra" is a keyword
940 raise error.ParseError(_('extra takes at least 1 argument')) 1039 raise error.ParseError(_('extra takes at least 1 argument'))
941 # i18n: "extra" is a keyword 1040 # i18n: "extra" is a keyword
942 label = getstring(args['label'], _('first argument to extra must be ' 1041 label = getstring(
943 'a string')) 1042 args['label'], _('first argument to extra must be ' 'a string')
1043 )
944 value = None 1044 value = None
945 1045
946 if 'value' in args: 1046 if 'value' in args:
947 # i18n: "extra" is a keyword 1047 # i18n: "extra" is a keyword
948 value = getstring(args['value'], _('second argument to extra must be ' 1048 value = getstring(
949 'a string')) 1049 args['value'], _('second argument to extra must be ' 'a string')
1050 )
950 kind, value, matcher = stringutil.stringmatcher(value) 1051 kind, value, matcher = stringutil.stringmatcher(value)
951 1052
952 def _matchvalue(r): 1053 def _matchvalue(r):
953 extra = repo[r].extra() 1054 extra = repo[r].extra()
954 return label in extra and (value is None or matcher(extra[label])) 1055 return label in extra and (value is None or matcher(extra[label]))
955 1056
956 return subset.filter(lambda r: _matchvalue(r), 1057 return subset.filter(
957 condrepr=('<extra[%r] %r>', label, value)) 1058 lambda r: _matchvalue(r), condrepr=('<extra[%r] %r>', label, value)
1059 )
1060
958 1061
959 @predicate('filelog(pattern)', safe=True) 1062 @predicate('filelog(pattern)', safe=True)
960 def filelog(repo, subset, x): 1063 def filelog(repo, subset, x):
961 """Changesets connected to the specified filelog. 1064 """Changesets connected to the specified filelog.
962 1065
1017 # deletion in changelog 1120 # deletion in changelog
1018 continue 1121 continue
1019 1122
1020 return subset & s 1123 return subset & s
1021 1124
1125
1022 @predicate('first(set, [n])', safe=True, takeorder=True, weight=0) 1126 @predicate('first(set, [n])', safe=True, takeorder=True, weight=0)
1023 def first(repo, subset, x, order): 1127 def first(repo, subset, x, order):
1024 """An alias for limit(). 1128 """An alias for limit().
1025 """ 1129 """
1026 return limit(repo, subset, x, order) 1130 return limit(repo, subset, x, order)
1131
1027 1132
1028 def _follow(repo, subset, x, name, followfirst=False): 1133 def _follow(repo, subset, x, name, followfirst=False):
1029 args = getargsdict(x, name, 'file startrev') 1134 args = getargsdict(x, name, 'file startrev')
1030 revs = None 1135 revs = None
1031 if 'startrev' in args: 1136 if 'startrev' in args:
1037 fctxs = [] 1142 fctxs = []
1038 for r in revs: 1143 for r in revs:
1039 ctx = mctx = repo[r] 1144 ctx = mctx = repo[r]
1040 if r is None: 1145 if r is None:
1041 ctx = repo['.'] 1146 ctx = repo['.']
1042 m = matchmod.match(repo.root, repo.getcwd(), [x], 1147 m = matchmod.match(
1043 ctx=mctx, default='path') 1148 repo.root, repo.getcwd(), [x], ctx=mctx, default='path'
1149 )
1044 fctxs.extend(ctx[f].introfilectx() for f in ctx.manifest().walk(m)) 1150 fctxs.extend(ctx[f].introfilectx() for f in ctx.manifest().walk(m))
1045 s = dagop.filerevancestors(fctxs, followfirst) 1151 s = dagop.filerevancestors(fctxs, followfirst)
1046 else: 1152 else:
1047 if revs is None: 1153 if revs is None:
1048 revs = baseset([repo['.'].rev()]) 1154 revs = baseset([repo['.'].rev()])
1049 s = dagop.revancestors(repo, revs, followfirst) 1155 s = dagop.revancestors(repo, revs, followfirst)
1050 1156
1051 return subset & s 1157 return subset & s
1052 1158
1159
1053 @predicate('follow([file[, startrev]])', safe=True) 1160 @predicate('follow([file[, startrev]])', safe=True)
1054 def follow(repo, subset, x): 1161 def follow(repo, subset, x):
1055 """ 1162 """
1056 An alias for ``::.`` (ancestors of the working directory's first parent). 1163 An alias for ``::.`` (ancestors of the working directory's first parent).
1057 If file pattern is specified, the histories of files matching given 1164 If file pattern is specified, the histories of files matching given
1058 pattern in the revision given by startrev are followed, including copies. 1165 pattern in the revision given by startrev are followed, including copies.
1059 """ 1166 """
1060 return _follow(repo, subset, x, 'follow') 1167 return _follow(repo, subset, x, 'follow')
1168
1061 1169
1062 @predicate('_followfirst', safe=True) 1170 @predicate('_followfirst', safe=True)
1063 def _followfirst(repo, subset, x): 1171 def _followfirst(repo, subset, x):
1064 # ``followfirst([file[, startrev]])`` 1172 # ``followfirst([file[, startrev]])``
1065 # Like ``follow([file[, startrev]])`` but follows only the first parent 1173 # Like ``follow([file[, startrev]])`` but follows only the first parent
1066 # of every revisions or files revisions. 1174 # of every revisions or files revisions.
1067 return _follow(repo, subset, x, '_followfirst', followfirst=True) 1175 return _follow(repo, subset, x, '_followfirst', followfirst=True)
1068 1176
1069 @predicate('followlines(file, fromline:toline[, startrev=., descend=False])', 1177
1070 safe=True) 1178 @predicate(
1179 'followlines(file, fromline:toline[, startrev=., descend=False])', safe=True
1180 )
1071 def followlines(repo, subset, x): 1181 def followlines(repo, subset, x):
1072 """Changesets modifying `file` in line range ('fromline', 'toline'). 1182 """Changesets modifying `file` in line range ('fromline', 'toline').
1073 1183
1074 Line range corresponds to 'file' content at 'startrev' and should hence be 1184 Line range corresponds to 'file' content at 'startrev' and should hence be
1075 consistent with file size. If startrev is not specified, working directory's 1185 consistent with file size. If startrev is not specified, working directory's
1087 if 'startrev' in args: 1197 if 'startrev' in args:
1088 revs = getset(repo, fullreposet(repo), args['startrev']) 1198 revs = getset(repo, fullreposet(repo), args['startrev'])
1089 if len(revs) != 1: 1199 if len(revs) != 1:
1090 raise error.ParseError( 1200 raise error.ParseError(
1091 # i18n: "followlines" is a keyword 1201 # i18n: "followlines" is a keyword
1092 _("followlines expects exactly one revision")) 1202 _("followlines expects exactly one revision")
1203 )
1093 rev = revs.last() 1204 rev = revs.last()
1094 1205
1095 pat = getstring(args['file'], _("followlines requires a pattern")) 1206 pat = getstring(args['file'], _("followlines requires a pattern"))
1096 # i18n: "followlines" is a keyword 1207 # i18n: "followlines" is a keyword
1097 msg = _("followlines expects exactly one file") 1208 msg = _("followlines expects exactly one file")
1098 fname = scmutil.parsefollowlinespattern(repo, rev, pat, msg) 1209 fname = scmutil.parsefollowlinespattern(repo, rev, pat, msg)
1099 fromline, toline = util.processlinerange( 1210 fromline, toline = util.processlinerange(
1100 *getintrange(args['lines'][0], 1211 *getintrange(
1101 # i18n: "followlines" is a keyword 1212 args['lines'][0],
1102 _("followlines expects a line number or a range"), 1213 # i18n: "followlines" is a keyword
1103 _("line range bounds must be integers"))) 1214 _("followlines expects a line number or a range"),
1215 _("line range bounds must be integers"),
1216 )
1217 )
1104 1218
1105 fctx = repo[rev].filectx(fname) 1219 fctx = repo[rev].filectx(fname)
1106 descend = False 1220 descend = False
1107 if 'descend' in args: 1221 if 'descend' in args:
1108 descend = getboolean(args['descend'], 1222 descend = getboolean(
1109 # i18n: "descend" is a keyword 1223 args['descend'],
1110 _("descend argument must be a boolean")) 1224 # i18n: "descend" is a keyword
1225 _("descend argument must be a boolean"),
1226 )
1111 if descend: 1227 if descend:
1112 rs = generatorset( 1228 rs = generatorset(
1113 (c.rev() for c, _linerange 1229 (
1114 in dagop.blockdescendants(fctx, fromline, toline)), 1230 c.rev()
1115 iterasc=True) 1231 for c, _linerange in dagop.blockdescendants(
1232 fctx, fromline, toline
1233 )
1234 ),
1235 iterasc=True,
1236 )
1116 else: 1237 else:
1117 rs = generatorset( 1238 rs = generatorset(
1118 (c.rev() for c, _linerange 1239 (
1119 in dagop.blockancestors(fctx, fromline, toline)), 1240 c.rev()
1120 iterasc=False) 1241 for c, _linerange in dagop.blockancestors(
1242 fctx, fromline, toline
1243 )
1244 ),
1245 iterasc=False,
1246 )
1121 return subset & rs 1247 return subset & rs
1248
1122 1249
1123 @predicate('all()', safe=True) 1250 @predicate('all()', safe=True)
1124 def getall(repo, subset, x): 1251 def getall(repo, subset, x):
1125 """All changesets, the same as ``0:tip``. 1252 """All changesets, the same as ``0:tip``.
1126 """ 1253 """
1127 # i18n: "all" is a keyword 1254 # i18n: "all" is a keyword
1128 getargs(x, 0, 0, _("all takes no arguments")) 1255 getargs(x, 0, 0, _("all takes no arguments"))
1129 return subset & spanset(repo) # drop "null" if any 1256 return subset & spanset(repo) # drop "null" if any
1257
1130 1258
1131 @predicate('grep(regex)', weight=10) 1259 @predicate('grep(regex)', weight=10)
1132 def grep(repo, subset, x): 1260 def grep(repo, subset, x):
1133 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')`` 1261 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
1134 to ensure special escape characters are handled correctly. Unlike 1262 to ensure special escape characters are handled correctly. Unlike
1137 try: 1265 try:
1138 # i18n: "grep" is a keyword 1266 # i18n: "grep" is a keyword
1139 gr = re.compile(getstring(x, _("grep requires a string"))) 1267 gr = re.compile(getstring(x, _("grep requires a string")))
1140 except re.error as e: 1268 except re.error as e:
1141 raise error.ParseError( 1269 raise error.ParseError(
1142 _('invalid match pattern: %s') % stringutil.forcebytestr(e)) 1270 _('invalid match pattern: %s') % stringutil.forcebytestr(e)
1271 )
1143 1272
1144 def matches(x): 1273 def matches(x):
1145 c = repo[x] 1274 c = repo[x]
1146 for e in c.files() + [c.user(), c.description()]: 1275 for e in c.files() + [c.user(), c.description()]:
1147 if gr.search(e): 1276 if gr.search(e):
1148 return True 1277 return True
1149 return False 1278 return False
1150 1279
1151 return subset.filter(matches, condrepr=('<grep %r>', gr.pattern)) 1280 return subset.filter(matches, condrepr=('<grep %r>', gr.pattern))
1281
1152 1282
1153 @predicate('_matchfiles', safe=True) 1283 @predicate('_matchfiles', safe=True)
1154 def _matchfiles(repo, subset, x): 1284 def _matchfiles(repo, subset, x):
1155 # _matchfiles takes a revset list of prefixed arguments: 1285 # _matchfiles takes a revset list of prefixed arguments:
1156 # 1286 #
1176 inc.append(value) 1306 inc.append(value)
1177 elif prefix == 'x:': 1307 elif prefix == 'x:':
1178 exc.append(value) 1308 exc.append(value)
1179 elif prefix == 'r:': 1309 elif prefix == 'r:':
1180 if rev is not None: 1310 if rev is not None:
1181 raise error.ParseError('_matchfiles expected at most one ' 1311 raise error.ParseError(
1182 'revision') 1312 '_matchfiles expected at most one ' 'revision'
1183 if value == '': # empty means working directory 1313 )
1314 if value == '': # empty means working directory
1184 rev = node.wdirrev 1315 rev = node.wdirrev
1185 else: 1316 else:
1186 rev = value 1317 rev = value
1187 elif prefix == 'd:': 1318 elif prefix == 'd:':
1188 if default is not None: 1319 if default is not None:
1189 raise error.ParseError('_matchfiles expected at most one ' 1320 raise error.ParseError(
1190 'default mode') 1321 '_matchfiles expected at most one ' 'default mode'
1322 )
1191 default = value 1323 default = value
1192 else: 1324 else:
1193 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix) 1325 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix)
1194 if not default: 1326 if not default:
1195 default = 'glob' 1327 default = 'glob'
1199 1331
1200 # This directly read the changelog data as creating changectx for all 1332 # This directly read the changelog data as creating changectx for all
1201 # revisions is quite expensive. 1333 # revisions is quite expensive.
1202 getfiles = repo.changelog.readfiles 1334 getfiles = repo.changelog.readfiles
1203 wdirrev = node.wdirrev 1335 wdirrev = node.wdirrev
1336
1204 def matches(x): 1337 def matches(x):
1205 if x == wdirrev: 1338 if x == wdirrev:
1206 files = repo[x].files() 1339 files = repo[x].files()
1207 else: 1340 else:
1208 files = getfiles(x) 1341 files = getfiles(x)
1209 1342
1210 if not mcache[0] or (hasset and rev is None): 1343 if not mcache[0] or (hasset and rev is None):
1211 r = x if rev is None else rev 1344 r = x if rev is None else rev
1212 mcache[0] = matchmod.match(repo.root, repo.getcwd(), pats, 1345 mcache[0] = matchmod.match(
1213 include=inc, exclude=exc, ctx=repo[r], 1346 repo.root,
1214 default=default) 1347 repo.getcwd(),
1348 pats,
1349 include=inc,
1350 exclude=exc,
1351 ctx=repo[r],
1352 default=default,
1353 )
1215 m = mcache[0] 1354 m = mcache[0]
1216 1355
1217 for f in files: 1356 for f in files:
1218 if m(f): 1357 if m(f):
1219 return True 1358 return True
1220 return False 1359 return False
1221 1360
1222 return subset.filter(matches, 1361 return subset.filter(
1223 condrepr=('<matchfiles patterns=%r, include=%r ' 1362 matches,
1224 'exclude=%r, default=%r, rev=%r>', 1363 condrepr=(
1225 pats, inc, exc, default, rev)) 1364 '<matchfiles patterns=%r, include=%r '
1365 'exclude=%r, default=%r, rev=%r>',
1366 pats,
1367 inc,
1368 exc,
1369 default,
1370 rev,
1371 ),
1372 )
1373
1226 1374
1227 @predicate('file(pattern)', safe=True, weight=10) 1375 @predicate('file(pattern)', safe=True, weight=10)
1228 def hasfile(repo, subset, x): 1376 def hasfile(repo, subset, x):
1229 """Changesets affecting files matched by pattern. 1377 """Changesets affecting files matched by pattern.
1230 1378
1234 This predicate uses ``glob:`` as the default kind of pattern. 1382 This predicate uses ``glob:`` as the default kind of pattern.
1235 """ 1383 """
1236 # i18n: "file" is a keyword 1384 # i18n: "file" is a keyword
1237 pat = getstring(x, _("file requires a pattern")) 1385 pat = getstring(x, _("file requires a pattern"))
1238 return _matchfiles(repo, subset, ('string', 'p:' + pat)) 1386 return _matchfiles(repo, subset, ('string', 'p:' + pat))
1387
1239 1388
1240 @predicate('head()', safe=True) 1389 @predicate('head()', safe=True)
1241 def head(repo, subset, x): 1390 def head(repo, subset, x):
1242 """Changeset is a named branch head. 1391 """Changeset is a named branch head.
1243 """ 1392 """
1246 hs = set() 1395 hs = set()
1247 cl = repo.changelog 1396 cl = repo.changelog
1248 for ls in repo.branchmap().iterheads(): 1397 for ls in repo.branchmap().iterheads():
1249 hs.update(cl.rev(h) for h in ls) 1398 hs.update(cl.rev(h) for h in ls)
1250 return subset & baseset(hs) 1399 return subset & baseset(hs)
1400
1251 1401
1252 @predicate('heads(set)', safe=True, takeorder=True) 1402 @predicate('heads(set)', safe=True, takeorder=True)
1253 def heads(repo, subset, x, order): 1403 def heads(repo, subset, x, order):
1254 """Members of set with no children in set. 1404 """Members of set with no children in set.
1255 """ 1405 """
1268 heads.difference_update(wdirparents) 1418 heads.difference_update(wdirparents)
1269 heads.add(node.wdirrev) 1419 heads.add(node.wdirrev)
1270 heads = baseset(heads) 1420 heads = baseset(heads)
1271 return subset & heads 1421 return subset & heads
1272 1422
1423
1273 @predicate('hidden()', safe=True) 1424 @predicate('hidden()', safe=True)
1274 def hidden(repo, subset, x): 1425 def hidden(repo, subset, x):
1275 """Hidden changesets. 1426 """Hidden changesets.
1276 """ 1427 """
1277 # i18n: "hidden" is a keyword 1428 # i18n: "hidden" is a keyword
1278 getargs(x, 0, 0, _("hidden takes no arguments")) 1429 getargs(x, 0, 0, _("hidden takes no arguments"))
1279 hiddenrevs = repoview.filterrevs(repo, 'visible') 1430 hiddenrevs = repoview.filterrevs(repo, 'visible')
1280 return subset & hiddenrevs 1431 return subset & hiddenrevs
1281 1432
1433
1282 @predicate('keyword(string)', safe=True, weight=10) 1434 @predicate('keyword(string)', safe=True, weight=10)
1283 def keyword(repo, subset, x): 1435 def keyword(repo, subset, x):
1284 """Search commit message, user name, and names of changed files for 1436 """Search commit message, user name, and names of changed files for
1285 string. The match is case-insensitive. 1437 string. The match is case-insensitive.
1286 1438
1290 # i18n: "keyword" is a keyword 1442 # i18n: "keyword" is a keyword
1291 kw = encoding.lower(getstring(x, _("keyword requires a string"))) 1443 kw = encoding.lower(getstring(x, _("keyword requires a string")))
1292 1444
1293 def matches(r): 1445 def matches(r):
1294 c = repo[r] 1446 c = repo[r]
1295 return any(kw in encoding.lower(t) 1447 return any(
1296 for t in c.files() + [c.user(), c.description()]) 1448 kw in encoding.lower(t)
1449 for t in c.files() + [c.user(), c.description()]
1450 )
1297 1451
1298 return subset.filter(matches, condrepr=('<keyword %r>', kw)) 1452 return subset.filter(matches, condrepr=('<keyword %r>', kw))
1453
1299 1454
1300 @predicate('limit(set[, n[, offset]])', safe=True, takeorder=True, weight=0) 1455 @predicate('limit(set[, n[, offset]])', safe=True, takeorder=True, weight=0)
1301 def limit(repo, subset, x, order): 1456 def limit(repo, subset, x, order):
1302 """First n members of set, defaulting to 1, starting from offset. 1457 """First n members of set, defaulting to 1, starting from offset.
1303 """ 1458 """
1317 ls = os.slice(ofs, ofs + lim) 1472 ls = os.slice(ofs, ofs + lim)
1318 if order == followorder and lim > 1: 1473 if order == followorder and lim > 1:
1319 return subset & ls 1474 return subset & ls
1320 return ls & subset 1475 return ls & subset
1321 1476
1477
1322 @predicate('last(set, [n])', safe=True, takeorder=True) 1478 @predicate('last(set, [n])', safe=True, takeorder=True)
1323 def last(repo, subset, x, order): 1479 def last(repo, subset, x, order):
1324 """Last n members of set, defaulting to 1. 1480 """Last n members of set, defaulting to 1.
1325 """ 1481 """
1326 # i18n: "last" is a keyword 1482 # i18n: "last" is a keyword
1337 if order == followorder and lim > 1: 1493 if order == followorder and lim > 1:
1338 return subset & ls 1494 return subset & ls
1339 ls.reverse() 1495 ls.reverse()
1340 return ls & subset 1496 return ls & subset
1341 1497
1498
1342 @predicate('max(set)', safe=True) 1499 @predicate('max(set)', safe=True)
1343 def maxrev(repo, subset, x): 1500 def maxrev(repo, subset, x):
1344 """Changeset with highest revision number in set. 1501 """Changeset with highest revision number in set.
1345 """ 1502 """
1346 os = getset(repo, fullreposet(repo), x) 1503 os = getset(repo, fullreposet(repo), x)
1352 # os.max() throws a ValueError when the collection is empty. 1509 # os.max() throws a ValueError when the collection is empty.
1353 # Same as python's max(). 1510 # Same as python's max().
1354 pass 1511 pass
1355 return baseset(datarepr=('<max %r, %r>', subset, os)) 1512 return baseset(datarepr=('<max %r, %r>', subset, os))
1356 1513
1514
1357 @predicate('merge()', safe=True) 1515 @predicate('merge()', safe=True)
1358 def merge(repo, subset, x): 1516 def merge(repo, subset, x):
1359 """Changeset is a merge changeset. 1517 """Changeset is a merge changeset.
1360 """ 1518 """
1361 # i18n: "merge" is a keyword 1519 # i18n: "merge" is a keyword
1362 getargs(x, 0, 0, _("merge takes no arguments")) 1520 getargs(x, 0, 0, _("merge takes no arguments"))
1363 cl = repo.changelog 1521 cl = repo.changelog
1364 nullrev = node.nullrev 1522 nullrev = node.nullrev
1523
1365 def ismerge(r): 1524 def ismerge(r):
1366 try: 1525 try:
1367 return cl.parentrevs(r)[1] != nullrev 1526 return cl.parentrevs(r)[1] != nullrev
1368 except error.WdirUnsupported: 1527 except error.WdirUnsupported:
1369 return bool(repo[r].p2()) 1528 return bool(repo[r].p2())
1529
1370 return subset.filter(ismerge, condrepr='<merge>') 1530 return subset.filter(ismerge, condrepr='<merge>')
1531
1371 1532
1372 @predicate('branchpoint()', safe=True) 1533 @predicate('branchpoint()', safe=True)
1373 def branchpoint(repo, subset, x): 1534 def branchpoint(repo, subset, x):
1374 """Changesets with more than one child. 1535 """Changesets with more than one child.
1375 """ 1536 """
1379 if not subset: 1540 if not subset:
1380 return baseset() 1541 return baseset()
1381 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset 1542 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset
1382 # (and if it is not, it should.) 1543 # (and if it is not, it should.)
1383 baserev = min(subset) 1544 baserev = min(subset)
1384 parentscount = [0]*(len(repo) - baserev) 1545 parentscount = [0] * (len(repo) - baserev)
1385 for r in cl.revs(start=baserev + 1): 1546 for r in cl.revs(start=baserev + 1):
1386 for p in cl.parentrevs(r): 1547 for p in cl.parentrevs(r):
1387 if p >= baserev: 1548 if p >= baserev:
1388 parentscount[p - baserev] += 1 1549 parentscount[p - baserev] += 1
1389 return subset.filter(lambda r: parentscount[r - baserev] > 1, 1550 return subset.filter(
1390 condrepr='<branchpoint>') 1551 lambda r: parentscount[r - baserev] > 1, condrepr='<branchpoint>'
1552 )
1553
1391 1554
1392 @predicate('min(set)', safe=True) 1555 @predicate('min(set)', safe=True)
1393 def minrev(repo, subset, x): 1556 def minrev(repo, subset, x):
1394 """Changeset with lowest revision number in set. 1557 """Changeset with lowest revision number in set.
1395 """ 1558 """
1402 # os.min() throws a ValueError when the collection is empty. 1565 # os.min() throws a ValueError when the collection is empty.
1403 # Same as python's min(). 1566 # Same as python's min().
1404 pass 1567 pass
1405 return baseset(datarepr=('<min %r, %r>', subset, os)) 1568 return baseset(datarepr=('<min %r, %r>', subset, os))
1406 1569
1570
1407 @predicate('modifies(pattern)', safe=True, weight=30) 1571 @predicate('modifies(pattern)', safe=True, weight=30)
1408 def modifies(repo, subset, x): 1572 def modifies(repo, subset, x):
1409 """Changesets modifying files matched by pattern. 1573 """Changesets modifying files matched by pattern.
1410 1574
1411 The pattern without explicit kind like ``glob:`` is expected to be 1575 The pattern without explicit kind like ``glob:`` is expected to be
1414 """ 1578 """
1415 # i18n: "modifies" is a keyword 1579 # i18n: "modifies" is a keyword
1416 pat = getstring(x, _("modifies requires a pattern")) 1580 pat = getstring(x, _("modifies requires a pattern"))
1417 return checkstatus(repo, subset, pat, 0) 1581 return checkstatus(repo, subset, pat, 0)
1418 1582
1583
1419 @predicate('named(namespace)') 1584 @predicate('named(namespace)')
1420 def named(repo, subset, x): 1585 def named(repo, subset, x):
1421 """The changesets in a given namespace. 1586 """The changesets in a given namespace.
1422 1587
1423 Pattern matching is supported for `namespace`. See 1588 Pattern matching is supported for `namespace`. See
1424 :hg:`help revisions.patterns`. 1589 :hg:`help revisions.patterns`.
1425 """ 1590 """
1426 # i18n: "named" is a keyword 1591 # i18n: "named" is a keyword
1427 args = getargs(x, 1, 1, _('named requires a namespace argument')) 1592 args = getargs(x, 1, 1, _('named requires a namespace argument'))
1428 1593
1429 ns = getstring(args[0], 1594 ns = getstring(
1430 # i18n: "named" is a keyword 1595 args[0],
1431 _('the argument to named must be a string')) 1596 # i18n: "named" is a keyword
1597 _('the argument to named must be a string'),
1598 )
1432 kind, pattern, matcher = stringutil.stringmatcher(ns) 1599 kind, pattern, matcher = stringutil.stringmatcher(ns)
1433 namespaces = set() 1600 namespaces = set()
1434 if kind == 'literal': 1601 if kind == 'literal':
1435 if pattern not in repo.names: 1602 if pattern not in repo.names:
1436 raise error.RepoLookupError(_("namespace '%s' does not exist") 1603 raise error.RepoLookupError(_("namespace '%s' does not exist") % ns)
1437 % ns)
1438 namespaces.add(repo.names[pattern]) 1604 namespaces.add(repo.names[pattern])
1439 else: 1605 else:
1440 for name, ns in repo.names.iteritems(): 1606 for name, ns in repo.names.iteritems():
1441 if matcher(name): 1607 if matcher(name):
1442 namespaces.add(ns) 1608 namespaces.add(ns)
1447 if name not in ns.deprecated: 1613 if name not in ns.deprecated:
1448 names.update(repo[n].rev() for n in ns.nodes(repo, name)) 1614 names.update(repo[n].rev() for n in ns.nodes(repo, name))
1449 1615
1450 names -= {node.nullrev} 1616 names -= {node.nullrev}
1451 return subset & names 1617 return subset & names
1618
1452 1619
1453 @predicate('id(string)', safe=True) 1620 @predicate('id(string)', safe=True)
1454 def node_(repo, subset, x): 1621 def node_(repo, subset, x):
1455 """Revision non-ambiguously specified by the given hex string prefix. 1622 """Revision non-ambiguously specified by the given hex string prefix.
1456 """ 1623 """
1479 if rn is None: 1646 if rn is None:
1480 return baseset() 1647 return baseset()
1481 result = baseset([rn]) 1648 result = baseset([rn])
1482 return result & subset 1649 return result & subset
1483 1650
1651
1484 @predicate('none()', safe=True) 1652 @predicate('none()', safe=True)
1485 def none(repo, subset, x): 1653 def none(repo, subset, x):
1486 """No changesets. 1654 """No changesets.
1487 """ 1655 """
1488 # i18n: "none" is a keyword 1656 # i18n: "none" is a keyword
1489 getargs(x, 0, 0, _("none takes no arguments")) 1657 getargs(x, 0, 0, _("none takes no arguments"))
1490 return baseset() 1658 return baseset()
1659
1491 1660
1492 @predicate('obsolete()', safe=True) 1661 @predicate('obsolete()', safe=True)
1493 def obsolete(repo, subset, x): 1662 def obsolete(repo, subset, x):
1494 """Mutable changeset with a newer version.""" 1663 """Mutable changeset with a newer version."""
1495 # i18n: "obsolete" is a keyword 1664 # i18n: "obsolete" is a keyword
1496 getargs(x, 0, 0, _("obsolete takes no arguments")) 1665 getargs(x, 0, 0, _("obsolete takes no arguments"))
1497 obsoletes = obsmod.getrevs(repo, 'obsolete') 1666 obsoletes = obsmod.getrevs(repo, 'obsolete')
1498 return subset & obsoletes 1667 return subset & obsoletes
1499 1668
1669
1500 @predicate('only(set, [set])', safe=True) 1670 @predicate('only(set, [set])', safe=True)
1501 def only(repo, subset, x): 1671 def only(repo, subset, x):
1502 """Changesets that are ancestors of the first set that are not ancestors 1672 """Changesets that are ancestors of the first set that are not ancestors
1503 of any other head in the repo. If a second set is specified, the result 1673 of any other head in the repo. If a second set is specified, the result
1504 is ancestors of the first set that are not ancestors of the second set 1674 is ancestors of the first set that are not ancestors of the second set
1511 if len(args) == 1: 1681 if len(args) == 1:
1512 if not include: 1682 if not include:
1513 return baseset() 1683 return baseset()
1514 1684
1515 descendants = set(dagop.revdescendants(repo, include, False)) 1685 descendants = set(dagop.revdescendants(repo, include, False))
1516 exclude = [rev for rev in cl.headrevs() 1686 exclude = [
1517 if not rev in descendants and not rev in include] 1687 rev
1688 for rev in cl.headrevs()
1689 if not rev in descendants and not rev in include
1690 ]
1518 else: 1691 else:
1519 exclude = getset(repo, fullreposet(repo), args[1]) 1692 exclude = getset(repo, fullreposet(repo), args[1])
1520 1693
1521 results = set(cl.findmissingrevs(common=exclude, heads=include)) 1694 results = set(cl.findmissingrevs(common=exclude, heads=include))
1522 # XXX we should turn this into a baseset instead of a set, smartset may do 1695 # XXX we should turn this into a baseset instead of a set, smartset may do
1523 # some optimizations from the fact this is a baseset. 1696 # some optimizations from the fact this is a baseset.
1524 return subset & results 1697 return subset & results
1698
1525 1699
1526 @predicate('origin([set])', safe=True) 1700 @predicate('origin([set])', safe=True)
1527 def origin(repo, subset, x): 1701 def origin(repo, subset, x):
1528 """ 1702 """
1529 Changesets that were specified as a source for the grafts, transplants or 1703 Changesets that were specified as a source for the grafts, transplants or
1553 o -= {None} 1727 o -= {None}
1554 # XXX we should turn this into a baseset instead of a set, smartset may do 1728 # XXX we should turn this into a baseset instead of a set, smartset may do
1555 # some optimizations from the fact this is a baseset. 1729 # some optimizations from the fact this is a baseset.
1556 return subset & o 1730 return subset & o
1557 1731
1732
1558 @predicate('outgoing([path])', safe=False, weight=10) 1733 @predicate('outgoing([path])', safe=False, weight=10)
1559 def outgoing(repo, subset, x): 1734 def outgoing(repo, subset, x):
1560 """Changesets not found in the specified destination repository, or the 1735 """Changesets not found in the specified destination repository, or the
1561 default push location. 1736 default push location.
1562 """ 1737 """
1563 # Avoid cycles. 1738 # Avoid cycles.
1564 from . import ( 1739 from . import (
1565 discovery, 1740 discovery,
1566 hg, 1741 hg,
1567 ) 1742 )
1743
1568 # i18n: "outgoing" is a keyword 1744 # i18n: "outgoing" is a keyword
1569 l = getargs(x, 0, 1, _("outgoing takes one or no arguments")) 1745 l = getargs(x, 0, 1, _("outgoing takes one or no arguments"))
1570 # i18n: "outgoing" is a keyword 1746 # i18n: "outgoing" is a keyword
1571 dest = l and getstring(l[0], _("outgoing requires a repository path")) or '' 1747 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
1572 if not dest: 1748 if not dest:
1573 # ui.paths.getpath() explicitly tests for None, not just a boolean 1749 # ui.paths.getpath() explicitly tests for None, not just a boolean
1574 dest = None 1750 dest = None
1575 path = repo.ui.paths.getpath(dest, default=('default-push', 'default')) 1751 path = repo.ui.paths.getpath(dest, default=('default-push', 'default'))
1576 if not path: 1752 if not path:
1577 raise error.Abort(_('default repository not configured!'), 1753 raise error.Abort(
1578 hint=_("see 'hg help config.paths'")) 1754 _('default repository not configured!'),
1755 hint=_("see 'hg help config.paths'"),
1756 )
1579 dest = path.pushloc or path.loc 1757 dest = path.pushloc or path.loc
1580 branches = path.branch, [] 1758 branches = path.branch, []
1581 1759
1582 revs, checkout = hg.addbranchrevs(repo, repo, branches, []) 1760 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
1583 if revs: 1761 if revs:
1587 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs) 1765 outgoing = discovery.findcommonoutgoing(repo, other, onlyheads=revs)
1588 repo.ui.popbuffer() 1766 repo.ui.popbuffer()
1589 cl = repo.changelog 1767 cl = repo.changelog
1590 o = {cl.rev(r) for r in outgoing.missing} 1768 o = {cl.rev(r) for r in outgoing.missing}
1591 return subset & o 1769 return subset & o
1770
1592 1771
1593 @predicate('p1([set])', safe=True) 1772 @predicate('p1([set])', safe=True)
1594 def p1(repo, subset, x): 1773 def p1(repo, subset, x):
1595 """First parent of changesets in set, or the working directory. 1774 """First parent of changesets in set, or the working directory.
1596 """ 1775 """
1609 ps.add(repo[r].p1().rev()) 1788 ps.add(repo[r].p1().rev())
1610 ps -= {node.nullrev} 1789 ps -= {node.nullrev}
1611 # XXX we should turn this into a baseset instead of a set, smartset may do 1790 # XXX we should turn this into a baseset instead of a set, smartset may do
1612 # some optimizations from the fact this is a baseset. 1791 # some optimizations from the fact this is a baseset.
1613 return subset & ps 1792 return subset & ps
1793
1614 1794
1615 @predicate('p2([set])', safe=True) 1795 @predicate('p2([set])', safe=True)
1616 def p2(repo, subset, x): 1796 def p2(repo, subset, x):
1617 """Second parent of changesets in set, or the working directory. 1797 """Second parent of changesets in set, or the working directory.
1618 """ 1798 """
1638 ps -= {node.nullrev} 1818 ps -= {node.nullrev}
1639 # XXX we should turn this into a baseset instead of a set, smartset may do 1819 # XXX we should turn this into a baseset instead of a set, smartset may do
1640 # some optimizations from the fact this is a baseset. 1820 # some optimizations from the fact this is a baseset.
1641 return subset & ps 1821 return subset & ps
1642 1822
1823
1643 def parentpost(repo, subset, x, order): 1824 def parentpost(repo, subset, x, order):
1644 return p1(repo, subset, x) 1825 return p1(repo, subset, x)
1826
1645 1827
1646 @predicate('parents([set])', safe=True) 1828 @predicate('parents([set])', safe=True)
1647 def parents(repo, subset, x): 1829 def parents(repo, subset, x):
1648 """ 1830 """
1649 The set of all parents for all changesets in set, or the working directory. 1831 The set of all parents for all changesets in set, or the working directory.
1661 except error.WdirUnsupported: 1843 except error.WdirUnsupported:
1662 up(p.rev() for p in repo[r].parents()) 1844 up(p.rev() for p in repo[r].parents())
1663 ps -= {node.nullrev} 1845 ps -= {node.nullrev}
1664 return subset & ps 1846 return subset & ps
1665 1847
1848
1666 def _phase(repo, subset, *targets): 1849 def _phase(repo, subset, *targets):
1667 """helper to select all rev in <targets> phases""" 1850 """helper to select all rev in <targets> phases"""
1668 return repo._phasecache.getrevset(repo, targets, subset) 1851 return repo._phasecache.getrevset(repo, targets, subset)
1669 1852
1853
1670 @predicate('_phase(idx)', safe=True) 1854 @predicate('_phase(idx)', safe=True)
1671 def phase(repo, subset, x): 1855 def phase(repo, subset, x):
1672 l = getargs(x, 1, 1, ("_phase requires one argument")) 1856 l = getargs(x, 1, 1, "_phase requires one argument")
1673 target = getinteger(l[0], ("_phase expects a number")) 1857 target = getinteger(l[0], "_phase expects a number")
1674 return _phase(repo, subset, target) 1858 return _phase(repo, subset, target)
1859
1675 1860
1676 @predicate('draft()', safe=True) 1861 @predicate('draft()', safe=True)
1677 def draft(repo, subset, x): 1862 def draft(repo, subset, x):
1678 """Changeset in draft phase.""" 1863 """Changeset in draft phase."""
1679 # i18n: "draft" is a keyword 1864 # i18n: "draft" is a keyword
1680 getargs(x, 0, 0, _("draft takes no arguments")) 1865 getargs(x, 0, 0, _("draft takes no arguments"))
1681 target = phases.draft 1866 target = phases.draft
1682 return _phase(repo, subset, target) 1867 return _phase(repo, subset, target)
1683 1868
1869
1684 @predicate('secret()', safe=True) 1870 @predicate('secret()', safe=True)
1685 def secret(repo, subset, x): 1871 def secret(repo, subset, x):
1686 """Changeset in secret phase.""" 1872 """Changeset in secret phase."""
1687 # i18n: "secret" is a keyword 1873 # i18n: "secret" is a keyword
1688 getargs(x, 0, 0, _("secret takes no arguments")) 1874 getargs(x, 0, 0, _("secret takes no arguments"))
1689 target = phases.secret 1875 target = phases.secret
1690 return _phase(repo, subset, target) 1876 return _phase(repo, subset, target)
1691 1877
1878
1692 @predicate('stack([revs])', safe=True) 1879 @predicate('stack([revs])', safe=True)
1693 def stack(repo, subset, x): 1880 def stack(repo, subset, x):
1694 """Experimental revset for the stack of changesets or working directory 1881 """Experimental revset for the stack of changesets or working directory
1695 parent. (EXPERIMENTAL) 1882 parent. (EXPERIMENTAL)
1696 """ 1883 """
1701 for revision in getset(repo, fullreposet(repo), x): 1888 for revision in getset(repo, fullreposet(repo), x):
1702 currentstack = stackmod.getstack(repo, revision) 1889 currentstack = stackmod.getstack(repo, revision)
1703 stacks = stacks + currentstack 1890 stacks = stacks + currentstack
1704 1891
1705 return subset & stacks 1892 return subset & stacks
1893
1706 1894
1707 def parentspec(repo, subset, x, n, order): 1895 def parentspec(repo, subset, x, n, order):
1708 """``set^0`` 1896 """``set^0``
1709 The set. 1897 The set.
1710 ``set^1`` (or ``set^``), ``set^2`` 1898 ``set^1`` (or ``set^``), ``set^2``
1735 parents = repo[r].parents() 1923 parents = repo[r].parents()
1736 if len(parents) == 2: 1924 if len(parents) == 2:
1737 ps.add(parents[1].rev()) 1925 ps.add(parents[1].rev())
1738 return subset & ps 1926 return subset & ps
1739 1927
1928
1740 @predicate('present(set)', safe=True, takeorder=True) 1929 @predicate('present(set)', safe=True, takeorder=True)
1741 def present(repo, subset, x, order): 1930 def present(repo, subset, x, order):
1742 """An empty set, if any revision in set isn't found; otherwise, 1931 """An empty set, if any revision in set isn't found; otherwise,
1743 all revisions in set. 1932 all revisions in set.
1744 1933
1748 """ 1937 """
1749 try: 1938 try:
1750 return getset(repo, subset, x, order) 1939 return getset(repo, subset, x, order)
1751 except error.RepoLookupError: 1940 except error.RepoLookupError:
1752 return baseset() 1941 return baseset()
1942
1753 1943
1754 # for internal use 1944 # for internal use
1755 @predicate('_notpublic', safe=True) 1945 @predicate('_notpublic', safe=True)
1756 def _notpublic(repo, subset, x): 1946 def _notpublic(repo, subset, x):
1757 getargs(x, 0, 0, "_notpublic takes no arguments") 1947 getargs(x, 0, 0, "_notpublic takes no arguments")
1758 return _phase(repo, subset, phases.draft, phases.secret) 1948 return _phase(repo, subset, phases.draft, phases.secret)
1949
1759 1950
1760 # for internal use 1951 # for internal use
1761 @predicate('_phaseandancestors(phasename, set)', safe=True) 1952 @predicate('_phaseandancestors(phasename, set)', safe=True)
1762 def _phaseandancestors(repo, subset, x): 1953 def _phaseandancestors(repo, subset, x):
1763 # equivalent to (phasename() & ancestors(set)) but more efficient 1954 # equivalent to (phasename() & ancestors(set)) but more efficient
1768 1959
1769 draft = phases.draft 1960 draft = phases.draft
1770 secret = phases.secret 1961 secret = phases.secret
1771 phasenamemap = { 1962 phasenamemap = {
1772 '_notpublic': draft, 1963 '_notpublic': draft,
1773 'draft': draft, # follow secret's ancestors 1964 'draft': draft, # follow secret's ancestors
1774 'secret': secret, 1965 'secret': secret,
1775 } 1966 }
1776 if phasename not in phasenamemap: 1967 if phasename not in phasenamemap:
1777 raise error.ParseError('%r is not a valid phasename' % phasename) 1968 raise error.ParseError('%r is not a valid phasename' % phasename)
1778 1969
1782 def cutfunc(rev): 1973 def cutfunc(rev):
1783 return getphase(repo, rev) < minimalphase 1974 return getphase(repo, rev) < minimalphase
1784 1975
1785 revs = dagop.revancestors(repo, s, cutfunc=cutfunc) 1976 revs = dagop.revancestors(repo, s, cutfunc=cutfunc)
1786 1977
1787 if phasename == 'draft': # need to remove secret changesets 1978 if phasename == 'draft': # need to remove secret changesets
1788 revs = revs.filter(lambda r: getphase(repo, r) == draft) 1979 revs = revs.filter(lambda r: getphase(repo, r) == draft)
1789 return subset & revs 1980 return subset & revs
1981
1790 1982
1791 @predicate('public()', safe=True) 1983 @predicate('public()', safe=True)
1792 def public(repo, subset, x): 1984 def public(repo, subset, x):
1793 """Changeset in public phase.""" 1985 """Changeset in public phase."""
1794 # i18n: "public" is a keyword 1986 # i18n: "public" is a keyword
1795 getargs(x, 0, 0, _("public takes no arguments")) 1987 getargs(x, 0, 0, _("public takes no arguments"))
1796 return _phase(repo, subset, phases.public) 1988 return _phase(repo, subset, phases.public)
1797 1989
1990
1798 @predicate('remote([id [,path]])', safe=False) 1991 @predicate('remote([id [,path]])', safe=False)
1799 def remote(repo, subset, x): 1992 def remote(repo, subset, x):
1800 """Local revision that corresponds to the given identifier in a 1993 """Local revision that corresponds to the given identifier in a
1801 remote repository, if present. Here, the '.' identifier is a 1994 remote repository, if present. Here, the '.' identifier is a
1802 synonym for the current local branch. 1995 synonym for the current local branch.
1803 """ 1996 """
1804 1997
1805 from . import hg # avoid start-up nasties 1998 from . import hg # avoid start-up nasties
1999
1806 # i18n: "remote" is a keyword 2000 # i18n: "remote" is a keyword
1807 l = getargs(x, 0, 2, _("remote takes zero, one, or two arguments")) 2001 l = getargs(x, 0, 2, _("remote takes zero, one, or two arguments"))
1808 2002
1809 q = '.' 2003 q = '.'
1810 if len(l) > 0: 2004 if len(l) > 0:
1811 # i18n: "remote" is a keyword 2005 # i18n: "remote" is a keyword
1812 q = getstring(l[0], _("remote requires a string id")) 2006 q = getstring(l[0], _("remote requires a string id"))
1813 if q == '.': 2007 if q == '.':
1814 q = repo['.'].branch() 2008 q = repo['.'].branch()
1815 2009
1816 dest = '' 2010 dest = ''
1828 r = repo[n].rev() 2022 r = repo[n].rev()
1829 if r in subset: 2023 if r in subset:
1830 return baseset([r]) 2024 return baseset([r])
1831 return baseset() 2025 return baseset()
1832 2026
2027
1833 @predicate('removes(pattern)', safe=True, weight=30) 2028 @predicate('removes(pattern)', safe=True, weight=30)
1834 def removes(repo, subset, x): 2029 def removes(repo, subset, x):
1835 """Changesets which remove files matching pattern. 2030 """Changesets which remove files matching pattern.
1836 2031
1837 The pattern without explicit kind like ``glob:`` is expected to be 2032 The pattern without explicit kind like ``glob:`` is expected to be
1839 directory. 2034 directory.
1840 """ 2035 """
1841 # i18n: "removes" is a keyword 2036 # i18n: "removes" is a keyword
1842 pat = getstring(x, _("removes requires a pattern")) 2037 pat = getstring(x, _("removes requires a pattern"))
1843 return checkstatus(repo, subset, pat, 2) 2038 return checkstatus(repo, subset, pat, 2)
2039
1844 2040
1845 @predicate('rev(number)', safe=True) 2041 @predicate('rev(number)', safe=True)
1846 def rev(repo, subset, x): 2042 def rev(repo, subset, x):
1847 """Revision with the given numeric identifier. 2043 """Revision with the given numeric identifier.
1848 """ 2044 """
1856 raise error.ParseError(_("rev expects a number")) 2052 raise error.ParseError(_("rev expects a number"))
1857 if l not in repo.changelog and l not in _virtualrevs: 2053 if l not in repo.changelog and l not in _virtualrevs:
1858 return baseset() 2054 return baseset()
1859 return subset & baseset([l]) 2055 return subset & baseset([l])
1860 2056
2057
1861 @predicate('_rev(number)', safe=True) 2058 @predicate('_rev(number)', safe=True)
1862 def _rev(repo, subset, x): 2059 def _rev(repo, subset, x):
1863 # internal version of "rev(x)" that raise error if "x" is invalid 2060 # internal version of "rev(x)" that raise error if "x" is invalid
1864 # i18n: "rev" is a keyword 2061 # i18n: "rev" is a keyword
1865 l = getargs(x, 1, 1, _("rev requires one argument")) 2062 l = getargs(x, 1, 1, _("rev requires one argument"))
1867 # i18n: "rev" is a keyword 2064 # i18n: "rev" is a keyword
1868 l = int(getstring(l[0], _("rev requires a number"))) 2065 l = int(getstring(l[0], _("rev requires a number")))
1869 except (TypeError, ValueError): 2066 except (TypeError, ValueError):
1870 # i18n: "rev" is a keyword 2067 # i18n: "rev" is a keyword
1871 raise error.ParseError(_("rev expects a number")) 2068 raise error.ParseError(_("rev expects a number"))
1872 repo.changelog.node(l) # check that the rev exists 2069 repo.changelog.node(l) # check that the rev exists
1873 return subset & baseset([l]) 2070 return subset & baseset([l])
2071
1874 2072
1875 @predicate('revset(set)', safe=True, takeorder=True) 2073 @predicate('revset(set)', safe=True, takeorder=True)
1876 def revsetpredicate(repo, subset, x, order): 2074 def revsetpredicate(repo, subset, x, order):
1877 """Strictly interpret the content as a revset. 2075 """Strictly interpret the content as a revset.
1878 2076
1879 The content of this special predicate will be strictly interpreted as a 2077 The content of this special predicate will be strictly interpreted as a
1880 revset. For example, ``revset(id(0))`` will be interpreted as "id(0)" 2078 revset. For example, ``revset(id(0))`` will be interpreted as "id(0)"
1881 without possible ambiguity with a "id(0)" bookmark or tag. 2079 without possible ambiguity with a "id(0)" bookmark or tag.
1882 """ 2080 """
1883 return getset(repo, subset, x, order) 2081 return getset(repo, subset, x, order)
2082
1884 2083
1885 @predicate('matching(revision [, field])', safe=True) 2084 @predicate('matching(revision [, field])', safe=True)
1886 def matching(repo, subset, x): 2085 def matching(repo, subset, x):
1887 """Changesets in which a given set of fields match the set of fields in the 2086 """Changesets in which a given set of fields match the set of fields in the
1888 selected revision or set. 2087 selected revision or set.
1912 2111
1913 revs = getset(repo, fullreposet(repo), l[0]) 2112 revs = getset(repo, fullreposet(repo), l[0])
1914 2113
1915 fieldlist = ['metadata'] 2114 fieldlist = ['metadata']
1916 if len(l) > 1: 2115 if len(l) > 1:
1917 fieldlist = getstring(l[1], 2116 fieldlist = getstring(
1918 # i18n: "matching" is a keyword 2117 l[1],
1919 _("matching requires a string " 2118 # i18n: "matching" is a keyword
1920 "as its second argument")).split() 2119 _("matching requires a string " "as its second argument"),
2120 ).split()
1921 2121
1922 # Make sure that there are no repeated fields, 2122 # Make sure that there are no repeated fields,
1923 # expand the 'special' 'metadata' field type 2123 # expand the 'special' 'metadata' field type
1924 # and check the 'files' whenever we check the 'diff' 2124 # and check the 'files' whenever we check the 'diff'
1925 fields = [] 2125 fields = []
1941 fields.discard('summary') 2141 fields.discard('summary')
1942 2142
1943 # We may want to match more than one field 2143 # We may want to match more than one field
1944 # Not all fields take the same amount of time to be matched 2144 # Not all fields take the same amount of time to be matched
1945 # Sort the selected fields in order of increasing matching cost 2145 # Sort the selected fields in order of increasing matching cost
1946 fieldorder = ['phase', 'parents', 'user', 'date', 'branch', 'summary', 2146 fieldorder = [
1947 'files', 'description', 'substate', 'diff'] 2147 'phase',
2148 'parents',
2149 'user',
2150 'date',
2151 'branch',
2152 'summary',
2153 'files',
2154 'description',
2155 'substate',
2156 'diff',
2157 ]
2158
1948 def fieldkeyfunc(f): 2159 def fieldkeyfunc(f):
1949 try: 2160 try:
1950 return fieldorder.index(f) 2161 return fieldorder.index(f)
1951 except ValueError: 2162 except ValueError:
1952 # assume an unknown field is very costly 2163 # assume an unknown field is very costly
1953 return len(fieldorder) 2164 return len(fieldorder)
2165
1954 fields = list(fields) 2166 fields = list(fields)
1955 fields.sort(key=fieldkeyfunc) 2167 fields.sort(key=fieldkeyfunc)
1956 2168
1957 # Each field will be matched with its own "getfield" function 2169 # Each field will be matched with its own "getfield" function
1958 # which will be added to the getfieldfuncs array of functions 2170 # which will be added to the getfieldfuncs array of functions
1965 'files': lambda r: repo[r].files(), 2177 'files': lambda r: repo[r].files(),
1966 'parents': lambda r: repo[r].parents(), 2178 'parents': lambda r: repo[r].parents(),
1967 'phase': lambda r: repo[r].phase(), 2179 'phase': lambda r: repo[r].phase(),
1968 'substate': lambda r: repo[r].substate, 2180 'substate': lambda r: repo[r].substate,
1969 'summary': lambda r: repo[r].description().splitlines()[0], 2181 'summary': lambda r: repo[r].description().splitlines()[0],
1970 'diff': lambda r: list(repo[r].diff( 2182 'diff': lambda r: list(
1971 opts=diffutil.diffallopts(repo.ui, {'git': True}))), 2183 repo[r].diff(opts=diffutil.diffallopts(repo.ui, {'git': True}))
2184 ),
1972 } 2185 }
1973 for info in fields: 2186 for info in fields:
1974 getfield = _funcs.get(info, None) 2187 getfield = _funcs.get(info, None)
1975 if getfield is None: 2188 if getfield is None:
1976 raise error.ParseError( 2189 raise error.ParseError(
1977 # i18n: "matching" is a keyword 2190 # i18n: "matching" is a keyword
1978 _("unexpected field name passed to matching: %s") % info) 2191 _("unexpected field name passed to matching: %s")
2192 % info
2193 )
1979 getfieldfuncs.append(getfield) 2194 getfieldfuncs.append(getfield)
1980 # convert the getfield array of functions into a "getinfo" function 2195 # convert the getfield array of functions into a "getinfo" function
1981 # which returns an array of field values (or a single value if there 2196 # which returns an array of field values (or a single value if there
1982 # is only one field to match) 2197 # is only one field to match)
1983 getinfo = lambda r: [f(r) for f in getfieldfuncs] 2198 getinfo = lambda r: [f(r) for f in getfieldfuncs]
1993 return True 2208 return True
1994 return False 2209 return False
1995 2210
1996 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs)) 2211 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs))
1997 2212
2213
1998 @predicate('reverse(set)', safe=True, takeorder=True, weight=0) 2214 @predicate('reverse(set)', safe=True, takeorder=True, weight=0)
1999 def reverse(repo, subset, x, order): 2215 def reverse(repo, subset, x, order):
2000 """Reverse order of set. 2216 """Reverse order of set.
2001 """ 2217 """
2002 l = getset(repo, subset, x, order) 2218 l = getset(repo, subset, x, order)
2003 if order == defineorder: 2219 if order == defineorder:
2004 l.reverse() 2220 l.reverse()
2005 return l 2221 return l
2006 2222
2223
2007 @predicate('roots(set)', safe=True) 2224 @predicate('roots(set)', safe=True)
2008 def roots(repo, subset, x): 2225 def roots(repo, subset, x):
2009 """Changesets in set with no parent changeset in set. 2226 """Changesets in set with no parent changeset in set.
2010 """ 2227 """
2011 s = getset(repo, fullreposet(repo), x) 2228 s = getset(repo, fullreposet(repo), x)
2012 parents = repo.changelog.parentrevs 2229 parents = repo.changelog.parentrevs
2230
2013 def filter(r): 2231 def filter(r):
2014 for p in parents(r): 2232 for p in parents(r):
2015 if 0 <= p and p in s: 2233 if 0 <= p and p in s:
2016 return False 2234 return False
2017 return True 2235 return True
2236
2018 return subset & s.filter(filter, condrepr='<roots>') 2237 return subset & s.filter(filter, condrepr='<roots>')
2238
2019 2239
2020 _sortkeyfuncs = { 2240 _sortkeyfuncs = {
2021 'rev': lambda c: c.rev(), 2241 'rev': lambda c: c.rev(),
2022 'branch': lambda c: c.branch(), 2242 'branch': lambda c: c.branch(),
2023 'desc': lambda c: c.description(), 2243 'desc': lambda c: c.description(),
2024 'user': lambda c: c.user(), 2244 'user': lambda c: c.user(),
2025 'author': lambda c: c.user(), 2245 'author': lambda c: c.user(),
2026 'date': lambda c: c.date()[0], 2246 'date': lambda c: c.date()[0],
2027 } 2247 }
2248
2028 2249
2029 def _getsortargs(x): 2250 def _getsortargs(x):
2030 """Parse sort options into (set, [(key, reverse)], opts)""" 2251 """Parse sort options into (set, [(key, reverse)], opts)"""
2031 args = getargsdict(x, 'sort', 'set keys topo.firstbranch') 2252 args = getargsdict(x, 'sort', 'set keys topo.firstbranch')
2032 if 'set' not in args: 2253 if 'set' not in args:
2038 keys = getstring(args['keys'], _("sort spec must be a string")) 2259 keys = getstring(args['keys'], _("sort spec must be a string"))
2039 2260
2040 keyflags = [] 2261 keyflags = []
2041 for k in keys.split(): 2262 for k in keys.split():
2042 fk = k 2263 fk = k
2043 reverse = (k.startswith('-')) 2264 reverse = k.startswith('-')
2044 if reverse: 2265 if reverse:
2045 k = k[1:] 2266 k = k[1:]
2046 if k not in _sortkeyfuncs and k != 'topo': 2267 if k not in _sortkeyfuncs and k != 'topo':
2047 raise error.ParseError( 2268 raise error.ParseError(
2048 _("unknown sort key %r") % pycompat.bytestr(fk)) 2269 _("unknown sort key %r") % pycompat.bytestr(fk)
2270 )
2049 keyflags.append((k, reverse)) 2271 keyflags.append((k, reverse))
2050 2272
2051 if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags): 2273 if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags):
2052 # i18n: "topo" is a keyword 2274 # i18n: "topo" is a keyword
2053 raise error.ParseError(_('topo sort order cannot be combined ' 2275 raise error.ParseError(
2054 'with other sort keys')) 2276 _('topo sort order cannot be combined ' 'with other sort keys')
2277 )
2055 2278
2056 opts = {} 2279 opts = {}
2057 if 'topo.firstbranch' in args: 2280 if 'topo.firstbranch' in args:
2058 if any(k == 'topo' for k, reverse in keyflags): 2281 if any(k == 'topo' for k, reverse in keyflags):
2059 opts['topo.firstbranch'] = args['topo.firstbranch'] 2282 opts['topo.firstbranch'] = args['topo.firstbranch']
2060 else: 2283 else:
2061 # i18n: "topo" and "topo.firstbranch" are keywords 2284 # i18n: "topo" and "topo.firstbranch" are keywords
2062 raise error.ParseError(_('topo.firstbranch can only be used ' 2285 raise error.ParseError(
2063 'when using the topo sort key')) 2286 _(
2287 'topo.firstbranch can only be used '
2288 'when using the topo sort key'
2289 )
2290 )
2064 2291
2065 return args['set'], keyflags, opts 2292 return args['set'], keyflags, opts
2066 2293
2067 @predicate('sort(set[, [-]key... [, ...]])', safe=True, takeorder=True, 2294
2068 weight=10) 2295 @predicate(
2296 'sort(set[, [-]key... [, ...]])', safe=True, takeorder=True, weight=10
2297 )
2069 def sort(repo, subset, x, order): 2298 def sort(repo, subset, x, order):
2070 """Sort set by keys. The default sort order is ascending, specify a key 2299 """Sort set by keys. The default sort order is ascending, specify a key
2071 as ``-key`` to sort in descending order. 2300 as ``-key`` to sort in descending order.
2072 2301
2073 The keys can be: 2302 The keys can be:
2094 return revs 2323 return revs
2095 elif keyflags[0][0] == "topo": 2324 elif keyflags[0][0] == "topo":
2096 firstbranch = () 2325 firstbranch = ()
2097 if 'topo.firstbranch' in opts: 2326 if 'topo.firstbranch' in opts:
2098 firstbranch = getset(repo, subset, opts['topo.firstbranch']) 2327 firstbranch = getset(repo, subset, opts['topo.firstbranch'])
2099 revs = baseset(dagop.toposort(revs, repo.changelog.parentrevs, 2328 revs = baseset(
2100 firstbranch), 2329 dagop.toposort(revs, repo.changelog.parentrevs, firstbranch),
2101 istopo=True) 2330 istopo=True,
2331 )
2102 if keyflags[0][1]: 2332 if keyflags[0][1]:
2103 revs.reverse() 2333 revs.reverse()
2104 return revs 2334 return revs
2105 2335
2106 # sort() is guaranteed to be stable 2336 # sort() is guaranteed to be stable
2107 ctxs = [repo[r] for r in revs] 2337 ctxs = [repo[r] for r in revs]
2108 for k, reverse in reversed(keyflags): 2338 for k, reverse in reversed(keyflags):
2109 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse) 2339 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse)
2110 return baseset([c.rev() for c in ctxs]) 2340 return baseset([c.rev() for c in ctxs])
2111 2341
2342
2112 @predicate('subrepo([pattern])') 2343 @predicate('subrepo([pattern])')
2113 def subrepo(repo, subset, x): 2344 def subrepo(repo, subset, x):
2114 """Changesets that add, modify or remove the given subrepo. If no subrepo 2345 """Changesets that add, modify or remove the given subrepo. If no subrepo
2115 pattern is named, any subrepo changes are returned. 2346 pattern is named, any subrepo changes are returned.
2116 """ 2347 """
2150 return any(submatches(c.p1().substate.keys())) 2381 return any(submatches(c.p1().substate.keys()))
2151 2382
2152 return False 2383 return False
2153 2384
2154 return subset.filter(matches, condrepr=('<subrepo %r>', pat)) 2385 return subset.filter(matches, condrepr=('<subrepo %r>', pat))
2386
2155 2387
2156 def _mapbynodefunc(repo, s, f): 2388 def _mapbynodefunc(repo, s, f):
2157 """(repo, smartset, [node] -> [node]) -> smartset 2389 """(repo, smartset, [node] -> [node]) -> smartset
2158 2390
2159 Helper method to map a smartset to another smartset given a function only 2391 Helper method to map a smartset to another smartset given a function only
2164 torev = cl.rev 2396 torev = cl.rev
2165 tonode = cl.node 2397 tonode = cl.node
2166 nodemap = cl.nodemap 2398 nodemap = cl.nodemap
2167 result = set(torev(n) for n in f(tonode(r) for r in s) if n in nodemap) 2399 result = set(torev(n) for n in f(tonode(r) for r in s) if n in nodemap)
2168 return smartset.baseset(result - repo.changelog.filteredrevs) 2400 return smartset.baseset(result - repo.changelog.filteredrevs)
2401
2169 2402
2170 @predicate('successors(set)', safe=True) 2403 @predicate('successors(set)', safe=True)
2171 def successors(repo, subset, x): 2404 def successors(repo, subset, x):
2172 """All successors for set, including the given set themselves""" 2405 """All successors for set, including the given set themselves"""
2173 s = getset(repo, fullreposet(repo), x) 2406 s = getset(repo, fullreposet(repo), x)
2174 f = lambda nodes: obsutil.allsuccessors(repo.obsstore, nodes) 2407 f = lambda nodes: obsutil.allsuccessors(repo.obsstore, nodes)
2175 d = _mapbynodefunc(repo, s, f) 2408 d = _mapbynodefunc(repo, s, f)
2176 return subset & d 2409 return subset & d
2177 2410
2411
2178 def _substringmatcher(pattern, casesensitive=True): 2412 def _substringmatcher(pattern, casesensitive=True):
2179 kind, pattern, matcher = stringutil.stringmatcher( 2413 kind, pattern, matcher = stringutil.stringmatcher(
2180 pattern, casesensitive=casesensitive) 2414 pattern, casesensitive=casesensitive
2415 )
2181 if kind == 'literal': 2416 if kind == 'literal':
2182 if not casesensitive: 2417 if not casesensitive:
2183 pattern = encoding.lower(pattern) 2418 pattern = encoding.lower(pattern)
2184 matcher = lambda s: pattern in encoding.lower(s) 2419 matcher = lambda s: pattern in encoding.lower(s)
2185 else: 2420 else:
2186 matcher = lambda s: pattern in s 2421 matcher = lambda s: pattern in s
2187 return kind, pattern, matcher 2422 return kind, pattern, matcher
2188 2423
2424
2189 @predicate('tag([name])', safe=True) 2425 @predicate('tag([name])', safe=True)
2190 def tag(repo, subset, x): 2426 def tag(repo, subset, x):
2191 """The specified tag by name, or all tagged revisions if no name is given. 2427 """The specified tag by name, or all tagged revisions if no name is given.
2192 2428
2193 Pattern matching is supported for `name`. See 2429 Pattern matching is supported for `name`. See
2195 """ 2431 """
2196 # i18n: "tag" is a keyword 2432 # i18n: "tag" is a keyword
2197 args = getargs(x, 0, 1, _("tag takes one or no arguments")) 2433 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
2198 cl = repo.changelog 2434 cl = repo.changelog
2199 if args: 2435 if args:
2200 pattern = getstring(args[0], 2436 pattern = getstring(
2201 # i18n: "tag" is a keyword 2437 args[0],
2202 _('the argument to tag must be a string')) 2438 # i18n: "tag" is a keyword
2439 _('the argument to tag must be a string'),
2440 )
2203 kind, pattern, matcher = stringutil.stringmatcher(pattern) 2441 kind, pattern, matcher = stringutil.stringmatcher(pattern)
2204 if kind == 'literal': 2442 if kind == 'literal':
2205 # avoid resolving all tags 2443 # avoid resolving all tags
2206 tn = repo._tagscache.tags.get(pattern, None) 2444 tn = repo._tagscache.tags.get(pattern, None)
2207 if tn is None: 2445 if tn is None:
2208 raise error.RepoLookupError(_("tag '%s' does not exist") 2446 raise error.RepoLookupError(
2209 % pattern) 2447 _("tag '%s' does not exist") % pattern
2448 )
2210 s = {repo[tn].rev()} 2449 s = {repo[tn].rev()}
2211 else: 2450 else:
2212 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)} 2451 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)}
2213 else: 2452 else:
2214 s = {cl.rev(n) for t, n in repo.tagslist() if t != 'tip'} 2453 s = {cl.rev(n) for t, n in repo.tagslist() if t != 'tip'}
2215 return subset & s 2454 return subset & s
2216 2455
2456
2217 @predicate('tagged', safe=True) 2457 @predicate('tagged', safe=True)
2218 def tagged(repo, subset, x): 2458 def tagged(repo, subset, x):
2219 return tag(repo, subset, x) 2459 return tag(repo, subset, x)
2460
2220 2461
2221 @predicate('orphan()', safe=True) 2462 @predicate('orphan()', safe=True)
2222 def orphan(repo, subset, x): 2463 def orphan(repo, subset, x):
2223 """Non-obsolete changesets with obsolete ancestors. (EXPERIMENTAL) 2464 """Non-obsolete changesets with obsolete ancestors. (EXPERIMENTAL)
2224 """ 2465 """
2234 2475
2235 Pattern matching is supported for `string`. See 2476 Pattern matching is supported for `string`. See
2236 :hg:`help revisions.patterns`. 2477 :hg:`help revisions.patterns`.
2237 """ 2478 """
2238 return author(repo, subset, x) 2479 return author(repo, subset, x)
2480
2239 2481
2240 @predicate('wdir()', safe=True, weight=0) 2482 @predicate('wdir()', safe=True, weight=0)
2241 def wdir(repo, subset, x): 2483 def wdir(repo, subset, x):
2242 """Working directory. (EXPERIMENTAL)""" 2484 """Working directory. (EXPERIMENTAL)"""
2243 # i18n: "wdir" is a keyword 2485 # i18n: "wdir" is a keyword
2244 getargs(x, 0, 0, _("wdir takes no arguments")) 2486 getargs(x, 0, 0, _("wdir takes no arguments"))
2245 if node.wdirrev in subset or isinstance(subset, fullreposet): 2487 if node.wdirrev in subset or isinstance(subset, fullreposet):
2246 return baseset([node.wdirrev]) 2488 return baseset([node.wdirrev])
2247 return baseset() 2489 return baseset()
2490
2248 2491
2249 def _orderedlist(repo, subset, x): 2492 def _orderedlist(repo, subset, x):
2250 s = getstring(x, "internal error") 2493 s = getstring(x, "internal error")
2251 if not s: 2494 if not s:
2252 return baseset() 2495 return baseset()
2266 revs = stringset(repo, subset, t, defineorder) 2509 revs = stringset(repo, subset, t, defineorder)
2267 2510
2268 for r in revs: 2511 for r in revs:
2269 if r in seen: 2512 if r in seen:
2270 continue 2513 continue
2271 if (r in subset 2514 if (
2272 or r in _virtualrevs and isinstance(subset, fullreposet)): 2515 r in subset
2516 or r in _virtualrevs
2517 and isinstance(subset, fullreposet)
2518 ):
2273 ls.append(r) 2519 ls.append(r)
2274 seen.add(r) 2520 seen.add(r)
2275 return baseset(ls) 2521 return baseset(ls)
2522
2276 2523
2277 # for internal use 2524 # for internal use
2278 @predicate('_list', safe=True, takeorder=True) 2525 @predicate('_list', safe=True, takeorder=True)
2279 def _list(repo, subset, x, order): 2526 def _list(repo, subset, x, order):
2280 if order == followorder: 2527 if order == followorder:
2281 # slow path to take the subset order 2528 # slow path to take the subset order
2282 return subset & _orderedlist(repo, fullreposet(repo), x) 2529 return subset & _orderedlist(repo, fullreposet(repo), x)
2283 else: 2530 else:
2284 return _orderedlist(repo, subset, x) 2531 return _orderedlist(repo, subset, x)
2285 2532
2533
2286 def _orderedintlist(repo, subset, x): 2534 def _orderedintlist(repo, subset, x):
2287 s = getstring(x, "internal error") 2535 s = getstring(x, "internal error")
2288 if not s: 2536 if not s:
2289 return baseset() 2537 return baseset()
2290 ls = [int(r) for r in s.split('\0')] 2538 ls = [int(r) for r in s.split('\0')]
2291 s = subset 2539 s = subset
2292 return baseset([r for r in ls if r in s]) 2540 return baseset([r for r in ls if r in s])
2541
2293 2542
2294 # for internal use 2543 # for internal use
2295 @predicate('_intlist', safe=True, takeorder=True, weight=0) 2544 @predicate('_intlist', safe=True, takeorder=True, weight=0)
2296 def _intlist(repo, subset, x, order): 2545 def _intlist(repo, subset, x, order):
2297 if order == followorder: 2546 if order == followorder:
2298 # slow path to take the subset order 2547 # slow path to take the subset order
2299 return subset & _orderedintlist(repo, fullreposet(repo), x) 2548 return subset & _orderedintlist(repo, fullreposet(repo), x)
2300 else: 2549 else:
2301 return _orderedintlist(repo, subset, x) 2550 return _orderedintlist(repo, subset, x)
2302 2551
2552
2303 def _orderedhexlist(repo, subset, x): 2553 def _orderedhexlist(repo, subset, x):
2304 s = getstring(x, "internal error") 2554 s = getstring(x, "internal error")
2305 if not s: 2555 if not s:
2306 return baseset() 2556 return baseset()
2307 cl = repo.changelog 2557 cl = repo.changelog
2308 ls = [cl.rev(node.bin(r)) for r in s.split('\0')] 2558 ls = [cl.rev(node.bin(r)) for r in s.split('\0')]
2309 s = subset 2559 s = subset
2310 return baseset([r for r in ls if r in s]) 2560 return baseset([r for r in ls if r in s])
2311 2561
2562
2312 # for internal use 2563 # for internal use
2313 @predicate('_hexlist', safe=True, takeorder=True) 2564 @predicate('_hexlist', safe=True, takeorder=True)
2314 def _hexlist(repo, subset, x, order): 2565 def _hexlist(repo, subset, x, order):
2315 if order == followorder: 2566 if order == followorder:
2316 # slow path to take the subset order 2567 # slow path to take the subset order
2317 return subset & _orderedhexlist(repo, fullreposet(repo), x) 2568 return subset & _orderedhexlist(repo, fullreposet(repo), x)
2318 else: 2569 else:
2319 return _orderedhexlist(repo, subset, x) 2570 return _orderedhexlist(repo, subset, x)
2571
2320 2572
2321 methods = { 2573 methods = {
2322 "range": rangeset, 2574 "range": rangeset,
2323 "rangeall": rangeall, 2575 "rangeall": rangeall,
2324 "rangepre": rangepre, 2576 "rangepre": rangepre,
2346 subscriptrelations = { 2598 subscriptrelations = {
2347 "g": generationsrel, 2599 "g": generationsrel,
2348 "generations": generationsrel, 2600 "generations": generationsrel,
2349 } 2601 }
2350 2602
2603
2351 def lookupfn(repo): 2604 def lookupfn(repo):
2352 return lambda symbol: scmutil.isrevsymbol(repo, symbol) 2605 return lambda symbol: scmutil.isrevsymbol(repo, symbol)
2606
2353 2607
2354 def match(ui, spec, lookup=None): 2608 def match(ui, spec, lookup=None):
2355 """Create a matcher for a single revision spec""" 2609 """Create a matcher for a single revision spec"""
2356 return matchany(ui, [spec], lookup=lookup) 2610 return matchany(ui, [spec], lookup=lookup)
2357 2611
2612
2358 def matchany(ui, specs, lookup=None, localalias=None): 2613 def matchany(ui, specs, lookup=None, localalias=None):
2359 """Create a matcher that will include any revisions matching one of the 2614 """Create a matcher that will include any revisions matching one of the
2360 given specs 2615 given specs
2361 2616
2362 If lookup function is not None, the parser will first attempt to handle 2617 If lookup function is not None, the parser will first attempt to handle
2364 2619
2365 If localalias is not None, it is a dict {name: definitionstring}. It takes 2620 If localalias is not None, it is a dict {name: definitionstring}. It takes
2366 precedence over [revsetalias] config section. 2621 precedence over [revsetalias] config section.
2367 """ 2622 """
2368 if not specs: 2623 if not specs:
2624
2369 def mfunc(repo, subset=None): 2625 def mfunc(repo, subset=None):
2370 return baseset() 2626 return baseset()
2627
2371 return mfunc 2628 return mfunc
2372 if not all(specs): 2629 if not all(specs):
2373 raise error.ParseError(_("empty query")) 2630 raise error.ParseError(_("empty query"))
2374 if len(specs) == 1: 2631 if len(specs) == 1:
2375 tree = revsetlang.parse(specs[0], lookup) 2632 tree = revsetlang.parse(specs[0], lookup)
2376 else: 2633 else:
2377 tree = ('or', 2634 tree = (
2378 ('list',) + tuple(revsetlang.parse(s, lookup) for s in specs)) 2635 'or',
2636 ('list',) + tuple(revsetlang.parse(s, lookup) for s in specs),
2637 )
2379 2638
2380 aliases = [] 2639 aliases = []
2381 warn = None 2640 warn = None
2382 if ui: 2641 if ui:
2383 aliases.extend(ui.configitems('revsetalias')) 2642 aliases.extend(ui.configitems('revsetalias'))
2389 tree = revsetlang.foldconcat(tree) 2648 tree = revsetlang.foldconcat(tree)
2390 tree = revsetlang.analyze(tree) 2649 tree = revsetlang.analyze(tree)
2391 tree = revsetlang.optimize(tree) 2650 tree = revsetlang.optimize(tree)
2392 return makematcher(tree) 2651 return makematcher(tree)
2393 2652
2653
2394 def makematcher(tree): 2654 def makematcher(tree):
2395 """Create a matcher from an evaluatable tree""" 2655 """Create a matcher from an evaluatable tree"""
2656
2396 def mfunc(repo, subset=None, order=None): 2657 def mfunc(repo, subset=None, order=None):
2397 if order is None: 2658 if order is None:
2398 if subset is None: 2659 if subset is None:
2399 order = defineorder # 'x' 2660 order = defineorder # 'x'
2400 else: 2661 else:
2401 order = followorder # 'subset & x' 2662 order = followorder # 'subset & x'
2402 if subset is None: 2663 if subset is None:
2403 subset = fullreposet(repo) 2664 subset = fullreposet(repo)
2404 return getset(repo, subset, tree, order) 2665 return getset(repo, subset, tree, order)
2666
2405 return mfunc 2667 return mfunc
2668
2406 2669
2407 def loadpredicate(ui, extname, registrarobj): 2670 def loadpredicate(ui, extname, registrarobj):
2408 """Load revset predicates from specified registrarobj 2671 """Load revset predicates from specified registrarobj
2409 """ 2672 """
2410 for name, func in registrarobj._table.iteritems(): 2673 for name, func in registrarobj._table.iteritems():
2411 symbols[name] = func 2674 symbols[name] = func
2412 if func._safe: 2675 if func._safe:
2413 safesymbols.add(name) 2676 safesymbols.add(name)
2414 2677
2678
2415 # load built-in predicates explicitly to setup safesymbols 2679 # load built-in predicates explicitly to setup safesymbols
2416 loadpredicate(None, None, predicate) 2680 loadpredicate(None, None, predicate)
2417 2681
2418 # tell hggettext to extract docstrings from these functions: 2682 # tell hggettext to extract docstrings from these functions:
2419 i18nfunctions = symbols.values() 2683 i18nfunctions = symbols.values()