Mercurial > hg
comparison mercurial/revset.py @ 43077:687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Done with
python3.7 contrib/byteify-strings.py -i $(hg files 'set:mercurial/**.py - mercurial/thirdparty/** + hgext/**.py - hgext/fsmonitor/pywatchman/** - mercurial/__init__.py')
black -l 80 -t py33 -S $(hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/**')
# skip-blame mass-reformatting only
Differential Revision: https://phab.mercurial-scm.org/D6972
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:48:39 -0400 |
parents | 2372284d9457 |
children | c59eb1560c44 |
comparison
equal
deleted
inserted
replaced
43076:2372284d9457 | 43077:687b865b95ad |
---|---|
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 = b'any' # don't care the order, could be even random-shuffled |
97 defineorder = 'define' # ALWAYS redefine, or ALWAYS follow the current order | 97 defineorder = b'define' # ALWAYS redefine, or ALWAYS follow the current order |
98 followorder = 'follow' # MUST follow the current order | 98 followorder = b'follow' # MUST follow the current order |
99 | 99 |
100 # helpers | 100 # helpers |
101 | 101 |
102 | 102 |
103 def getset(repo, subset, x, order=defineorder): | 103 def getset(repo, subset, x, order=defineorder): |
104 if not x: | 104 if not x: |
105 raise error.ParseError(_("missing argument")) | 105 raise error.ParseError(_(b"missing argument")) |
106 return methods[x[0]](repo, subset, *x[1:], order=order) | 106 return methods[x[0]](repo, subset, *x[1:], order=order) |
107 | 107 |
108 | 108 |
109 def _getrevsource(repo, r): | 109 def _getrevsource(repo, r): |
110 extra = repo[r].extra() | 110 extra = repo[r].extra() |
111 for label in ('source', 'transplant_source', 'rebase_source'): | 111 for label in (b'source', b'transplant_source', b'rebase_source'): |
112 if label in extra: | 112 if label in extra: |
113 try: | 113 try: |
114 return repo[extra[label]].rev() | 114 return repo[extra[label]].rev() |
115 except error.RepoLookupError: | 115 except error.RepoLookupError: |
116 pass | 116 pass |
124 # operator methods | 124 # operator methods |
125 | 125 |
126 | 126 |
127 def stringset(repo, subset, x, order): | 127 def stringset(repo, subset, x, order): |
128 if not x: | 128 if not x: |
129 raise error.ParseError(_("empty string is not a valid revision")) | 129 raise error.ParseError(_(b"empty string is not a valid revision")) |
130 x = scmutil.intrev(scmutil.revsymbol(repo, x)) | 130 x = scmutil.intrev(scmutil.revsymbol(repo, x)) |
131 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): |
132 return baseset([x]) | 132 return baseset([x]) |
133 return baseset() | 133 return baseset() |
134 | 134 |
244 def notset(repo, subset, x, order): | 244 def notset(repo, subset, x, order): |
245 return subset - getset(repo, subset, x, anyorder) | 245 return subset - getset(repo, subset, x, anyorder) |
246 | 246 |
247 | 247 |
248 def relationset(repo, subset, x, y, order): | 248 def relationset(repo, subset, x, y, order): |
249 raise error.ParseError(_("can't use a relation in this context")) | 249 raise error.ParseError(_(b"can't use a relation in this context")) |
250 | 250 |
251 | 251 |
252 def _splitrange(a, b): | 252 def _splitrange(a, b): |
253 """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 |
254 tuples of numbers for use as startdepth and stopdepth arguments of | 254 tuples of numbers for use as startdepth and stopdepth arguments of |
283 def generationsrel(repo, subset, x, rel, z, order): | 283 def generationsrel(repo, subset, x, rel, z, order): |
284 # TODO: rewrite tests, and drop startdepth argument from ancestors() and | 284 # TODO: rewrite tests, and drop startdepth argument from ancestors() and |
285 # descendants() predicates | 285 # descendants() predicates |
286 a, b = getintrange( | 286 a, b = getintrange( |
287 z, | 287 z, |
288 _('relation subscript must be an integer or a range'), | 288 _(b'relation subscript must be an integer or a range'), |
289 _('relation subscript bounds must be integers'), | 289 _(b'relation subscript bounds must be integers'), |
290 deffirst=-(dagop.maxlogdepth - 1), | 290 deffirst=-(dagop.maxlogdepth - 1), |
291 deflast=+(dagop.maxlogdepth - 1), | 291 deflast=+(dagop.maxlogdepth - 1), |
292 ) | 292 ) |
293 (ancstart, ancstop), (descstart, descstop) = _splitrange(a, b) | 293 (ancstart, ancstop), (descstart, descstop) = _splitrange(a, b) |
294 | 294 |
321 relnames = [r for r in subscriptrelations.keys() if len(r) > 1] | 321 relnames = [r for r in subscriptrelations.keys() if len(r) > 1] |
322 raise error.UnknownIdentifier(rel, relnames) | 322 raise error.UnknownIdentifier(rel, relnames) |
323 | 323 |
324 | 324 |
325 def subscriptset(repo, subset, x, y, order): | 325 def subscriptset(repo, subset, x, y, order): |
326 raise error.ParseError(_("can't use a subscript in this context")) | 326 raise error.ParseError(_(b"can't use a subscript in this context")) |
327 | 327 |
328 | 328 |
329 def listset(repo, subset, *xs, **opts): | 329 def listset(repo, subset, *xs, **opts): |
330 raise error.ParseError( | 330 raise error.ParseError( |
331 _("can't use a list in this context"), | 331 _(b"can't use a list in this context"), |
332 hint=_('see \'hg help "revsets.x or y"\''), | 332 hint=_(b'see \'hg help "revsets.x or y"\''), |
333 ) | 333 ) |
334 | 334 |
335 | 335 |
336 def keyvaluepair(repo, subset, k, v, order): | 336 def keyvaluepair(repo, subset, k, v, order): |
337 raise error.ParseError(_("can't use a key-value pair in this context")) | 337 raise error.ParseError(_(b"can't use a key-value pair in this context")) |
338 | 338 |
339 | 339 |
340 def func(repo, subset, a, b, order): | 340 def func(repo, subset, a, b, order): |
341 f = getsymbol(a) | 341 f = getsymbol(a) |
342 if f in symbols: | 342 if f in symbols: |
367 safesymbols = set() | 367 safesymbols = set() |
368 | 368 |
369 predicate = registrar.revsetpredicate() | 369 predicate = registrar.revsetpredicate() |
370 | 370 |
371 | 371 |
372 @predicate('_destupdate') | 372 @predicate(b'_destupdate') |
373 def _destupdate(repo, subset, x): | 373 def _destupdate(repo, subset, x): |
374 # experimental revset for update destination | 374 # experimental revset for update destination |
375 args = getargsdict(x, 'limit', 'clean') | 375 args = getargsdict(x, b'limit', b'clean') |
376 return subset & baseset( | 376 return subset & baseset( |
377 [destutil.destupdate(repo, **pycompat.strkwargs(args))[0]] | 377 [destutil.destupdate(repo, **pycompat.strkwargs(args))[0]] |
378 ) | 378 ) |
379 | 379 |
380 | 380 |
381 @predicate('_destmerge') | 381 @predicate(b'_destmerge') |
382 def _destmerge(repo, subset, x): | 382 def _destmerge(repo, subset, x): |
383 # experimental revset for merge destination | 383 # experimental revset for merge destination |
384 sourceset = None | 384 sourceset = None |
385 if x is not None: | 385 if x is not None: |
386 sourceset = getset(repo, fullreposet(repo), x) | 386 sourceset = getset(repo, fullreposet(repo), x) |
387 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)]) | 387 return subset & baseset([destutil.destmerge(repo, sourceset=sourceset)]) |
388 | 388 |
389 | 389 |
390 @predicate('adds(pattern)', safe=True, weight=30) | 390 @predicate(b'adds(pattern)', safe=True, weight=30) |
391 def adds(repo, subset, x): | 391 def adds(repo, subset, x): |
392 """Changesets that add a file matching pattern. | 392 """Changesets that add a file matching pattern. |
393 | 393 |
394 The pattern without explicit kind like ``glob:`` is expected to be | 394 The pattern without explicit kind like ``glob:`` is expected to be |
395 relative to the current directory and match against a file or a | 395 relative to the current directory and match against a file or a |
396 directory. | 396 directory. |
397 """ | 397 """ |
398 # i18n: "adds" is a keyword | 398 # i18n: "adds" is a keyword |
399 pat = getstring(x, _("adds requires a pattern")) | 399 pat = getstring(x, _(b"adds requires a pattern")) |
400 return checkstatus(repo, subset, pat, 1) | 400 return checkstatus(repo, subset, pat, 1) |
401 | 401 |
402 | 402 |
403 @predicate('ancestor(*changeset)', safe=True, weight=0.5) | 403 @predicate(b'ancestor(*changeset)', safe=True, weight=0.5) |
404 def ancestor(repo, subset, x): | 404 def ancestor(repo, subset, x): |
405 """A greatest common ancestor of the changesets. | 405 """A greatest common ancestor of the changesets. |
406 | 406 |
407 Accepts 0 or more changesets. | 407 Accepts 0 or more changesets. |
408 Will return empty list when passed no args. | 408 Will return empty list when passed no args. |
430 return baseset() | 430 return baseset() |
431 s = dagop.revancestors(repo, heads, followfirst, startdepth, stopdepth) | 431 s = dagop.revancestors(repo, heads, followfirst, startdepth, stopdepth) |
432 return subset & s | 432 return subset & s |
433 | 433 |
434 | 434 |
435 @predicate('ancestors(set[, depth])', safe=True) | 435 @predicate(b'ancestors(set[, depth])', safe=True) |
436 def ancestors(repo, subset, x): | 436 def ancestors(repo, subset, x): |
437 """Changesets that are ancestors of changesets in set, including the | 437 """Changesets that are ancestors of changesets in set, including the |
438 given changesets themselves. | 438 given changesets themselves. |
439 | 439 |
440 If depth is specified, the result only includes changesets up to | 440 If depth is specified, the result only includes changesets up to |
441 the specified generation. | 441 the specified generation. |
442 """ | 442 """ |
443 # startdepth is for internal use only until we can decide the UI | 443 # startdepth is for internal use only until we can decide the UI |
444 args = getargsdict(x, 'ancestors', 'set depth startdepth') | 444 args = getargsdict(x, b'ancestors', b'set depth startdepth') |
445 if 'set' not in args: | 445 if b'set' not in args: |
446 # i18n: "ancestors" is a keyword | 446 # i18n: "ancestors" is a keyword |
447 raise error.ParseError(_('ancestors takes at least 1 argument')) | 447 raise error.ParseError(_(b'ancestors takes at least 1 argument')) |
448 startdepth = stopdepth = None | 448 startdepth = stopdepth = None |
449 if 'startdepth' in args: | 449 if b'startdepth' in args: |
450 n = getinteger( | 450 n = getinteger( |
451 args['startdepth'], "ancestors expects an integer startdepth" | 451 args[b'startdepth'], b"ancestors expects an integer startdepth" |
452 ) | 452 ) |
453 if n < 0: | 453 if n < 0: |
454 raise error.ParseError("negative startdepth") | 454 raise error.ParseError(b"negative startdepth") |
455 startdepth = n | 455 startdepth = n |
456 if 'depth' in args: | 456 if b'depth' in args: |
457 # i18n: "ancestors" is a keyword | 457 # i18n: "ancestors" is a keyword |
458 n = getinteger(args['depth'], _("ancestors expects an integer depth")) | 458 n = getinteger(args[b'depth'], _(b"ancestors expects an integer depth")) |
459 if n < 0: | 459 if n < 0: |
460 raise error.ParseError(_("negative depth")) | 460 raise error.ParseError(_(b"negative depth")) |
461 stopdepth = n + 1 | 461 stopdepth = n + 1 |
462 return _ancestors( | 462 return _ancestors( |
463 repo, subset, args['set'], startdepth=startdepth, stopdepth=stopdepth | 463 repo, subset, args[b'set'], startdepth=startdepth, stopdepth=stopdepth |
464 ) | 464 ) |
465 | 465 |
466 | 466 |
467 @predicate('_firstancestors', safe=True) | 467 @predicate(b'_firstancestors', safe=True) |
468 def _firstancestors(repo, subset, x): | 468 def _firstancestors(repo, subset, x): |
469 # ``_firstancestors(set)`` | 469 # ``_firstancestors(set)`` |
470 # Like ``ancestors(set)`` but follows only the first parents. | 470 # Like ``ancestors(set)`` but follows only the first parents. |
471 return _ancestors(repo, subset, x, followfirst=True) | 471 return _ancestors(repo, subset, x, followfirst=True) |
472 | 472 |
481 c = repo[r].children() | 481 c = repo[r].children() |
482 if len(c) == 0: | 482 if len(c) == 0: |
483 break | 483 break |
484 if len(c) > 1: | 484 if len(c) > 1: |
485 raise error.RepoLookupError( | 485 raise error.RepoLookupError( |
486 _("revision in set has more than one child") | 486 _(b"revision in set has more than one child") |
487 ) | 487 ) |
488 r = c[0].rev() | 488 r = c[0].rev() |
489 else: | 489 else: |
490 cs.add(r) | 490 cs.add(r) |
491 return subset & cs | 491 return subset & cs |
494 def ancestorspec(repo, subset, x, n, order): | 494 def ancestorspec(repo, subset, x, n, order): |
495 """``set~n`` | 495 """``set~n`` |
496 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 |
497 in set. | 497 in set. |
498 """ | 498 """ |
499 n = getinteger(n, _("~ expects a number")) | 499 n = getinteger(n, _(b"~ expects a number")) |
500 if n < 0: | 500 if n < 0: |
501 # children lookup | 501 # children lookup |
502 return _childrenspec(repo, subset, x, -n, order) | 502 return _childrenspec(repo, subset, x, -n, order) |
503 ps = set() | 503 ps = set() |
504 cl = repo.changelog | 504 cl = repo.changelog |
510 r = repo[r].p1().rev() | 510 r = repo[r].p1().rev() |
511 ps.add(r) | 511 ps.add(r) |
512 return subset & ps | 512 return subset & ps |
513 | 513 |
514 | 514 |
515 @predicate('author(string)', safe=True, weight=10) | 515 @predicate(b'author(string)', safe=True, weight=10) |
516 def author(repo, subset, x): | 516 def author(repo, subset, x): |
517 """Alias for ``user(string)``. | 517 """Alias for ``user(string)``. |
518 """ | 518 """ |
519 # i18n: "author" is a keyword | 519 # i18n: "author" is a keyword |
520 n = getstring(x, _("author requires a string")) | 520 n = getstring(x, _(b"author requires a string")) |
521 kind, pattern, matcher = _substringmatcher(n, casesensitive=False) | 521 kind, pattern, matcher = _substringmatcher(n, casesensitive=False) |
522 return subset.filter( | 522 return subset.filter( |
523 lambda x: matcher(repo[x].user()), condrepr=('<user %r>', n) | 523 lambda x: matcher(repo[x].user()), condrepr=(b'<user %r>', n) |
524 ) | 524 ) |
525 | 525 |
526 | 526 |
527 @predicate('bisect(string)', safe=True) | 527 @predicate(b'bisect(string)', safe=True) |
528 def bisect(repo, subset, x): | 528 def bisect(repo, subset, x): |
529 """Changesets marked in the specified bisect status: | 529 """Changesets marked in the specified bisect status: |
530 | 530 |
531 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip | 531 - ``good``, ``bad``, ``skip``: csets explicitly marked as good/bad/skip |
532 - ``goods``, ``bads`` : csets topologically good/bad | 532 - ``goods``, ``bads`` : csets topologically good/bad |
535 - ``untested`` : csets whose fate is yet unknown | 535 - ``untested`` : csets whose fate is yet unknown |
536 - ``ignored`` : csets ignored due to DAG topology | 536 - ``ignored`` : csets ignored due to DAG topology |
537 - ``current`` : the cset currently being bisected | 537 - ``current`` : the cset currently being bisected |
538 """ | 538 """ |
539 # i18n: "bisect" is a keyword | 539 # i18n: "bisect" is a keyword |
540 status = getstring(x, _("bisect requires a string")).lower() | 540 status = getstring(x, _(b"bisect requires a string")).lower() |
541 state = set(hbisect.get(repo, status)) | 541 state = set(hbisect.get(repo, status)) |
542 return subset & state | 542 return subset & state |
543 | 543 |
544 | 544 |
545 # Backward-compatibility | 545 # Backward-compatibility |
546 # - 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 |
547 @predicate('bisected', safe=True) | 547 @predicate(b'bisected', safe=True) |
548 def bisected(repo, subset, x): | 548 def bisected(repo, subset, x): |
549 return bisect(repo, subset, x) | 549 return bisect(repo, subset, x) |
550 | 550 |
551 | 551 |
552 @predicate('bookmark([name])', safe=True) | 552 @predicate(b'bookmark([name])', safe=True) |
553 def bookmark(repo, subset, x): | 553 def bookmark(repo, subset, x): |
554 """The named bookmark or all bookmarks. | 554 """The named bookmark or all bookmarks. |
555 | 555 |
556 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`. | 556 Pattern matching is supported for `name`. See :hg:`help revisions.patterns`. |
557 """ | 557 """ |
558 # i18n: "bookmark" is a keyword | 558 # i18n: "bookmark" is a keyword |
559 args = getargs(x, 0, 1, _('bookmark takes one or no arguments')) | 559 args = getargs(x, 0, 1, _(b'bookmark takes one or no arguments')) |
560 if args: | 560 if args: |
561 bm = getstring( | 561 bm = getstring( |
562 args[0], | 562 args[0], |
563 # i18n: "bookmark" is a keyword | 563 # i18n: "bookmark" is a keyword |
564 _('the argument to bookmark must be a string'), | 564 _(b'the argument to bookmark must be a string'), |
565 ) | 565 ) |
566 kind, pattern, matcher = stringutil.stringmatcher(bm) | 566 kind, pattern, matcher = stringutil.stringmatcher(bm) |
567 bms = set() | 567 bms = set() |
568 if kind == 'literal': | 568 if kind == b'literal': |
569 if bm == pattern: | 569 if bm == pattern: |
570 pattern = repo._bookmarks.expandname(pattern) | 570 pattern = repo._bookmarks.expandname(pattern) |
571 bmrev = repo._bookmarks.get(pattern, None) | 571 bmrev = repo._bookmarks.get(pattern, None) |
572 if not bmrev: | 572 if not bmrev: |
573 raise error.RepoLookupError( | 573 raise error.RepoLookupError( |
574 _("bookmark '%s' does not exist") % pattern | 574 _(b"bookmark '%s' does not exist") % pattern |
575 ) | 575 ) |
576 bms.add(repo[bmrev].rev()) | 576 bms.add(repo[bmrev].rev()) |
577 else: | 577 else: |
578 matchrevs = set() | 578 matchrevs = set() |
579 for name, bmrev in repo._bookmarks.iteritems(): | 579 for name, bmrev in repo._bookmarks.iteritems(): |
585 bms = {repo[r].rev() for r in repo._bookmarks.values()} | 585 bms = {repo[r].rev() for r in repo._bookmarks.values()} |
586 bms -= {node.nullrev} | 586 bms -= {node.nullrev} |
587 return subset & bms | 587 return subset & bms |
588 | 588 |
589 | 589 |
590 @predicate('branch(string or set)', safe=True, weight=10) | 590 @predicate(b'branch(string or set)', safe=True, weight=10) |
591 def branch(repo, subset, x): | 591 def branch(repo, subset, x): |
592 """ | 592 """ |
593 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 |
594 changesets. | 594 changesets. |
595 | 595 |
603 return getbi(r)[0] | 603 return getbi(r)[0] |
604 except error.WdirUnsupported: | 604 except error.WdirUnsupported: |
605 return repo[r].branch() | 605 return repo[r].branch() |
606 | 606 |
607 try: | 607 try: |
608 b = getstring(x, '') | 608 b = getstring(x, b'') |
609 except error.ParseError: | 609 except error.ParseError: |
610 # not a string, but another revspec, e.g. tip() | 610 # not a string, but another revspec, e.g. tip() |
611 pass | 611 pass |
612 else: | 612 else: |
613 kind, pattern, matcher = stringutil.stringmatcher(b) | 613 kind, pattern, matcher = stringutil.stringmatcher(b) |
614 if kind == 'literal': | 614 if kind == b'literal': |
615 # note: falls through to the revspec case if no branch with | 615 # note: falls through to the revspec case if no branch with |
616 # this name exists and pattern kind is not specified explicitly | 616 # this name exists and pattern kind is not specified explicitly |
617 if repo.branchmap().hasbranch(pattern): | 617 if repo.branchmap().hasbranch(pattern): |
618 return subset.filter( | 618 return subset.filter( |
619 lambda r: matcher(getbranch(r)), condrepr=('<branch %r>', b) | 619 lambda r: matcher(getbranch(r)), |
620 condrepr=(b'<branch %r>', b), | |
620 ) | 621 ) |
621 if b.startswith('literal:'): | 622 if b.startswith(b'literal:'): |
622 raise error.RepoLookupError( | 623 raise error.RepoLookupError( |
623 _("branch '%s' does not exist") % pattern | 624 _(b"branch '%s' does not exist") % pattern |
624 ) | 625 ) |
625 else: | 626 else: |
626 return subset.filter( | 627 return subset.filter( |
627 lambda r: matcher(getbranch(r)), condrepr=('<branch %r>', b) | 628 lambda r: matcher(getbranch(r)), condrepr=(b'<branch %r>', b) |
628 ) | 629 ) |
629 | 630 |
630 s = getset(repo, fullreposet(repo), x) | 631 s = getset(repo, fullreposet(repo), x) |
631 b = set() | 632 b = set() |
632 for r in s: | 633 for r in s: |
633 b.add(getbranch(r)) | 634 b.add(getbranch(r)) |
634 c = s.__contains__ | 635 c = s.__contains__ |
635 return subset.filter( | 636 return subset.filter( |
636 lambda r: c(r) or getbranch(r) in b, | 637 lambda r: c(r) or getbranch(r) in b, |
637 condrepr=lambda: '<branch %r>' % _sortedb(b), | 638 condrepr=lambda: b'<branch %r>' % _sortedb(b), |
638 ) | 639 ) |
639 | 640 |
640 | 641 |
641 @predicate('phasedivergent()', safe=True) | 642 @predicate(b'phasedivergent()', safe=True) |
642 def phasedivergent(repo, subset, x): | 643 def phasedivergent(repo, subset, x): |
643 """Mutable changesets marked as successors of public changesets. | 644 """Mutable changesets marked as successors of public changesets. |
644 | 645 |
645 Only non-public and non-obsolete changesets can be `phasedivergent`. | 646 Only non-public and non-obsolete changesets can be `phasedivergent`. |
646 (EXPERIMENTAL) | 647 (EXPERIMENTAL) |
647 """ | 648 """ |
648 # i18n: "phasedivergent" is a keyword | 649 # i18n: "phasedivergent" is a keyword |
649 getargs(x, 0, 0, _("phasedivergent takes no arguments")) | 650 getargs(x, 0, 0, _(b"phasedivergent takes no arguments")) |
650 phasedivergent = obsmod.getrevs(repo, 'phasedivergent') | 651 phasedivergent = obsmod.getrevs(repo, b'phasedivergent') |
651 return subset & phasedivergent | 652 return subset & phasedivergent |
652 | 653 |
653 | 654 |
654 @predicate('bundle()', safe=True) | 655 @predicate(b'bundle()', safe=True) |
655 def bundle(repo, subset, x): | 656 def bundle(repo, subset, x): |
656 """Changesets in the bundle. | 657 """Changesets in the bundle. |
657 | 658 |
658 Bundle must be specified by the -R option.""" | 659 Bundle must be specified by the -R option.""" |
659 | 660 |
660 try: | 661 try: |
661 bundlerevs = repo.changelog.bundlerevs | 662 bundlerevs = repo.changelog.bundlerevs |
662 except AttributeError: | 663 except AttributeError: |
663 raise error.Abort(_("no bundle provided - specify with -R")) | 664 raise error.Abort(_(b"no bundle provided - specify with -R")) |
664 return subset & bundlerevs | 665 return subset & bundlerevs |
665 | 666 |
666 | 667 |
667 def checkstatus(repo, subset, pat, field): | 668 def checkstatus(repo, subset, pat, field): |
668 """Helper for status-related revsets (adds, removes, modifies). | 669 """Helper for status-related revsets (adds, removes, modifies). |
669 The field parameter says which kind is desired: | 670 The field parameter says which kind is desired: |
670 0: modified | 671 0: modified |
671 1: added | 672 1: added |
672 2: removed | 673 2: removed |
673 """ | 674 """ |
674 hasset = matchmod.patkind(pat) == 'set' | 675 hasset = matchmod.patkind(pat) == b'set' |
675 | 676 |
676 mcache = [None] | 677 mcache = [None] |
677 | 678 |
678 def matches(x): | 679 def matches(x): |
679 c = repo[x] | 680 c = repo[x] |
699 else: | 700 else: |
700 for f in files: | 701 for f in files: |
701 if m(f): | 702 if m(f): |
702 return True | 703 return True |
703 | 704 |
704 return subset.filter(matches, condrepr=('<status[%r] %r>', field, pat)) | 705 return subset.filter(matches, condrepr=(b'<status[%r] %r>', field, pat)) |
705 | 706 |
706 | 707 |
707 def _children(repo, subset, parentset): | 708 def _children(repo, subset, parentset): |
708 if not parentset: | 709 if not parentset: |
709 return baseset() | 710 return baseset() |
720 if p2 != nullrev and p2 in parentset: | 721 if p2 != nullrev and p2 in parentset: |
721 cs.add(r) | 722 cs.add(r) |
722 return baseset(cs) | 723 return baseset(cs) |
723 | 724 |
724 | 725 |
725 @predicate('children(set)', safe=True) | 726 @predicate(b'children(set)', safe=True) |
726 def children(repo, subset, x): | 727 def children(repo, subset, x): |
727 """Child changesets of changesets in set. | 728 """Child changesets of changesets in set. |
728 """ | 729 """ |
729 s = getset(repo, fullreposet(repo), x) | 730 s = getset(repo, fullreposet(repo), x) |
730 cs = _children(repo, subset, s) | 731 cs = _children(repo, subset, s) |
731 return subset & cs | 732 return subset & cs |
732 | 733 |
733 | 734 |
734 @predicate('closed()', safe=True, weight=10) | 735 @predicate(b'closed()', safe=True, weight=10) |
735 def closed(repo, subset, x): | 736 def closed(repo, subset, x): |
736 """Changeset is closed. | 737 """Changeset is closed. |
737 """ | 738 """ |
738 # i18n: "closed" is a keyword | 739 # i18n: "closed" is a keyword |
739 getargs(x, 0, 0, _("closed takes no arguments")) | 740 getargs(x, 0, 0, _(b"closed takes no arguments")) |
740 return subset.filter( | 741 return subset.filter( |
741 lambda r: repo[r].closesbranch(), condrepr='<branch closed>' | 742 lambda r: repo[r].closesbranch(), condrepr=b'<branch closed>' |
742 ) | 743 ) |
743 | 744 |
744 | 745 |
745 # for internal use | 746 # for internal use |
746 @predicate('_commonancestorheads(set)', safe=True) | 747 @predicate(b'_commonancestorheads(set)', safe=True) |
747 def _commonancestorheads(repo, subset, x): | 748 def _commonancestorheads(repo, subset, x): |
748 # This is an internal method is for quickly calculating "heads(::x and | 749 # This is an internal method is for quickly calculating "heads(::x and |
749 # ::y)" | 750 # ::y)" |
750 | 751 |
751 # These greatest common ancestors are the same ones that the consensus bid | 752 # These greatest common ancestors are the same ones that the consensus bid |
754 | 755 |
755 ancs = repo.changelog._commonancestorsheads(*list(startrevs)) | 756 ancs = repo.changelog._commonancestorsheads(*list(startrevs)) |
756 return subset & baseset(ancs) | 757 return subset & baseset(ancs) |
757 | 758 |
758 | 759 |
759 @predicate('commonancestors(set)', safe=True) | 760 @predicate(b'commonancestors(set)', safe=True) |
760 def commonancestors(repo, subset, x): | 761 def commonancestors(repo, subset, x): |
761 """Changesets that are ancestors of every changeset in set. | 762 """Changesets that are ancestors of every changeset in set. |
762 """ | 763 """ |
763 startrevs = getset(repo, fullreposet(repo), x, order=anyorder) | 764 startrevs = getset(repo, fullreposet(repo), x, order=anyorder) |
764 if not startrevs: | 765 if not startrevs: |
766 for r in startrevs: | 767 for r in startrevs: |
767 subset &= dagop.revancestors(repo, baseset([r])) | 768 subset &= dagop.revancestors(repo, baseset([r])) |
768 return subset | 769 return subset |
769 | 770 |
770 | 771 |
771 @predicate('contains(pattern)', weight=100) | 772 @predicate(b'contains(pattern)', weight=100) |
772 def contains(repo, subset, x): | 773 def contains(repo, subset, x): |
773 """The revision's manifest contains a file matching pattern (but might not | 774 """The revision's manifest contains a file matching pattern (but might not |
774 modify it). See :hg:`help patterns` for information about file patterns. | 775 modify it). See :hg:`help patterns` for information about file patterns. |
775 | 776 |
776 The pattern without explicit kind like ``glob:`` is expected to be | 777 The pattern without explicit kind like ``glob:`` is expected to be |
777 relative to the current directory and match against a file exactly | 778 relative to the current directory and match against a file exactly |
778 for efficiency. | 779 for efficiency. |
779 """ | 780 """ |
780 # i18n: "contains" is a keyword | 781 # i18n: "contains" is a keyword |
781 pat = getstring(x, _("contains requires a pattern")) | 782 pat = getstring(x, _(b"contains requires a pattern")) |
782 | 783 |
783 def matches(x): | 784 def matches(x): |
784 if not matchmod.patkind(pat): | 785 if not matchmod.patkind(pat): |
785 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat) | 786 pats = pathutil.canonpath(repo.root, repo.getcwd(), pat) |
786 if pats in repo[x]: | 787 if pats in repo[x]: |
791 for f in c.manifest(): | 792 for f in c.manifest(): |
792 if m(f): | 793 if m(f): |
793 return True | 794 return True |
794 return False | 795 return False |
795 | 796 |
796 return subset.filter(matches, condrepr=('<contains %r>', pat)) | 797 return subset.filter(matches, condrepr=(b'<contains %r>', pat)) |
797 | 798 |
798 | 799 |
799 @predicate('converted([id])', safe=True) | 800 @predicate(b'converted([id])', safe=True) |
800 def converted(repo, subset, x): | 801 def converted(repo, subset, x): |
801 """Changesets converted from the given identifier in the old repository if | 802 """Changesets converted from the given identifier in the old repository if |
802 present, or all converted changesets if no identifier is specified. | 803 present, or all converted changesets if no identifier is specified. |
803 """ | 804 """ |
804 | 805 |
805 # There is exactly no chance of resolving the revision, so do a simple | 806 # There is exactly no chance of resolving the revision, so do a simple |
806 # string compare and hope for the best | 807 # string compare and hope for the best |
807 | 808 |
808 rev = None | 809 rev = None |
809 # i18n: "converted" is a keyword | 810 # i18n: "converted" is a keyword |
810 l = getargs(x, 0, 1, _('converted takes one or no arguments')) | 811 l = getargs(x, 0, 1, _(b'converted takes one or no arguments')) |
811 if l: | 812 if l: |
812 # i18n: "converted" is a keyword | 813 # i18n: "converted" is a keyword |
813 rev = getstring(l[0], _('converted requires a revision')) | 814 rev = getstring(l[0], _(b'converted requires a revision')) |
814 | 815 |
815 def _matchvalue(r): | 816 def _matchvalue(r): |
816 source = repo[r].extra().get('convert_revision', None) | 817 source = repo[r].extra().get(b'convert_revision', None) |
817 return source is not None and (rev is None or source.startswith(rev)) | 818 return source is not None and (rev is None or source.startswith(rev)) |
818 | 819 |
819 return subset.filter( | 820 return subset.filter( |
820 lambda r: _matchvalue(r), condrepr=('<converted %r>', rev) | 821 lambda r: _matchvalue(r), condrepr=(b'<converted %r>', rev) |
821 ) | 822 ) |
822 | 823 |
823 | 824 |
824 @predicate('date(interval)', safe=True, weight=10) | 825 @predicate(b'date(interval)', safe=True, weight=10) |
825 def date(repo, subset, x): | 826 def date(repo, subset, x): |
826 """Changesets within the interval, see :hg:`help dates`. | 827 """Changesets within the interval, see :hg:`help dates`. |
827 """ | 828 """ |
828 # i18n: "date" is a keyword | 829 # i18n: "date" is a keyword |
829 ds = getstring(x, _("date requires a string")) | 830 ds = getstring(x, _(b"date requires a string")) |
830 dm = dateutil.matchdate(ds) | 831 dm = dateutil.matchdate(ds) |
831 return subset.filter( | 832 return subset.filter( |
832 lambda x: dm(repo[x].date()[0]), condrepr=('<date %r>', ds) | 833 lambda x: dm(repo[x].date()[0]), condrepr=(b'<date %r>', ds) |
833 ) | 834 ) |
834 | 835 |
835 | 836 |
836 @predicate('desc(string)', safe=True, weight=10) | 837 @predicate(b'desc(string)', safe=True, weight=10) |
837 def desc(repo, subset, x): | 838 def desc(repo, subset, x): |
838 """Search commit message for string. The match is case-insensitive. | 839 """Search commit message for string. The match is case-insensitive. |
839 | 840 |
840 Pattern matching is supported for `string`. See | 841 Pattern matching is supported for `string`. See |
841 :hg:`help revisions.patterns`. | 842 :hg:`help revisions.patterns`. |
842 """ | 843 """ |
843 # i18n: "desc" is a keyword | 844 # i18n: "desc" is a keyword |
844 ds = getstring(x, _("desc requires a string")) | 845 ds = getstring(x, _(b"desc requires a string")) |
845 | 846 |
846 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False) | 847 kind, pattern, matcher = _substringmatcher(ds, casesensitive=False) |
847 | 848 |
848 return subset.filter( | 849 return subset.filter( |
849 lambda r: matcher(repo[r].description()), condrepr=('<desc %r>', ds) | 850 lambda r: matcher(repo[r].description()), condrepr=(b'<desc %r>', ds) |
850 ) | 851 ) |
851 | 852 |
852 | 853 |
853 def _descendants( | 854 def _descendants( |
854 repo, subset, x, followfirst=False, startdepth=None, stopdepth=None | 855 repo, subset, x, followfirst=False, startdepth=None, stopdepth=None |
858 return baseset() | 859 return baseset() |
859 s = dagop.revdescendants(repo, roots, followfirst, startdepth, stopdepth) | 860 s = dagop.revdescendants(repo, roots, followfirst, startdepth, stopdepth) |
860 return subset & s | 861 return subset & s |
861 | 862 |
862 | 863 |
863 @predicate('descendants(set[, depth])', safe=True) | 864 @predicate(b'descendants(set[, depth])', safe=True) |
864 def descendants(repo, subset, x): | 865 def descendants(repo, subset, x): |
865 """Changesets which are descendants of changesets in set, including the | 866 """Changesets which are descendants of changesets in set, including the |
866 given changesets themselves. | 867 given changesets themselves. |
867 | 868 |
868 If depth is specified, the result only includes changesets up to | 869 If depth is specified, the result only includes changesets up to |
869 the specified generation. | 870 the specified generation. |
870 """ | 871 """ |
871 # startdepth is for internal use only until we can decide the UI | 872 # startdepth is for internal use only until we can decide the UI |
872 args = getargsdict(x, 'descendants', 'set depth startdepth') | 873 args = getargsdict(x, b'descendants', b'set depth startdepth') |
873 if 'set' not in args: | 874 if b'set' not in args: |
874 # i18n: "descendants" is a keyword | 875 # i18n: "descendants" is a keyword |
875 raise error.ParseError(_('descendants takes at least 1 argument')) | 876 raise error.ParseError(_(b'descendants takes at least 1 argument')) |
876 startdepth = stopdepth = None | 877 startdepth = stopdepth = None |
877 if 'startdepth' in args: | 878 if b'startdepth' in args: |
878 n = getinteger( | 879 n = getinteger( |
879 args['startdepth'], "descendants expects an integer startdepth" | 880 args[b'startdepth'], b"descendants expects an integer startdepth" |
880 ) | 881 ) |
881 if n < 0: | 882 if n < 0: |
882 raise error.ParseError("negative startdepth") | 883 raise error.ParseError(b"negative startdepth") |
883 startdepth = n | 884 startdepth = n |
884 if 'depth' in args: | 885 if b'depth' in args: |
885 # i18n: "descendants" is a keyword | 886 # i18n: "descendants" is a keyword |
886 n = getinteger(args['depth'], _("descendants expects an integer depth")) | 887 n = getinteger( |
888 args[b'depth'], _(b"descendants expects an integer depth") | |
889 ) | |
887 if n < 0: | 890 if n < 0: |
888 raise error.ParseError(_("negative depth")) | 891 raise error.ParseError(_(b"negative depth")) |
889 stopdepth = n + 1 | 892 stopdepth = n + 1 |
890 return _descendants( | 893 return _descendants( |
891 repo, subset, args['set'], startdepth=startdepth, stopdepth=stopdepth | 894 repo, subset, args[b'set'], startdepth=startdepth, stopdepth=stopdepth |
892 ) | 895 ) |
893 | 896 |
894 | 897 |
895 @predicate('_firstdescendants', safe=True) | 898 @predicate(b'_firstdescendants', safe=True) |
896 def _firstdescendants(repo, subset, x): | 899 def _firstdescendants(repo, subset, x): |
897 # ``_firstdescendants(set)`` | 900 # ``_firstdescendants(set)`` |
898 # Like ``descendants(set)`` but follows only the first parents. | 901 # Like ``descendants(set)`` but follows only the first parents. |
899 return _descendants(repo, subset, x, followfirst=True) | 902 return _descendants(repo, subset, x, followfirst=True) |
900 | 903 |
901 | 904 |
902 @predicate('destination([set])', safe=True, weight=10) | 905 @predicate(b'destination([set])', safe=True, weight=10) |
903 def destination(repo, subset, x): | 906 def destination(repo, subset, x): |
904 """Changesets that were created by a graft, transplant or rebase operation, | 907 """Changesets that were created by a graft, transplant or rebase operation, |
905 with the given revisions specified as the source. Omitting the optional set | 908 with the given revisions specified as the source. Omitting the optional set |
906 is the same as passing all(). | 909 is the same as passing all(). |
907 """ | 910 """ |
941 r = src | 944 r = src |
942 src = _getrevsource(repo, r) | 945 src = _getrevsource(repo, r) |
943 | 946 |
944 return subset.filter( | 947 return subset.filter( |
945 dests.__contains__, | 948 dests.__contains__, |
946 condrepr=lambda: '<destination %r>' % _sortedb(dests), | 949 condrepr=lambda: b'<destination %r>' % _sortedb(dests), |
947 ) | 950 ) |
948 | 951 |
949 | 952 |
950 @predicate('contentdivergent()', safe=True) | 953 @predicate(b'contentdivergent()', safe=True) |
951 def contentdivergent(repo, subset, x): | 954 def contentdivergent(repo, subset, x): |
952 """ | 955 """ |
953 Final successors of changesets with an alternative set of final | 956 Final successors of changesets with an alternative set of final |
954 successors. (EXPERIMENTAL) | 957 successors. (EXPERIMENTAL) |
955 """ | 958 """ |
956 # i18n: "contentdivergent" is a keyword | 959 # i18n: "contentdivergent" is a keyword |
957 getargs(x, 0, 0, _("contentdivergent takes no arguments")) | 960 getargs(x, 0, 0, _(b"contentdivergent takes no arguments")) |
958 contentdivergent = obsmod.getrevs(repo, 'contentdivergent') | 961 contentdivergent = obsmod.getrevs(repo, b'contentdivergent') |
959 return subset & contentdivergent | 962 return subset & contentdivergent |
960 | 963 |
961 | 964 |
962 @predicate('expectsize(set[, size])', safe=True, takeorder=True) | 965 @predicate(b'expectsize(set[, size])', safe=True, takeorder=True) |
963 def expectsize(repo, subset, x, order): | 966 def expectsize(repo, subset, x, order): |
964 """Return the given revset if size matches the revset size. | 967 """Return the given revset if size matches the revset size. |
965 Abort if the revset doesn't expect given size. | 968 Abort if the revset doesn't expect given size. |
966 size can either be an integer range or an integer. | 969 size can either be an integer range or an integer. |
967 | 970 |
968 For example, ``expectsize(0:1, 3:5)`` will abort as revset size is 2 and | 971 For example, ``expectsize(0:1, 3:5)`` will abort as revset size is 2 and |
969 2 is not between 3 and 5 inclusive.""" | 972 2 is not between 3 and 5 inclusive.""" |
970 | 973 |
971 args = getargsdict(x, 'expectsize', 'set size') | 974 args = getargsdict(x, b'expectsize', b'set size') |
972 minsize = 0 | 975 minsize = 0 |
973 maxsize = len(repo) + 1 | 976 maxsize = len(repo) + 1 |
974 err = '' | 977 err = b'' |
975 if 'size' not in args or 'set' not in args: | 978 if b'size' not in args or b'set' not in args: |
976 raise error.ParseError(_('invalid set of arguments')) | 979 raise error.ParseError(_(b'invalid set of arguments')) |
977 minsize, maxsize = getintrange( | 980 minsize, maxsize = getintrange( |
978 args['size'], | 981 args[b'size'], |
979 _('expectsize requires a size range' ' or a positive integer'), | 982 _(b'expectsize requires a size range' b' or a positive integer'), |
980 _('size range bounds must be integers'), | 983 _(b'size range bounds must be integers'), |
981 minsize, | 984 minsize, |
982 maxsize, | 985 maxsize, |
983 ) | 986 ) |
984 if minsize < 0 or maxsize < 0: | 987 if minsize < 0 or maxsize < 0: |
985 raise error.ParseError(_('negative size')) | 988 raise error.ParseError(_(b'negative size')) |
986 rev = getset(repo, fullreposet(repo), args['set'], order=order) | 989 rev = getset(repo, fullreposet(repo), args[b'set'], order=order) |
987 if minsize != maxsize and (len(rev) < minsize or len(rev) > maxsize): | 990 if minsize != maxsize and (len(rev) < minsize or len(rev) > maxsize): |
988 err = _( | 991 err = _( |
989 'revset size mismatch.' ' expected between %d and %d, got %d' | 992 b'revset size mismatch.' b' expected between %d and %d, got %d' |
990 ) % (minsize, maxsize, len(rev)) | 993 ) % (minsize, maxsize, len(rev)) |
991 elif minsize == maxsize and len(rev) != minsize: | 994 elif minsize == maxsize and len(rev) != minsize: |
992 err = _('revset size mismatch.' ' expected %d, got %d') % ( | 995 err = _(b'revset size mismatch.' b' expected %d, got %d') % ( |
993 minsize, | 996 minsize, |
994 len(rev), | 997 len(rev), |
995 ) | 998 ) |
996 if err: | 999 if err: |
997 raise error.RepoLookupError(err) | 1000 raise error.RepoLookupError(err) |
999 return subset & rev | 1002 return subset & rev |
1000 else: | 1003 else: |
1001 return rev & subset | 1004 return rev & subset |
1002 | 1005 |
1003 | 1006 |
1004 @predicate('extdata(source)', safe=False, weight=100) | 1007 @predicate(b'extdata(source)', safe=False, weight=100) |
1005 def extdata(repo, subset, x): | 1008 def extdata(repo, subset, x): |
1006 """Changesets in the specified extdata source. (EXPERIMENTAL)""" | 1009 """Changesets in the specified extdata source. (EXPERIMENTAL)""" |
1007 # i18n: "extdata" is a keyword | 1010 # i18n: "extdata" is a keyword |
1008 args = getargsdict(x, 'extdata', 'source') | 1011 args = getargsdict(x, b'extdata', b'source') |
1009 source = getstring( | 1012 source = getstring( |
1010 args.get('source'), | 1013 args.get(b'source'), |
1011 # i18n: "extdata" is a keyword | 1014 # i18n: "extdata" is a keyword |
1012 _('extdata takes at least 1 string argument'), | 1015 _(b'extdata takes at least 1 string argument'), |
1013 ) | 1016 ) |
1014 data = scmutil.extdatasource(repo, source) | 1017 data = scmutil.extdatasource(repo, source) |
1015 return subset & baseset(data) | 1018 return subset & baseset(data) |
1016 | 1019 |
1017 | 1020 |
1018 @predicate('extinct()', safe=True) | 1021 @predicate(b'extinct()', safe=True) |
1019 def extinct(repo, subset, x): | 1022 def extinct(repo, subset, x): |
1020 """Obsolete changesets with obsolete descendants only. | 1023 """Obsolete changesets with obsolete descendants only. |
1021 """ | 1024 """ |
1022 # i18n: "extinct" is a keyword | 1025 # i18n: "extinct" is a keyword |
1023 getargs(x, 0, 0, _("extinct takes no arguments")) | 1026 getargs(x, 0, 0, _(b"extinct takes no arguments")) |
1024 extincts = obsmod.getrevs(repo, 'extinct') | 1027 extincts = obsmod.getrevs(repo, b'extinct') |
1025 return subset & extincts | 1028 return subset & extincts |
1026 | 1029 |
1027 | 1030 |
1028 @predicate('extra(label, [value])', safe=True) | 1031 @predicate(b'extra(label, [value])', safe=True) |
1029 def extra(repo, subset, x): | 1032 def extra(repo, subset, x): |
1030 """Changesets with the given label in the extra metadata, with the given | 1033 """Changesets with the given label in the extra metadata, with the given |
1031 optional value. | 1034 optional value. |
1032 | 1035 |
1033 Pattern matching is supported for `value`. See | 1036 Pattern matching is supported for `value`. See |
1034 :hg:`help revisions.patterns`. | 1037 :hg:`help revisions.patterns`. |
1035 """ | 1038 """ |
1036 args = getargsdict(x, 'extra', 'label value') | 1039 args = getargsdict(x, b'extra', b'label value') |
1037 if 'label' not in args: | 1040 if b'label' not in args: |
1038 # i18n: "extra" is a keyword | 1041 # i18n: "extra" is a keyword |
1039 raise error.ParseError(_('extra takes at least 1 argument')) | 1042 raise error.ParseError(_(b'extra takes at least 1 argument')) |
1040 # i18n: "extra" is a keyword | 1043 # i18n: "extra" is a keyword |
1041 label = getstring( | 1044 label = getstring( |
1042 args['label'], _('first argument to extra must be ' 'a string') | 1045 args[b'label'], _(b'first argument to extra must be ' b'a string') |
1043 ) | 1046 ) |
1044 value = None | 1047 value = None |
1045 | 1048 |
1046 if 'value' in args: | 1049 if b'value' in args: |
1047 # i18n: "extra" is a keyword | 1050 # i18n: "extra" is a keyword |
1048 value = getstring( | 1051 value = getstring( |
1049 args['value'], _('second argument to extra must be ' 'a string') | 1052 args[b'value'], _(b'second argument to extra must be ' b'a string') |
1050 ) | 1053 ) |
1051 kind, value, matcher = stringutil.stringmatcher(value) | 1054 kind, value, matcher = stringutil.stringmatcher(value) |
1052 | 1055 |
1053 def _matchvalue(r): | 1056 def _matchvalue(r): |
1054 extra = repo[r].extra() | 1057 extra = repo[r].extra() |
1055 return label in extra and (value is None or matcher(extra[label])) | 1058 return label in extra and (value is None or matcher(extra[label])) |
1056 | 1059 |
1057 return subset.filter( | 1060 return subset.filter( |
1058 lambda r: _matchvalue(r), condrepr=('<extra[%r] %r>', label, value) | 1061 lambda r: _matchvalue(r), condrepr=(b'<extra[%r] %r>', label, value) |
1059 ) | 1062 ) |
1060 | 1063 |
1061 | 1064 |
1062 @predicate('filelog(pattern)', safe=True) | 1065 @predicate(b'filelog(pattern)', safe=True) |
1063 def filelog(repo, subset, x): | 1066 def filelog(repo, subset, x): |
1064 """Changesets connected to the specified filelog. | 1067 """Changesets connected to the specified filelog. |
1065 | 1068 |
1066 For performance reasons, visits only revisions mentioned in the file-level | 1069 For performance reasons, visits only revisions mentioned in the file-level |
1067 filelog, rather than filtering through all changesets (much faster, but | 1070 filelog, rather than filtering through all changesets (much faster, but |
1072 relative to the current directory and match against a file exactly | 1075 relative to the current directory and match against a file exactly |
1073 for efficiency. | 1076 for efficiency. |
1074 """ | 1077 """ |
1075 | 1078 |
1076 # i18n: "filelog" is a keyword | 1079 # i18n: "filelog" is a keyword |
1077 pat = getstring(x, _("filelog requires a pattern")) | 1080 pat = getstring(x, _(b"filelog requires a pattern")) |
1078 s = set() | 1081 s = set() |
1079 cl = repo.changelog | 1082 cl = repo.changelog |
1080 | 1083 |
1081 if not matchmod.patkind(pat): | 1084 if not matchmod.patkind(pat): |
1082 f = pathutil.canonpath(repo.root, repo.getcwd(), pat) | 1085 f = pathutil.canonpath(repo.root, repo.getcwd(), pat) |
1121 continue | 1124 continue |
1122 | 1125 |
1123 return subset & s | 1126 return subset & s |
1124 | 1127 |
1125 | 1128 |
1126 @predicate('first(set, [n])', safe=True, takeorder=True, weight=0) | 1129 @predicate(b'first(set, [n])', safe=True, takeorder=True, weight=0) |
1127 def first(repo, subset, x, order): | 1130 def first(repo, subset, x, order): |
1128 """An alias for limit(). | 1131 """An alias for limit(). |
1129 """ | 1132 """ |
1130 return limit(repo, subset, x, order) | 1133 return limit(repo, subset, x, order) |
1131 | 1134 |
1132 | 1135 |
1133 def _follow(repo, subset, x, name, followfirst=False): | 1136 def _follow(repo, subset, x, name, followfirst=False): |
1134 args = getargsdict(x, name, 'file startrev') | 1137 args = getargsdict(x, name, b'file startrev') |
1135 revs = None | 1138 revs = None |
1136 if 'startrev' in args: | 1139 if b'startrev' in args: |
1137 revs = getset(repo, fullreposet(repo), args['startrev']) | 1140 revs = getset(repo, fullreposet(repo), args[b'startrev']) |
1138 if 'file' in args: | 1141 if b'file' in args: |
1139 x = getstring(args['file'], _("%s expected a pattern") % name) | 1142 x = getstring(args[b'file'], _(b"%s expected a pattern") % name) |
1140 if revs is None: | 1143 if revs is None: |
1141 revs = [None] | 1144 revs = [None] |
1142 fctxs = [] | 1145 fctxs = [] |
1143 for r in revs: | 1146 for r in revs: |
1144 ctx = mctx = repo[r] | 1147 ctx = mctx = repo[r] |
1145 if r is None: | 1148 if r is None: |
1146 ctx = repo['.'] | 1149 ctx = repo[b'.'] |
1147 m = matchmod.match( | 1150 m = matchmod.match( |
1148 repo.root, repo.getcwd(), [x], ctx=mctx, default='path' | 1151 repo.root, repo.getcwd(), [x], ctx=mctx, default=b'path' |
1149 ) | 1152 ) |
1150 fctxs.extend(ctx[f].introfilectx() for f in ctx.manifest().walk(m)) | 1153 fctxs.extend(ctx[f].introfilectx() for f in ctx.manifest().walk(m)) |
1151 s = dagop.filerevancestors(fctxs, followfirst) | 1154 s = dagop.filerevancestors(fctxs, followfirst) |
1152 else: | 1155 else: |
1153 if revs is None: | 1156 if revs is None: |
1154 revs = baseset([repo['.'].rev()]) | 1157 revs = baseset([repo[b'.'].rev()]) |
1155 s = dagop.revancestors(repo, revs, followfirst) | 1158 s = dagop.revancestors(repo, revs, followfirst) |
1156 | 1159 |
1157 return subset & s | 1160 return subset & s |
1158 | 1161 |
1159 | 1162 |
1160 @predicate('follow([file[, startrev]])', safe=True) | 1163 @predicate(b'follow([file[, startrev]])', safe=True) |
1161 def follow(repo, subset, x): | 1164 def follow(repo, subset, x): |
1162 """ | 1165 """ |
1163 An alias for ``::.`` (ancestors of the working directory's first parent). | 1166 An alias for ``::.`` (ancestors of the working directory's first parent). |
1164 If file pattern is specified, the histories of files matching given | 1167 If file pattern is specified, the histories of files matching given |
1165 pattern in the revision given by startrev are followed, including copies. | 1168 pattern in the revision given by startrev are followed, including copies. |
1166 """ | 1169 """ |
1167 return _follow(repo, subset, x, 'follow') | 1170 return _follow(repo, subset, x, b'follow') |
1168 | 1171 |
1169 | 1172 |
1170 @predicate('_followfirst', safe=True) | 1173 @predicate(b'_followfirst', safe=True) |
1171 def _followfirst(repo, subset, x): | 1174 def _followfirst(repo, subset, x): |
1172 # ``followfirst([file[, startrev]])`` | 1175 # ``followfirst([file[, startrev]])`` |
1173 # Like ``follow([file[, startrev]])`` but follows only the first parent | 1176 # Like ``follow([file[, startrev]])`` but follows only the first parent |
1174 # of every revisions or files revisions. | 1177 # of every revisions or files revisions. |
1175 return _follow(repo, subset, x, '_followfirst', followfirst=True) | 1178 return _follow(repo, subset, x, b'_followfirst', followfirst=True) |
1176 | 1179 |
1177 | 1180 |
1178 @predicate( | 1181 @predicate( |
1179 'followlines(file, fromline:toline[, startrev=., descend=False])', safe=True | 1182 b'followlines(file, fromline:toline[, startrev=., descend=False])', |
1183 safe=True, | |
1180 ) | 1184 ) |
1181 def followlines(repo, subset, x): | 1185 def followlines(repo, subset, x): |
1182 """Changesets modifying `file` in line range ('fromline', 'toline'). | 1186 """Changesets modifying `file` in line range ('fromline', 'toline'). |
1183 | 1187 |
1184 Line range corresponds to 'file' content at 'startrev' and should hence be | 1188 Line range corresponds to 'file' content at 'startrev' and should hence be |
1187 | 1191 |
1188 By default, ancestors of 'startrev' are returned. If 'descend' is True, | 1192 By default, ancestors of 'startrev' are returned. If 'descend' is True, |
1189 descendants of 'startrev' are returned though renames are (currently) not | 1193 descendants of 'startrev' are returned though renames are (currently) not |
1190 followed in this direction. | 1194 followed in this direction. |
1191 """ | 1195 """ |
1192 args = getargsdict(x, 'followlines', 'file *lines startrev descend') | 1196 args = getargsdict(x, b'followlines', b'file *lines startrev descend') |
1193 if len(args['lines']) != 1: | 1197 if len(args[b'lines']) != 1: |
1194 raise error.ParseError(_("followlines requires a line range")) | 1198 raise error.ParseError(_(b"followlines requires a line range")) |
1195 | 1199 |
1196 rev = '.' | 1200 rev = b'.' |
1197 if 'startrev' in args: | 1201 if b'startrev' in args: |
1198 revs = getset(repo, fullreposet(repo), args['startrev']) | 1202 revs = getset(repo, fullreposet(repo), args[b'startrev']) |
1199 if len(revs) != 1: | 1203 if len(revs) != 1: |
1200 raise error.ParseError( | 1204 raise error.ParseError( |
1201 # i18n: "followlines" is a keyword | 1205 # i18n: "followlines" is a keyword |
1202 _("followlines expects exactly one revision") | 1206 _(b"followlines expects exactly one revision") |
1203 ) | 1207 ) |
1204 rev = revs.last() | 1208 rev = revs.last() |
1205 | 1209 |
1206 pat = getstring(args['file'], _("followlines requires a pattern")) | 1210 pat = getstring(args[b'file'], _(b"followlines requires a pattern")) |
1207 # i18n: "followlines" is a keyword | 1211 # i18n: "followlines" is a keyword |
1208 msg = _("followlines expects exactly one file") | 1212 msg = _(b"followlines expects exactly one file") |
1209 fname = scmutil.parsefollowlinespattern(repo, rev, pat, msg) | 1213 fname = scmutil.parsefollowlinespattern(repo, rev, pat, msg) |
1210 fromline, toline = util.processlinerange( | 1214 fromline, toline = util.processlinerange( |
1211 *getintrange( | 1215 *getintrange( |
1212 args['lines'][0], | 1216 args[b'lines'][0], |
1213 # i18n: "followlines" is a keyword | 1217 # i18n: "followlines" is a keyword |
1214 _("followlines expects a line number or a range"), | 1218 _(b"followlines expects a line number or a range"), |
1215 _("line range bounds must be integers"), | 1219 _(b"line range bounds must be integers"), |
1216 ) | 1220 ) |
1217 ) | 1221 ) |
1218 | 1222 |
1219 fctx = repo[rev].filectx(fname) | 1223 fctx = repo[rev].filectx(fname) |
1220 descend = False | 1224 descend = False |
1221 if 'descend' in args: | 1225 if b'descend' in args: |
1222 descend = getboolean( | 1226 descend = getboolean( |
1223 args['descend'], | 1227 args[b'descend'], |
1224 # i18n: "descend" is a keyword | 1228 # i18n: "descend" is a keyword |
1225 _("descend argument must be a boolean"), | 1229 _(b"descend argument must be a boolean"), |
1226 ) | 1230 ) |
1227 if descend: | 1231 if descend: |
1228 rs = generatorset( | 1232 rs = generatorset( |
1229 ( | 1233 ( |
1230 c.rev() | 1234 c.rev() |
1245 iterasc=False, | 1249 iterasc=False, |
1246 ) | 1250 ) |
1247 return subset & rs | 1251 return subset & rs |
1248 | 1252 |
1249 | 1253 |
1250 @predicate('all()', safe=True) | 1254 @predicate(b'all()', safe=True) |
1251 def getall(repo, subset, x): | 1255 def getall(repo, subset, x): |
1252 """All changesets, the same as ``0:tip``. | 1256 """All changesets, the same as ``0:tip``. |
1253 """ | 1257 """ |
1254 # i18n: "all" is a keyword | 1258 # i18n: "all" is a keyword |
1255 getargs(x, 0, 0, _("all takes no arguments")) | 1259 getargs(x, 0, 0, _(b"all takes no arguments")) |
1256 return subset & spanset(repo) # drop "null" if any | 1260 return subset & spanset(repo) # drop "null" if any |
1257 | 1261 |
1258 | 1262 |
1259 @predicate('grep(regex)', weight=10) | 1263 @predicate(b'grep(regex)', weight=10) |
1260 def grep(repo, subset, x): | 1264 def grep(repo, subset, x): |
1261 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')`` | 1265 """Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')`` |
1262 to ensure special escape characters are handled correctly. Unlike | 1266 to ensure special escape characters are handled correctly. Unlike |
1263 ``keyword(string)``, the match is case-sensitive. | 1267 ``keyword(string)``, the match is case-sensitive. |
1264 """ | 1268 """ |
1265 try: | 1269 try: |
1266 # i18n: "grep" is a keyword | 1270 # i18n: "grep" is a keyword |
1267 gr = re.compile(getstring(x, _("grep requires a string"))) | 1271 gr = re.compile(getstring(x, _(b"grep requires a string"))) |
1268 except re.error as e: | 1272 except re.error as e: |
1269 raise error.ParseError( | 1273 raise error.ParseError( |
1270 _('invalid match pattern: %s') % stringutil.forcebytestr(e) | 1274 _(b'invalid match pattern: %s') % stringutil.forcebytestr(e) |
1271 ) | 1275 ) |
1272 | 1276 |
1273 def matches(x): | 1277 def matches(x): |
1274 c = repo[x] | 1278 c = repo[x] |
1275 for e in c.files() + [c.user(), c.description()]: | 1279 for e in c.files() + [c.user(), c.description()]: |
1276 if gr.search(e): | 1280 if gr.search(e): |
1277 return True | 1281 return True |
1278 return False | 1282 return False |
1279 | 1283 |
1280 return subset.filter(matches, condrepr=('<grep %r>', gr.pattern)) | 1284 return subset.filter(matches, condrepr=(b'<grep %r>', gr.pattern)) |
1281 | 1285 |
1282 | 1286 |
1283 @predicate('_matchfiles', safe=True) | 1287 @predicate(b'_matchfiles', safe=True) |
1284 def _matchfiles(repo, subset, x): | 1288 def _matchfiles(repo, subset, x): |
1285 # _matchfiles takes a revset list of prefixed arguments: | 1289 # _matchfiles takes a revset list of prefixed arguments: |
1286 # | 1290 # |
1287 # [p:foo, i:bar, x:baz] | 1291 # [p:foo, i:bar, x:baz] |
1288 # | 1292 # |
1292 # a revision identifier, or the empty string to reference the | 1296 # a revision identifier, or the empty string to reference the |
1293 # working directory, from which the match object is | 1297 # working directory, from which the match object is |
1294 # initialized. Use 'd:' to set the default matching mode, default | 1298 # initialized. Use 'd:' to set the default matching mode, default |
1295 # to 'glob'. At most one 'r:' and 'd:' argument can be passed. | 1299 # to 'glob'. At most one 'r:' and 'd:' argument can be passed. |
1296 | 1300 |
1297 l = getargs(x, 1, -1, "_matchfiles requires at least one argument") | 1301 l = getargs(x, 1, -1, b"_matchfiles requires at least one argument") |
1298 pats, inc, exc = [], [], [] | 1302 pats, inc, exc = [], [], [] |
1299 rev, default = None, None | 1303 rev, default = None, None |
1300 for arg in l: | 1304 for arg in l: |
1301 s = getstring(arg, "_matchfiles requires string arguments") | 1305 s = getstring(arg, b"_matchfiles requires string arguments") |
1302 prefix, value = s[:2], s[2:] | 1306 prefix, value = s[:2], s[2:] |
1303 if prefix == 'p:': | 1307 if prefix == b'p:': |
1304 pats.append(value) | 1308 pats.append(value) |
1305 elif prefix == 'i:': | 1309 elif prefix == b'i:': |
1306 inc.append(value) | 1310 inc.append(value) |
1307 elif prefix == 'x:': | 1311 elif prefix == b'x:': |
1308 exc.append(value) | 1312 exc.append(value) |
1309 elif prefix == 'r:': | 1313 elif prefix == b'r:': |
1310 if rev is not None: | 1314 if rev is not None: |
1311 raise error.ParseError( | 1315 raise error.ParseError( |
1312 '_matchfiles expected at most one ' 'revision' | 1316 b'_matchfiles expected at most one ' b'revision' |
1313 ) | 1317 ) |
1314 if value == '': # empty means working directory | 1318 if value == b'': # empty means working directory |
1315 rev = node.wdirrev | 1319 rev = node.wdirrev |
1316 else: | 1320 else: |
1317 rev = value | 1321 rev = value |
1318 elif prefix == 'd:': | 1322 elif prefix == b'd:': |
1319 if default is not None: | 1323 if default is not None: |
1320 raise error.ParseError( | 1324 raise error.ParseError( |
1321 '_matchfiles expected at most one ' 'default mode' | 1325 b'_matchfiles expected at most one ' b'default mode' |
1322 ) | 1326 ) |
1323 default = value | 1327 default = value |
1324 else: | 1328 else: |
1325 raise error.ParseError('invalid _matchfiles prefix: %s' % prefix) | 1329 raise error.ParseError(b'invalid _matchfiles prefix: %s' % prefix) |
1326 if not default: | 1330 if not default: |
1327 default = 'glob' | 1331 default = b'glob' |
1328 hasset = any(matchmod.patkind(p) == 'set' for p in pats + inc + exc) | 1332 hasset = any(matchmod.patkind(p) == b'set' for p in pats + inc + exc) |
1329 | 1333 |
1330 mcache = [None] | 1334 mcache = [None] |
1331 | 1335 |
1332 # This directly read the changelog data as creating changectx for all | 1336 # This directly read the changelog data as creating changectx for all |
1333 # revisions is quite expensive. | 1337 # revisions is quite expensive. |
1359 return False | 1363 return False |
1360 | 1364 |
1361 return subset.filter( | 1365 return subset.filter( |
1362 matches, | 1366 matches, |
1363 condrepr=( | 1367 condrepr=( |
1364 '<matchfiles patterns=%r, include=%r ' | 1368 b'<matchfiles patterns=%r, include=%r ' |
1365 'exclude=%r, default=%r, rev=%r>', | 1369 b'exclude=%r, default=%r, rev=%r>', |
1366 pats, | 1370 pats, |
1367 inc, | 1371 inc, |
1368 exc, | 1372 exc, |
1369 default, | 1373 default, |
1370 rev, | 1374 rev, |
1371 ), | 1375 ), |
1372 ) | 1376 ) |
1373 | 1377 |
1374 | 1378 |
1375 @predicate('file(pattern)', safe=True, weight=10) | 1379 @predicate(b'file(pattern)', safe=True, weight=10) |
1376 def hasfile(repo, subset, x): | 1380 def hasfile(repo, subset, x): |
1377 """Changesets affecting files matched by pattern. | 1381 """Changesets affecting files matched by pattern. |
1378 | 1382 |
1379 For a faster but less accurate result, consider using ``filelog()`` | 1383 For a faster but less accurate result, consider using ``filelog()`` |
1380 instead. | 1384 instead. |
1381 | 1385 |
1382 This predicate uses ``glob:`` as the default kind of pattern. | 1386 This predicate uses ``glob:`` as the default kind of pattern. |
1383 """ | 1387 """ |
1384 # i18n: "file" is a keyword | 1388 # i18n: "file" is a keyword |
1385 pat = getstring(x, _("file requires a pattern")) | 1389 pat = getstring(x, _(b"file requires a pattern")) |
1386 return _matchfiles(repo, subset, ('string', 'p:' + pat)) | 1390 return _matchfiles(repo, subset, (b'string', b'p:' + pat)) |
1387 | 1391 |
1388 | 1392 |
1389 @predicate('head()', safe=True) | 1393 @predicate(b'head()', safe=True) |
1390 def head(repo, subset, x): | 1394 def head(repo, subset, x): |
1391 """Changeset is a named branch head. | 1395 """Changeset is a named branch head. |
1392 """ | 1396 """ |
1393 # i18n: "head" is a keyword | 1397 # i18n: "head" is a keyword |
1394 getargs(x, 0, 0, _("head takes no arguments")) | 1398 getargs(x, 0, 0, _(b"head takes no arguments")) |
1395 hs = set() | 1399 hs = set() |
1396 cl = repo.changelog | 1400 cl = repo.changelog |
1397 for ls in repo.branchmap().iterheads(): | 1401 for ls in repo.branchmap().iterheads(): |
1398 hs.update(cl.rev(h) for h in ls) | 1402 hs.update(cl.rev(h) for h in ls) |
1399 return subset & baseset(hs) | 1403 return subset & baseset(hs) |
1400 | 1404 |
1401 | 1405 |
1402 @predicate('heads(set)', safe=True, takeorder=True) | 1406 @predicate(b'heads(set)', safe=True, takeorder=True) |
1403 def heads(repo, subset, x, order): | 1407 def heads(repo, subset, x, order): |
1404 """Members of set with no children in set. | 1408 """Members of set with no children in set. |
1405 """ | 1409 """ |
1406 # argument set should never define order | 1410 # argument set should never define order |
1407 if order == defineorder: | 1411 if order == defineorder: |
1419 heads.add(node.wdirrev) | 1423 heads.add(node.wdirrev) |
1420 heads = baseset(heads) | 1424 heads = baseset(heads) |
1421 return subset & heads | 1425 return subset & heads |
1422 | 1426 |
1423 | 1427 |
1424 @predicate('hidden()', safe=True) | 1428 @predicate(b'hidden()', safe=True) |
1425 def hidden(repo, subset, x): | 1429 def hidden(repo, subset, x): |
1426 """Hidden changesets. | 1430 """Hidden changesets. |
1427 """ | 1431 """ |
1428 # i18n: "hidden" is a keyword | 1432 # i18n: "hidden" is a keyword |
1429 getargs(x, 0, 0, _("hidden takes no arguments")) | 1433 getargs(x, 0, 0, _(b"hidden takes no arguments")) |
1430 hiddenrevs = repoview.filterrevs(repo, 'visible') | 1434 hiddenrevs = repoview.filterrevs(repo, b'visible') |
1431 return subset & hiddenrevs | 1435 return subset & hiddenrevs |
1432 | 1436 |
1433 | 1437 |
1434 @predicate('keyword(string)', safe=True, weight=10) | 1438 @predicate(b'keyword(string)', safe=True, weight=10) |
1435 def keyword(repo, subset, x): | 1439 def keyword(repo, subset, x): |
1436 """Search commit message, user name, and names of changed files for | 1440 """Search commit message, user name, and names of changed files for |
1437 string. The match is case-insensitive. | 1441 string. The match is case-insensitive. |
1438 | 1442 |
1439 For a regular expression or case sensitive search of these fields, use | 1443 For a regular expression or case sensitive search of these fields, use |
1440 ``grep(regex)``. | 1444 ``grep(regex)``. |
1441 """ | 1445 """ |
1442 # i18n: "keyword" is a keyword | 1446 # i18n: "keyword" is a keyword |
1443 kw = encoding.lower(getstring(x, _("keyword requires a string"))) | 1447 kw = encoding.lower(getstring(x, _(b"keyword requires a string"))) |
1444 | 1448 |
1445 def matches(r): | 1449 def matches(r): |
1446 c = repo[r] | 1450 c = repo[r] |
1447 return any( | 1451 return any( |
1448 kw in encoding.lower(t) | 1452 kw in encoding.lower(t) |
1449 for t in c.files() + [c.user(), c.description()] | 1453 for t in c.files() + [c.user(), c.description()] |
1450 ) | 1454 ) |
1451 | 1455 |
1452 return subset.filter(matches, condrepr=('<keyword %r>', kw)) | 1456 return subset.filter(matches, condrepr=(b'<keyword %r>', kw)) |
1453 | 1457 |
1454 | 1458 |
1455 @predicate('limit(set[, n[, offset]])', safe=True, takeorder=True, weight=0) | 1459 @predicate(b'limit(set[, n[, offset]])', safe=True, takeorder=True, weight=0) |
1456 def limit(repo, subset, x, order): | 1460 def limit(repo, subset, x, order): |
1457 """First n members of set, defaulting to 1, starting from offset. | 1461 """First n members of set, defaulting to 1, starting from offset. |
1458 """ | 1462 """ |
1459 args = getargsdict(x, 'limit', 'set n offset') | 1463 args = getargsdict(x, b'limit', b'set n offset') |
1460 if 'set' not in args: | 1464 if b'set' not in args: |
1461 # i18n: "limit" is a keyword | 1465 # i18n: "limit" is a keyword |
1462 raise error.ParseError(_("limit requires one to three arguments")) | 1466 raise error.ParseError(_(b"limit requires one to three arguments")) |
1463 # i18n: "limit" is a keyword | 1467 # i18n: "limit" is a keyword |
1464 lim = getinteger(args.get('n'), _("limit expects a number"), default=1) | 1468 lim = getinteger(args.get(b'n'), _(b"limit expects a number"), default=1) |
1465 if lim < 0: | 1469 if lim < 0: |
1466 raise error.ParseError(_("negative number to select")) | 1470 raise error.ParseError(_(b"negative number to select")) |
1467 # i18n: "limit" is a keyword | 1471 # i18n: "limit" is a keyword |
1468 ofs = getinteger(args.get('offset'), _("limit expects a number"), default=0) | 1472 ofs = getinteger( |
1473 args.get(b'offset'), _(b"limit expects a number"), default=0 | |
1474 ) | |
1469 if ofs < 0: | 1475 if ofs < 0: |
1470 raise error.ParseError(_("negative offset")) | 1476 raise error.ParseError(_(b"negative offset")) |
1471 os = getset(repo, fullreposet(repo), args['set']) | 1477 os = getset(repo, fullreposet(repo), args[b'set']) |
1472 ls = os.slice(ofs, ofs + lim) | 1478 ls = os.slice(ofs, ofs + lim) |
1473 if order == followorder and lim > 1: | 1479 if order == followorder and lim > 1: |
1474 return subset & ls | 1480 return subset & ls |
1475 return ls & subset | 1481 return ls & subset |
1476 | 1482 |
1477 | 1483 |
1478 @predicate('last(set, [n])', safe=True, takeorder=True) | 1484 @predicate(b'last(set, [n])', safe=True, takeorder=True) |
1479 def last(repo, subset, x, order): | 1485 def last(repo, subset, x, order): |
1480 """Last n members of set, defaulting to 1. | 1486 """Last n members of set, defaulting to 1. |
1481 """ | 1487 """ |
1482 # i18n: "last" is a keyword | 1488 # i18n: "last" is a keyword |
1483 l = getargs(x, 1, 2, _("last requires one or two arguments")) | 1489 l = getargs(x, 1, 2, _(b"last requires one or two arguments")) |
1484 lim = 1 | 1490 lim = 1 |
1485 if len(l) == 2: | 1491 if len(l) == 2: |
1486 # i18n: "last" is a keyword | 1492 # i18n: "last" is a keyword |
1487 lim = getinteger(l[1], _("last expects a number")) | 1493 lim = getinteger(l[1], _(b"last expects a number")) |
1488 if lim < 0: | 1494 if lim < 0: |
1489 raise error.ParseError(_("negative number to select")) | 1495 raise error.ParseError(_(b"negative number to select")) |
1490 os = getset(repo, fullreposet(repo), l[0]) | 1496 os = getset(repo, fullreposet(repo), l[0]) |
1491 os.reverse() | 1497 os.reverse() |
1492 ls = os.slice(0, lim) | 1498 ls = os.slice(0, lim) |
1493 if order == followorder and lim > 1: | 1499 if order == followorder and lim > 1: |
1494 return subset & ls | 1500 return subset & ls |
1495 ls.reverse() | 1501 ls.reverse() |
1496 return ls & subset | 1502 return ls & subset |
1497 | 1503 |
1498 | 1504 |
1499 @predicate('max(set)', safe=True) | 1505 @predicate(b'max(set)', safe=True) |
1500 def maxrev(repo, subset, x): | 1506 def maxrev(repo, subset, x): |
1501 """Changeset with highest revision number in set. | 1507 """Changeset with highest revision number in set. |
1502 """ | 1508 """ |
1503 os = getset(repo, fullreposet(repo), x) | 1509 os = getset(repo, fullreposet(repo), x) |
1504 try: | 1510 try: |
1505 m = os.max() | 1511 m = os.max() |
1506 if m in subset: | 1512 if m in subset: |
1507 return baseset([m], datarepr=('<max %r, %r>', subset, os)) | 1513 return baseset([m], datarepr=(b'<max %r, %r>', subset, os)) |
1508 except ValueError: | 1514 except ValueError: |
1509 # os.max() throws a ValueError when the collection is empty. | 1515 # os.max() throws a ValueError when the collection is empty. |
1510 # Same as python's max(). | 1516 # Same as python's max(). |
1511 pass | 1517 pass |
1512 return baseset(datarepr=('<max %r, %r>', subset, os)) | 1518 return baseset(datarepr=(b'<max %r, %r>', subset, os)) |
1513 | 1519 |
1514 | 1520 |
1515 @predicate('merge()', safe=True) | 1521 @predicate(b'merge()', safe=True) |
1516 def merge(repo, subset, x): | 1522 def merge(repo, subset, x): |
1517 """Changeset is a merge changeset. | 1523 """Changeset is a merge changeset. |
1518 """ | 1524 """ |
1519 # i18n: "merge" is a keyword | 1525 # i18n: "merge" is a keyword |
1520 getargs(x, 0, 0, _("merge takes no arguments")) | 1526 getargs(x, 0, 0, _(b"merge takes no arguments")) |
1521 cl = repo.changelog | 1527 cl = repo.changelog |
1522 nullrev = node.nullrev | 1528 nullrev = node.nullrev |
1523 | 1529 |
1524 def ismerge(r): | 1530 def ismerge(r): |
1525 try: | 1531 try: |
1526 return cl.parentrevs(r)[1] != nullrev | 1532 return cl.parentrevs(r)[1] != nullrev |
1527 except error.WdirUnsupported: | 1533 except error.WdirUnsupported: |
1528 return bool(repo[r].p2()) | 1534 return bool(repo[r].p2()) |
1529 | 1535 |
1530 return subset.filter(ismerge, condrepr='<merge>') | 1536 return subset.filter(ismerge, condrepr=b'<merge>') |
1531 | 1537 |
1532 | 1538 |
1533 @predicate('branchpoint()', safe=True) | 1539 @predicate(b'branchpoint()', safe=True) |
1534 def branchpoint(repo, subset, x): | 1540 def branchpoint(repo, subset, x): |
1535 """Changesets with more than one child. | 1541 """Changesets with more than one child. |
1536 """ | 1542 """ |
1537 # i18n: "branchpoint" is a keyword | 1543 # i18n: "branchpoint" is a keyword |
1538 getargs(x, 0, 0, _("branchpoint takes no arguments")) | 1544 getargs(x, 0, 0, _(b"branchpoint takes no arguments")) |
1539 cl = repo.changelog | 1545 cl = repo.changelog |
1540 if not subset: | 1546 if not subset: |
1541 return baseset() | 1547 return baseset() |
1542 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset | 1548 # XXX this should be 'parentset.min()' assuming 'parentset' is a smartset |
1543 # (and if it is not, it should.) | 1549 # (and if it is not, it should.) |
1546 for r in cl.revs(start=baserev + 1): | 1552 for r in cl.revs(start=baserev + 1): |
1547 for p in cl.parentrevs(r): | 1553 for p in cl.parentrevs(r): |
1548 if p >= baserev: | 1554 if p >= baserev: |
1549 parentscount[p - baserev] += 1 | 1555 parentscount[p - baserev] += 1 |
1550 return subset.filter( | 1556 return subset.filter( |
1551 lambda r: parentscount[r - baserev] > 1, condrepr='<branchpoint>' | 1557 lambda r: parentscount[r - baserev] > 1, condrepr=b'<branchpoint>' |
1552 ) | 1558 ) |
1553 | 1559 |
1554 | 1560 |
1555 @predicate('min(set)', safe=True) | 1561 @predicate(b'min(set)', safe=True) |
1556 def minrev(repo, subset, x): | 1562 def minrev(repo, subset, x): |
1557 """Changeset with lowest revision number in set. | 1563 """Changeset with lowest revision number in set. |
1558 """ | 1564 """ |
1559 os = getset(repo, fullreposet(repo), x) | 1565 os = getset(repo, fullreposet(repo), x) |
1560 try: | 1566 try: |
1561 m = os.min() | 1567 m = os.min() |
1562 if m in subset: | 1568 if m in subset: |
1563 return baseset([m], datarepr=('<min %r, %r>', subset, os)) | 1569 return baseset([m], datarepr=(b'<min %r, %r>', subset, os)) |
1564 except ValueError: | 1570 except ValueError: |
1565 # os.min() throws a ValueError when the collection is empty. | 1571 # os.min() throws a ValueError when the collection is empty. |
1566 # Same as python's min(). | 1572 # Same as python's min(). |
1567 pass | 1573 pass |
1568 return baseset(datarepr=('<min %r, %r>', subset, os)) | 1574 return baseset(datarepr=(b'<min %r, %r>', subset, os)) |
1569 | 1575 |
1570 | 1576 |
1571 @predicate('modifies(pattern)', safe=True, weight=30) | 1577 @predicate(b'modifies(pattern)', safe=True, weight=30) |
1572 def modifies(repo, subset, x): | 1578 def modifies(repo, subset, x): |
1573 """Changesets modifying files matched by pattern. | 1579 """Changesets modifying files matched by pattern. |
1574 | 1580 |
1575 The pattern without explicit kind like ``glob:`` is expected to be | 1581 The pattern without explicit kind like ``glob:`` is expected to be |
1576 relative to the current directory and match against a file or a | 1582 relative to the current directory and match against a file or a |
1577 directory. | 1583 directory. |
1578 """ | 1584 """ |
1579 # i18n: "modifies" is a keyword | 1585 # i18n: "modifies" is a keyword |
1580 pat = getstring(x, _("modifies requires a pattern")) | 1586 pat = getstring(x, _(b"modifies requires a pattern")) |
1581 return checkstatus(repo, subset, pat, 0) | 1587 return checkstatus(repo, subset, pat, 0) |
1582 | 1588 |
1583 | 1589 |
1584 @predicate('named(namespace)') | 1590 @predicate(b'named(namespace)') |
1585 def named(repo, subset, x): | 1591 def named(repo, subset, x): |
1586 """The changesets in a given namespace. | 1592 """The changesets in a given namespace. |
1587 | 1593 |
1588 Pattern matching is supported for `namespace`. See | 1594 Pattern matching is supported for `namespace`. See |
1589 :hg:`help revisions.patterns`. | 1595 :hg:`help revisions.patterns`. |
1590 """ | 1596 """ |
1591 # i18n: "named" is a keyword | 1597 # i18n: "named" is a keyword |
1592 args = getargs(x, 1, 1, _('named requires a namespace argument')) | 1598 args = getargs(x, 1, 1, _(b'named requires a namespace argument')) |
1593 | 1599 |
1594 ns = getstring( | 1600 ns = getstring( |
1595 args[0], | 1601 args[0], |
1596 # i18n: "named" is a keyword | 1602 # i18n: "named" is a keyword |
1597 _('the argument to named must be a string'), | 1603 _(b'the argument to named must be a string'), |
1598 ) | 1604 ) |
1599 kind, pattern, matcher = stringutil.stringmatcher(ns) | 1605 kind, pattern, matcher = stringutil.stringmatcher(ns) |
1600 namespaces = set() | 1606 namespaces = set() |
1601 if kind == 'literal': | 1607 if kind == b'literal': |
1602 if pattern not in repo.names: | 1608 if pattern not in repo.names: |
1603 raise error.RepoLookupError(_("namespace '%s' does not exist") % ns) | 1609 raise error.RepoLookupError( |
1610 _(b"namespace '%s' does not exist") % ns | |
1611 ) | |
1604 namespaces.add(repo.names[pattern]) | 1612 namespaces.add(repo.names[pattern]) |
1605 else: | 1613 else: |
1606 for name, ns in repo.names.iteritems(): | 1614 for name, ns in repo.names.iteritems(): |
1607 if matcher(name): | 1615 if matcher(name): |
1608 namespaces.add(ns) | 1616 namespaces.add(ns) |
1615 | 1623 |
1616 names -= {node.nullrev} | 1624 names -= {node.nullrev} |
1617 return subset & names | 1625 return subset & names |
1618 | 1626 |
1619 | 1627 |
1620 @predicate('id(string)', safe=True) | 1628 @predicate(b'id(string)', safe=True) |
1621 def node_(repo, subset, x): | 1629 def node_(repo, subset, x): |
1622 """Revision non-ambiguously specified by the given hex string prefix. | 1630 """Revision non-ambiguously specified by the given hex string prefix. |
1623 """ | 1631 """ |
1624 # i18n: "id" is a keyword | 1632 # i18n: "id" is a keyword |
1625 l = getargs(x, 1, 1, _("id requires one argument")) | 1633 l = getargs(x, 1, 1, _(b"id requires one argument")) |
1626 # i18n: "id" is a keyword | 1634 # i18n: "id" is a keyword |
1627 n = getstring(l[0], _("id requires a string")) | 1635 n = getstring(l[0], _(b"id requires a string")) |
1628 if len(n) == 40: | 1636 if len(n) == 40: |
1629 try: | 1637 try: |
1630 rn = repo.changelog.rev(node.bin(n)) | 1638 rn = repo.changelog.rev(node.bin(n)) |
1631 except error.WdirUnsupported: | 1639 except error.WdirUnsupported: |
1632 rn = node.wdirrev | 1640 rn = node.wdirrev |
1647 return baseset() | 1655 return baseset() |
1648 result = baseset([rn]) | 1656 result = baseset([rn]) |
1649 return result & subset | 1657 return result & subset |
1650 | 1658 |
1651 | 1659 |
1652 @predicate('none()', safe=True) | 1660 @predicate(b'none()', safe=True) |
1653 def none(repo, subset, x): | 1661 def none(repo, subset, x): |
1654 """No changesets. | 1662 """No changesets. |
1655 """ | 1663 """ |
1656 # i18n: "none" is a keyword | 1664 # i18n: "none" is a keyword |
1657 getargs(x, 0, 0, _("none takes no arguments")) | 1665 getargs(x, 0, 0, _(b"none takes no arguments")) |
1658 return baseset() | 1666 return baseset() |
1659 | 1667 |
1660 | 1668 |
1661 @predicate('obsolete()', safe=True) | 1669 @predicate(b'obsolete()', safe=True) |
1662 def obsolete(repo, subset, x): | 1670 def obsolete(repo, subset, x): |
1663 """Mutable changeset with a newer version.""" | 1671 """Mutable changeset with a newer version.""" |
1664 # i18n: "obsolete" is a keyword | 1672 # i18n: "obsolete" is a keyword |
1665 getargs(x, 0, 0, _("obsolete takes no arguments")) | 1673 getargs(x, 0, 0, _(b"obsolete takes no arguments")) |
1666 obsoletes = obsmod.getrevs(repo, 'obsolete') | 1674 obsoletes = obsmod.getrevs(repo, b'obsolete') |
1667 return subset & obsoletes | 1675 return subset & obsoletes |
1668 | 1676 |
1669 | 1677 |
1670 @predicate('only(set, [set])', safe=True) | 1678 @predicate(b'only(set, [set])', safe=True) |
1671 def only(repo, subset, x): | 1679 def only(repo, subset, x): |
1672 """Changesets that are ancestors of the first set that are not ancestors | 1680 """Changesets that are ancestors of the first set that are not ancestors |
1673 of any other head in the repo. If a second set is specified, the result | 1681 of any other head in the repo. If a second set is specified, the result |
1674 is ancestors of the first set that are not ancestors of the second set | 1682 is ancestors of the first set that are not ancestors of the second set |
1675 (i.e. ::<set1> - ::<set2>). | 1683 (i.e. ::<set1> - ::<set2>). |
1676 """ | 1684 """ |
1677 cl = repo.changelog | 1685 cl = repo.changelog |
1678 # i18n: "only" is a keyword | 1686 # i18n: "only" is a keyword |
1679 args = getargs(x, 1, 2, _('only takes one or two arguments')) | 1687 args = getargs(x, 1, 2, _(b'only takes one or two arguments')) |
1680 include = getset(repo, fullreposet(repo), args[0]) | 1688 include = getset(repo, fullreposet(repo), args[0]) |
1681 if len(args) == 1: | 1689 if len(args) == 1: |
1682 if not include: | 1690 if not include: |
1683 return baseset() | 1691 return baseset() |
1684 | 1692 |
1695 # XXX we should turn this into a baseset instead of a set, smartset may do | 1703 # XXX we should turn this into a baseset instead of a set, smartset may do |
1696 # some optimizations from the fact this is a baseset. | 1704 # some optimizations from the fact this is a baseset. |
1697 return subset & results | 1705 return subset & results |
1698 | 1706 |
1699 | 1707 |
1700 @predicate('origin([set])', safe=True) | 1708 @predicate(b'origin([set])', safe=True) |
1701 def origin(repo, subset, x): | 1709 def origin(repo, subset, x): |
1702 """ | 1710 """ |
1703 Changesets that were specified as a source for the grafts, transplants or | 1711 Changesets that were specified as a source for the grafts, transplants or |
1704 rebases that created the given revisions. Omitting the optional set is the | 1712 rebases that created the given revisions. Omitting the optional set is the |
1705 same as passing all(). If a changeset created by these operations is itself | 1713 same as passing all(). If a changeset created by these operations is itself |
1728 # XXX we should turn this into a baseset instead of a set, smartset may do | 1736 # XXX we should turn this into a baseset instead of a set, smartset may do |
1729 # some optimizations from the fact this is a baseset. | 1737 # some optimizations from the fact this is a baseset. |
1730 return subset & o | 1738 return subset & o |
1731 | 1739 |
1732 | 1740 |
1733 @predicate('outgoing([path])', safe=False, weight=10) | 1741 @predicate(b'outgoing([path])', safe=False, weight=10) |
1734 def outgoing(repo, subset, x): | 1742 def outgoing(repo, subset, x): |
1735 """Changesets not found in the specified destination repository, or the | 1743 """Changesets not found in the specified destination repository, or the |
1736 default push location. | 1744 default push location. |
1737 """ | 1745 """ |
1738 # Avoid cycles. | 1746 # Avoid cycles. |
1740 discovery, | 1748 discovery, |
1741 hg, | 1749 hg, |
1742 ) | 1750 ) |
1743 | 1751 |
1744 # i18n: "outgoing" is a keyword | 1752 # i18n: "outgoing" is a keyword |
1745 l = getargs(x, 0, 1, _("outgoing takes one or no arguments")) | 1753 l = getargs(x, 0, 1, _(b"outgoing takes one or no arguments")) |
1746 # i18n: "outgoing" is a keyword | 1754 # i18n: "outgoing" is a keyword |
1747 dest = l and getstring(l[0], _("outgoing requires a repository path")) or '' | 1755 dest = ( |
1756 l and getstring(l[0], _(b"outgoing requires a repository path")) or b'' | |
1757 ) | |
1748 if not dest: | 1758 if not dest: |
1749 # ui.paths.getpath() explicitly tests for None, not just a boolean | 1759 # ui.paths.getpath() explicitly tests for None, not just a boolean |
1750 dest = None | 1760 dest = None |
1751 path = repo.ui.paths.getpath(dest, default=('default-push', 'default')) | 1761 path = repo.ui.paths.getpath(dest, default=(b'default-push', b'default')) |
1752 if not path: | 1762 if not path: |
1753 raise error.Abort( | 1763 raise error.Abort( |
1754 _('default repository not configured!'), | 1764 _(b'default repository not configured!'), |
1755 hint=_("see 'hg help config.paths'"), | 1765 hint=_(b"see 'hg help config.paths'"), |
1756 ) | 1766 ) |
1757 dest = path.pushloc or path.loc | 1767 dest = path.pushloc or path.loc |
1758 branches = path.branch, [] | 1768 branches = path.branch, [] |
1759 | 1769 |
1760 revs, checkout = hg.addbranchrevs(repo, repo, branches, []) | 1770 revs, checkout = hg.addbranchrevs(repo, repo, branches, []) |
1767 cl = repo.changelog | 1777 cl = repo.changelog |
1768 o = {cl.rev(r) for r in outgoing.missing} | 1778 o = {cl.rev(r) for r in outgoing.missing} |
1769 return subset & o | 1779 return subset & o |
1770 | 1780 |
1771 | 1781 |
1772 @predicate('p1([set])', safe=True) | 1782 @predicate(b'p1([set])', safe=True) |
1773 def p1(repo, subset, x): | 1783 def p1(repo, subset, x): |
1774 """First parent of changesets in set, or the working directory. | 1784 """First parent of changesets in set, or the working directory. |
1775 """ | 1785 """ |
1776 if x is None: | 1786 if x is None: |
1777 p = repo[x].p1().rev() | 1787 p = repo[x].p1().rev() |
1790 # XXX we should turn this into a baseset instead of a set, smartset may do | 1800 # XXX we should turn this into a baseset instead of a set, smartset may do |
1791 # some optimizations from the fact this is a baseset. | 1801 # some optimizations from the fact this is a baseset. |
1792 return subset & ps | 1802 return subset & ps |
1793 | 1803 |
1794 | 1804 |
1795 @predicate('p2([set])', safe=True) | 1805 @predicate(b'p2([set])', safe=True) |
1796 def p2(repo, subset, x): | 1806 def p2(repo, subset, x): |
1797 """Second parent of changesets in set, or the working directory. | 1807 """Second parent of changesets in set, or the working directory. |
1798 """ | 1808 """ |
1799 if x is None: | 1809 if x is None: |
1800 ps = repo[x].parents() | 1810 ps = repo[x].parents() |
1823 | 1833 |
1824 def parentpost(repo, subset, x, order): | 1834 def parentpost(repo, subset, x, order): |
1825 return p1(repo, subset, x) | 1835 return p1(repo, subset, x) |
1826 | 1836 |
1827 | 1837 |
1828 @predicate('parents([set])', safe=True) | 1838 @predicate(b'parents([set])', safe=True) |
1829 def parents(repo, subset, x): | 1839 def parents(repo, subset, x): |
1830 """ | 1840 """ |
1831 The set of all parents for all changesets in set, or the working directory. | 1841 The set of all parents for all changesets in set, or the working directory. |
1832 """ | 1842 """ |
1833 if x is None: | 1843 if x is None: |
1849 def _phase(repo, subset, *targets): | 1859 def _phase(repo, subset, *targets): |
1850 """helper to select all rev in <targets> phases""" | 1860 """helper to select all rev in <targets> phases""" |
1851 return repo._phasecache.getrevset(repo, targets, subset) | 1861 return repo._phasecache.getrevset(repo, targets, subset) |
1852 | 1862 |
1853 | 1863 |
1854 @predicate('_phase(idx)', safe=True) | 1864 @predicate(b'_phase(idx)', safe=True) |
1855 def phase(repo, subset, x): | 1865 def phase(repo, subset, x): |
1856 l = getargs(x, 1, 1, "_phase requires one argument") | 1866 l = getargs(x, 1, 1, b"_phase requires one argument") |
1857 target = getinteger(l[0], "_phase expects a number") | 1867 target = getinteger(l[0], b"_phase expects a number") |
1858 return _phase(repo, subset, target) | 1868 return _phase(repo, subset, target) |
1859 | 1869 |
1860 | 1870 |
1861 @predicate('draft()', safe=True) | 1871 @predicate(b'draft()', safe=True) |
1862 def draft(repo, subset, x): | 1872 def draft(repo, subset, x): |
1863 """Changeset in draft phase.""" | 1873 """Changeset in draft phase.""" |
1864 # i18n: "draft" is a keyword | 1874 # i18n: "draft" is a keyword |
1865 getargs(x, 0, 0, _("draft takes no arguments")) | 1875 getargs(x, 0, 0, _(b"draft takes no arguments")) |
1866 target = phases.draft | 1876 target = phases.draft |
1867 return _phase(repo, subset, target) | 1877 return _phase(repo, subset, target) |
1868 | 1878 |
1869 | 1879 |
1870 @predicate('secret()', safe=True) | 1880 @predicate(b'secret()', safe=True) |
1871 def secret(repo, subset, x): | 1881 def secret(repo, subset, x): |
1872 """Changeset in secret phase.""" | 1882 """Changeset in secret phase.""" |
1873 # i18n: "secret" is a keyword | 1883 # i18n: "secret" is a keyword |
1874 getargs(x, 0, 0, _("secret takes no arguments")) | 1884 getargs(x, 0, 0, _(b"secret takes no arguments")) |
1875 target = phases.secret | 1885 target = phases.secret |
1876 return _phase(repo, subset, target) | 1886 return _phase(repo, subset, target) |
1877 | 1887 |
1878 | 1888 |
1879 @predicate('stack([revs])', safe=True) | 1889 @predicate(b'stack([revs])', safe=True) |
1880 def stack(repo, subset, x): | 1890 def stack(repo, subset, x): |
1881 """Experimental revset for the stack of changesets or working directory | 1891 """Experimental revset for the stack of changesets or working directory |
1882 parent. (EXPERIMENTAL) | 1892 parent. (EXPERIMENTAL) |
1883 """ | 1893 """ |
1884 if x is None: | 1894 if x is None: |
1901 try: | 1911 try: |
1902 n = int(n[1]) | 1912 n = int(n[1]) |
1903 if n not in (0, 1, 2): | 1913 if n not in (0, 1, 2): |
1904 raise ValueError | 1914 raise ValueError |
1905 except (TypeError, ValueError): | 1915 except (TypeError, ValueError): |
1906 raise error.ParseError(_("^ expects a number 0, 1, or 2")) | 1916 raise error.ParseError(_(b"^ expects a number 0, 1, or 2")) |
1907 ps = set() | 1917 ps = set() |
1908 cl = repo.changelog | 1918 cl = repo.changelog |
1909 for r in getset(repo, fullreposet(repo), x): | 1919 for r in getset(repo, fullreposet(repo), x): |
1910 if n == 0: | 1920 if n == 0: |
1911 ps.add(r) | 1921 ps.add(r) |
1924 if len(parents) == 2: | 1934 if len(parents) == 2: |
1925 ps.add(parents[1].rev()) | 1935 ps.add(parents[1].rev()) |
1926 return subset & ps | 1936 return subset & ps |
1927 | 1937 |
1928 | 1938 |
1929 @predicate('present(set)', safe=True, takeorder=True) | 1939 @predicate(b'present(set)', safe=True, takeorder=True) |
1930 def present(repo, subset, x, order): | 1940 def present(repo, subset, x, order): |
1931 """An empty set, if any revision in set isn't found; otherwise, | 1941 """An empty set, if any revision in set isn't found; otherwise, |
1932 all revisions in set. | 1942 all revisions in set. |
1933 | 1943 |
1934 If any of specified revisions is not present in the local repository, | 1944 If any of specified revisions is not present in the local repository, |
1940 except error.RepoLookupError: | 1950 except error.RepoLookupError: |
1941 return baseset() | 1951 return baseset() |
1942 | 1952 |
1943 | 1953 |
1944 # for internal use | 1954 # for internal use |
1945 @predicate('_notpublic', safe=True) | 1955 @predicate(b'_notpublic', safe=True) |
1946 def _notpublic(repo, subset, x): | 1956 def _notpublic(repo, subset, x): |
1947 getargs(x, 0, 0, "_notpublic takes no arguments") | 1957 getargs(x, 0, 0, b"_notpublic takes no arguments") |
1948 return _phase(repo, subset, phases.draft, phases.secret) | 1958 return _phase(repo, subset, phases.draft, phases.secret) |
1949 | 1959 |
1950 | 1960 |
1951 # for internal use | 1961 # for internal use |
1952 @predicate('_phaseandancestors(phasename, set)', safe=True) | 1962 @predicate(b'_phaseandancestors(phasename, set)', safe=True) |
1953 def _phaseandancestors(repo, subset, x): | 1963 def _phaseandancestors(repo, subset, x): |
1954 # equivalent to (phasename() & ancestors(set)) but more efficient | 1964 # equivalent to (phasename() & ancestors(set)) but more efficient |
1955 # phasename could be one of 'draft', 'secret', or '_notpublic' | 1965 # phasename could be one of 'draft', 'secret', or '_notpublic' |
1956 args = getargs(x, 2, 2, "_phaseandancestors requires two arguments") | 1966 args = getargs(x, 2, 2, b"_phaseandancestors requires two arguments") |
1957 phasename = getsymbol(args[0]) | 1967 phasename = getsymbol(args[0]) |
1958 s = getset(repo, fullreposet(repo), args[1]) | 1968 s = getset(repo, fullreposet(repo), args[1]) |
1959 | 1969 |
1960 draft = phases.draft | 1970 draft = phases.draft |
1961 secret = phases.secret | 1971 secret = phases.secret |
1962 phasenamemap = { | 1972 phasenamemap = { |
1963 '_notpublic': draft, | 1973 b'_notpublic': draft, |
1964 'draft': draft, # follow secret's ancestors | 1974 b'draft': draft, # follow secret's ancestors |
1965 'secret': secret, | 1975 b'secret': secret, |
1966 } | 1976 } |
1967 if phasename not in phasenamemap: | 1977 if phasename not in phasenamemap: |
1968 raise error.ParseError('%r is not a valid phasename' % phasename) | 1978 raise error.ParseError(b'%r is not a valid phasename' % phasename) |
1969 | 1979 |
1970 minimalphase = phasenamemap[phasename] | 1980 minimalphase = phasenamemap[phasename] |
1971 getphase = repo._phasecache.phase | 1981 getphase = repo._phasecache.phase |
1972 | 1982 |
1973 def cutfunc(rev): | 1983 def cutfunc(rev): |
1974 return getphase(repo, rev) < minimalphase | 1984 return getphase(repo, rev) < minimalphase |
1975 | 1985 |
1976 revs = dagop.revancestors(repo, s, cutfunc=cutfunc) | 1986 revs = dagop.revancestors(repo, s, cutfunc=cutfunc) |
1977 | 1987 |
1978 if phasename == 'draft': # need to remove secret changesets | 1988 if phasename == b'draft': # need to remove secret changesets |
1979 revs = revs.filter(lambda r: getphase(repo, r) == draft) | 1989 revs = revs.filter(lambda r: getphase(repo, r) == draft) |
1980 return subset & revs | 1990 return subset & revs |
1981 | 1991 |
1982 | 1992 |
1983 @predicate('public()', safe=True) | 1993 @predicate(b'public()', safe=True) |
1984 def public(repo, subset, x): | 1994 def public(repo, subset, x): |
1985 """Changeset in public phase.""" | 1995 """Changeset in public phase.""" |
1986 # i18n: "public" is a keyword | 1996 # i18n: "public" is a keyword |
1987 getargs(x, 0, 0, _("public takes no arguments")) | 1997 getargs(x, 0, 0, _(b"public takes no arguments")) |
1988 return _phase(repo, subset, phases.public) | 1998 return _phase(repo, subset, phases.public) |
1989 | 1999 |
1990 | 2000 |
1991 @predicate('remote([id [,path]])', safe=False) | 2001 @predicate(b'remote([id [,path]])', safe=False) |
1992 def remote(repo, subset, x): | 2002 def remote(repo, subset, x): |
1993 """Local revision that corresponds to the given identifier in a | 2003 """Local revision that corresponds to the given identifier in a |
1994 remote repository, if present. Here, the '.' identifier is a | 2004 remote repository, if present. Here, the '.' identifier is a |
1995 synonym for the current local branch. | 2005 synonym for the current local branch. |
1996 """ | 2006 """ |
1997 | 2007 |
1998 from . import hg # avoid start-up nasties | 2008 from . import hg # avoid start-up nasties |
1999 | 2009 |
2000 # i18n: "remote" is a keyword | 2010 # i18n: "remote" is a keyword |
2001 l = getargs(x, 0, 2, _("remote takes zero, one, or two arguments")) | 2011 l = getargs(x, 0, 2, _(b"remote takes zero, one, or two arguments")) |
2002 | 2012 |
2003 q = '.' | 2013 q = b'.' |
2004 if len(l) > 0: | 2014 if len(l) > 0: |
2005 # i18n: "remote" is a keyword | 2015 # i18n: "remote" is a keyword |
2006 q = getstring(l[0], _("remote requires a string id")) | 2016 q = getstring(l[0], _(b"remote requires a string id")) |
2007 if q == '.': | 2017 if q == b'.': |
2008 q = repo['.'].branch() | 2018 q = repo[b'.'].branch() |
2009 | 2019 |
2010 dest = '' | 2020 dest = b'' |
2011 if len(l) > 1: | 2021 if len(l) > 1: |
2012 # i18n: "remote" is a keyword | 2022 # i18n: "remote" is a keyword |
2013 dest = getstring(l[1], _("remote requires a repository path")) | 2023 dest = getstring(l[1], _(b"remote requires a repository path")) |
2014 dest = repo.ui.expandpath(dest or 'default') | 2024 dest = repo.ui.expandpath(dest or b'default') |
2015 dest, branches = hg.parseurl(dest) | 2025 dest, branches = hg.parseurl(dest) |
2016 revs, checkout = hg.addbranchrevs(repo, repo, branches, []) | 2026 revs, checkout = hg.addbranchrevs(repo, repo, branches, []) |
2017 if revs: | 2027 if revs: |
2018 revs = [repo.lookup(rev) for rev in revs] | 2028 revs = [repo.lookup(rev) for rev in revs] |
2019 other = hg.peer(repo, {}, dest) | 2029 other = hg.peer(repo, {}, dest) |
2023 if r in subset: | 2033 if r in subset: |
2024 return baseset([r]) | 2034 return baseset([r]) |
2025 return baseset() | 2035 return baseset() |
2026 | 2036 |
2027 | 2037 |
2028 @predicate('removes(pattern)', safe=True, weight=30) | 2038 @predicate(b'removes(pattern)', safe=True, weight=30) |
2029 def removes(repo, subset, x): | 2039 def removes(repo, subset, x): |
2030 """Changesets which remove files matching pattern. | 2040 """Changesets which remove files matching pattern. |
2031 | 2041 |
2032 The pattern without explicit kind like ``glob:`` is expected to be | 2042 The pattern without explicit kind like ``glob:`` is expected to be |
2033 relative to the current directory and match against a file or a | 2043 relative to the current directory and match against a file or a |
2034 directory. | 2044 directory. |
2035 """ | 2045 """ |
2036 # i18n: "removes" is a keyword | 2046 # i18n: "removes" is a keyword |
2037 pat = getstring(x, _("removes requires a pattern")) | 2047 pat = getstring(x, _(b"removes requires a pattern")) |
2038 return checkstatus(repo, subset, pat, 2) | 2048 return checkstatus(repo, subset, pat, 2) |
2039 | 2049 |
2040 | 2050 |
2041 @predicate('rev(number)', safe=True) | 2051 @predicate(b'rev(number)', safe=True) |
2042 def rev(repo, subset, x): | 2052 def rev(repo, subset, x): |
2043 """Revision with the given numeric identifier. | 2053 """Revision with the given numeric identifier. |
2044 """ | 2054 """ |
2045 # i18n: "rev" is a keyword | 2055 # i18n: "rev" is a keyword |
2046 l = getargs(x, 1, 1, _("rev requires one argument")) | 2056 l = getargs(x, 1, 1, _(b"rev requires one argument")) |
2047 try: | 2057 try: |
2048 # i18n: "rev" is a keyword | 2058 # i18n: "rev" is a keyword |
2049 l = int(getstring(l[0], _("rev requires a number"))) | 2059 l = int(getstring(l[0], _(b"rev requires a number"))) |
2050 except (TypeError, ValueError): | 2060 except (TypeError, ValueError): |
2051 # i18n: "rev" is a keyword | 2061 # i18n: "rev" is a keyword |
2052 raise error.ParseError(_("rev expects a number")) | 2062 raise error.ParseError(_(b"rev expects a number")) |
2053 if l not in repo.changelog and l not in _virtualrevs: | 2063 if l not in repo.changelog and l not in _virtualrevs: |
2054 return baseset() | 2064 return baseset() |
2055 return subset & baseset([l]) | 2065 return subset & baseset([l]) |
2056 | 2066 |
2057 | 2067 |
2058 @predicate('_rev(number)', safe=True) | 2068 @predicate(b'_rev(number)', safe=True) |
2059 def _rev(repo, subset, x): | 2069 def _rev(repo, subset, x): |
2060 # internal version of "rev(x)" that raise error if "x" is invalid | 2070 # internal version of "rev(x)" that raise error if "x" is invalid |
2061 # i18n: "rev" is a keyword | 2071 # i18n: "rev" is a keyword |
2062 l = getargs(x, 1, 1, _("rev requires one argument")) | 2072 l = getargs(x, 1, 1, _(b"rev requires one argument")) |
2063 try: | 2073 try: |
2064 # i18n: "rev" is a keyword | 2074 # i18n: "rev" is a keyword |
2065 l = int(getstring(l[0], _("rev requires a number"))) | 2075 l = int(getstring(l[0], _(b"rev requires a number"))) |
2066 except (TypeError, ValueError): | 2076 except (TypeError, ValueError): |
2067 # i18n: "rev" is a keyword | 2077 # i18n: "rev" is a keyword |
2068 raise error.ParseError(_("rev expects a number")) | 2078 raise error.ParseError(_(b"rev expects a number")) |
2069 repo.changelog.node(l) # check that the rev exists | 2079 repo.changelog.node(l) # check that the rev exists |
2070 return subset & baseset([l]) | 2080 return subset & baseset([l]) |
2071 | 2081 |
2072 | 2082 |
2073 @predicate('revset(set)', safe=True, takeorder=True) | 2083 @predicate(b'revset(set)', safe=True, takeorder=True) |
2074 def revsetpredicate(repo, subset, x, order): | 2084 def revsetpredicate(repo, subset, x, order): |
2075 """Strictly interpret the content as a revset. | 2085 """Strictly interpret the content as a revset. |
2076 | 2086 |
2077 The content of this special predicate will be strictly interpreted as a | 2087 The content of this special predicate will be strictly interpreted as a |
2078 revset. For example, ``revset(id(0))`` will be interpreted as "id(0)" | 2088 revset. For example, ``revset(id(0))`` will be interpreted as "id(0)" |
2079 without possible ambiguity with a "id(0)" bookmark or tag. | 2089 without possible ambiguity with a "id(0)" bookmark or tag. |
2080 """ | 2090 """ |
2081 return getset(repo, subset, x, order) | 2091 return getset(repo, subset, x, order) |
2082 | 2092 |
2083 | 2093 |
2084 @predicate('matching(revision [, field])', safe=True) | 2094 @predicate(b'matching(revision [, field])', safe=True) |
2085 def matching(repo, subset, x): | 2095 def matching(repo, subset, x): |
2086 """Changesets in which a given set of fields match the set of fields in the | 2096 """Changesets in which a given set of fields match the set of fields in the |
2087 selected revision or set. | 2097 selected revision or set. |
2088 | 2098 |
2089 To match more than one field pass the list of fields to match separated | 2099 To match more than one field pass the list of fields to match separated |
2105 | 2115 |
2106 ``metadata`` is the default field which is used when no fields are | 2116 ``metadata`` is the default field which is used when no fields are |
2107 specified. You can match more than one field at a time. | 2117 specified. You can match more than one field at a time. |
2108 """ | 2118 """ |
2109 # i18n: "matching" is a keyword | 2119 # i18n: "matching" is a keyword |
2110 l = getargs(x, 1, 2, _("matching takes 1 or 2 arguments")) | 2120 l = getargs(x, 1, 2, _(b"matching takes 1 or 2 arguments")) |
2111 | 2121 |
2112 revs = getset(repo, fullreposet(repo), l[0]) | 2122 revs = getset(repo, fullreposet(repo), l[0]) |
2113 | 2123 |
2114 fieldlist = ['metadata'] | 2124 fieldlist = [b'metadata'] |
2115 if len(l) > 1: | 2125 if len(l) > 1: |
2116 fieldlist = getstring( | 2126 fieldlist = getstring( |
2117 l[1], | 2127 l[1], |
2118 # i18n: "matching" is a keyword | 2128 # i18n: "matching" is a keyword |
2119 _("matching requires a string " "as its second argument"), | 2129 _(b"matching requires a string " b"as its second argument"), |
2120 ).split() | 2130 ).split() |
2121 | 2131 |
2122 # Make sure that there are no repeated fields, | 2132 # Make sure that there are no repeated fields, |
2123 # expand the 'special' 'metadata' field type | 2133 # expand the 'special' 'metadata' field type |
2124 # and check the 'files' whenever we check the 'diff' | 2134 # and check the 'files' whenever we check the 'diff' |
2125 fields = [] | 2135 fields = [] |
2126 for field in fieldlist: | 2136 for field in fieldlist: |
2127 if field == 'metadata': | 2137 if field == b'metadata': |
2128 fields += ['user', 'description', 'date'] | 2138 fields += [b'user', b'description', b'date'] |
2129 elif field == 'diff': | 2139 elif field == b'diff': |
2130 # a revision matching the diff must also match the files | 2140 # a revision matching the diff must also match the files |
2131 # since matching the diff is very costly, make sure to | 2141 # since matching the diff is very costly, make sure to |
2132 # also match the files first | 2142 # also match the files first |
2133 fields += ['files', 'diff'] | 2143 fields += [b'files', b'diff'] |
2134 else: | 2144 else: |
2135 if field == 'author': | 2145 if field == b'author': |
2136 field = 'user' | 2146 field = b'user' |
2137 fields.append(field) | 2147 fields.append(field) |
2138 fields = set(fields) | 2148 fields = set(fields) |
2139 if 'summary' in fields and 'description' in fields: | 2149 if b'summary' in fields and b'description' in fields: |
2140 # If a revision matches its description it also matches its summary | 2150 # If a revision matches its description it also matches its summary |
2141 fields.discard('summary') | 2151 fields.discard(b'summary') |
2142 | 2152 |
2143 # We may want to match more than one field | 2153 # We may want to match more than one field |
2144 # Not all fields take the same amount of time to be matched | 2154 # Not all fields take the same amount of time to be matched |
2145 # Sort the selected fields in order of increasing matching cost | 2155 # Sort the selected fields in order of increasing matching cost |
2146 fieldorder = [ | 2156 fieldorder = [ |
2147 'phase', | 2157 b'phase', |
2148 'parents', | 2158 b'parents', |
2149 'user', | 2159 b'user', |
2150 'date', | 2160 b'date', |
2151 'branch', | 2161 b'branch', |
2152 'summary', | 2162 b'summary', |
2153 'files', | 2163 b'files', |
2154 'description', | 2164 b'description', |
2155 'substate', | 2165 b'substate', |
2156 'diff', | 2166 b'diff', |
2157 ] | 2167 ] |
2158 | 2168 |
2159 def fieldkeyfunc(f): | 2169 def fieldkeyfunc(f): |
2160 try: | 2170 try: |
2161 return fieldorder.index(f) | 2171 return fieldorder.index(f) |
2168 | 2178 |
2169 # Each field will be matched with its own "getfield" function | 2179 # Each field will be matched with its own "getfield" function |
2170 # which will be added to the getfieldfuncs array of functions | 2180 # which will be added to the getfieldfuncs array of functions |
2171 getfieldfuncs = [] | 2181 getfieldfuncs = [] |
2172 _funcs = { | 2182 _funcs = { |
2173 'user': lambda r: repo[r].user(), | 2183 b'user': lambda r: repo[r].user(), |
2174 'branch': lambda r: repo[r].branch(), | 2184 b'branch': lambda r: repo[r].branch(), |
2175 'date': lambda r: repo[r].date(), | 2185 b'date': lambda r: repo[r].date(), |
2176 'description': lambda r: repo[r].description(), | 2186 b'description': lambda r: repo[r].description(), |
2177 'files': lambda r: repo[r].files(), | 2187 b'files': lambda r: repo[r].files(), |
2178 'parents': lambda r: repo[r].parents(), | 2188 b'parents': lambda r: repo[r].parents(), |
2179 'phase': lambda r: repo[r].phase(), | 2189 b'phase': lambda r: repo[r].phase(), |
2180 'substate': lambda r: repo[r].substate, | 2190 b'substate': lambda r: repo[r].substate, |
2181 'summary': lambda r: repo[r].description().splitlines()[0], | 2191 b'summary': lambda r: repo[r].description().splitlines()[0], |
2182 'diff': lambda r: list( | 2192 b'diff': lambda r: list( |
2183 repo[r].diff(opts=diffutil.diffallopts(repo.ui, {'git': True})) | 2193 repo[r].diff(opts=diffutil.diffallopts(repo.ui, {b'git': True})) |
2184 ), | 2194 ), |
2185 } | 2195 } |
2186 for info in fields: | 2196 for info in fields: |
2187 getfield = _funcs.get(info, None) | 2197 getfield = _funcs.get(info, None) |
2188 if getfield is None: | 2198 if getfield is None: |
2189 raise error.ParseError( | 2199 raise error.ParseError( |
2190 # i18n: "matching" is a keyword | 2200 # i18n: "matching" is a keyword |
2191 _("unexpected field name passed to matching: %s") | 2201 _(b"unexpected field name passed to matching: %s") |
2192 % info | 2202 % info |
2193 ) | 2203 ) |
2194 getfieldfuncs.append(getfield) | 2204 getfieldfuncs.append(getfield) |
2195 # convert the getfield array of functions into a "getinfo" function | 2205 # convert the getfield array of functions into a "getinfo" function |
2196 # which returns an array of field values (or a single value if there | 2206 # which returns an array of field values (or a single value if there |
2206 match = False | 2216 match = False |
2207 if match: | 2217 if match: |
2208 return True | 2218 return True |
2209 return False | 2219 return False |
2210 | 2220 |
2211 return subset.filter(matches, condrepr=('<matching%r %r>', fields, revs)) | 2221 return subset.filter(matches, condrepr=(b'<matching%r %r>', fields, revs)) |
2212 | 2222 |
2213 | 2223 |
2214 @predicate('reverse(set)', safe=True, takeorder=True, weight=0) | 2224 @predicate(b'reverse(set)', safe=True, takeorder=True, weight=0) |
2215 def reverse(repo, subset, x, order): | 2225 def reverse(repo, subset, x, order): |
2216 """Reverse order of set. | 2226 """Reverse order of set. |
2217 """ | 2227 """ |
2218 l = getset(repo, subset, x, order) | 2228 l = getset(repo, subset, x, order) |
2219 if order == defineorder: | 2229 if order == defineorder: |
2220 l.reverse() | 2230 l.reverse() |
2221 return l | 2231 return l |
2222 | 2232 |
2223 | 2233 |
2224 @predicate('roots(set)', safe=True) | 2234 @predicate(b'roots(set)', safe=True) |
2225 def roots(repo, subset, x): | 2235 def roots(repo, subset, x): |
2226 """Changesets in set with no parent changeset in set. | 2236 """Changesets in set with no parent changeset in set. |
2227 """ | 2237 """ |
2228 s = getset(repo, fullreposet(repo), x) | 2238 s = getset(repo, fullreposet(repo), x) |
2229 parents = repo.changelog.parentrevs | 2239 parents = repo.changelog.parentrevs |
2232 for p in parents(r): | 2242 for p in parents(r): |
2233 if 0 <= p and p in s: | 2243 if 0 <= p and p in s: |
2234 return False | 2244 return False |
2235 return True | 2245 return True |
2236 | 2246 |
2237 return subset & s.filter(filter, condrepr='<roots>') | 2247 return subset & s.filter(filter, condrepr=b'<roots>') |
2238 | 2248 |
2239 | 2249 |
2240 _sortkeyfuncs = { | 2250 _sortkeyfuncs = { |
2241 'rev': lambda c: c.rev(), | 2251 b'rev': lambda c: c.rev(), |
2242 'branch': lambda c: c.branch(), | 2252 b'branch': lambda c: c.branch(), |
2243 'desc': lambda c: c.description(), | 2253 b'desc': lambda c: c.description(), |
2244 'user': lambda c: c.user(), | 2254 b'user': lambda c: c.user(), |
2245 'author': lambda c: c.user(), | 2255 b'author': lambda c: c.user(), |
2246 'date': lambda c: c.date()[0], | 2256 b'date': lambda c: c.date()[0], |
2247 } | 2257 } |
2248 | 2258 |
2249 | 2259 |
2250 def _getsortargs(x): | 2260 def _getsortargs(x): |
2251 """Parse sort options into (set, [(key, reverse)], opts)""" | 2261 """Parse sort options into (set, [(key, reverse)], opts)""" |
2252 args = getargsdict(x, 'sort', 'set keys topo.firstbranch') | 2262 args = getargsdict(x, b'sort', b'set keys topo.firstbranch') |
2253 if 'set' not in args: | 2263 if b'set' not in args: |
2254 # i18n: "sort" is a keyword | 2264 # i18n: "sort" is a keyword |
2255 raise error.ParseError(_('sort requires one or two arguments')) | 2265 raise error.ParseError(_(b'sort requires one or two arguments')) |
2256 keys = "rev" | 2266 keys = b"rev" |
2257 if 'keys' in args: | 2267 if b'keys' in args: |
2258 # i18n: "sort" is a keyword | 2268 # i18n: "sort" is a keyword |
2259 keys = getstring(args['keys'], _("sort spec must be a string")) | 2269 keys = getstring(args[b'keys'], _(b"sort spec must be a string")) |
2260 | 2270 |
2261 keyflags = [] | 2271 keyflags = [] |
2262 for k in keys.split(): | 2272 for k in keys.split(): |
2263 fk = k | 2273 fk = k |
2264 reverse = k.startswith('-') | 2274 reverse = k.startswith(b'-') |
2265 if reverse: | 2275 if reverse: |
2266 k = k[1:] | 2276 k = k[1:] |
2267 if k not in _sortkeyfuncs and k != 'topo': | 2277 if k not in _sortkeyfuncs and k != b'topo': |
2268 raise error.ParseError( | 2278 raise error.ParseError( |
2269 _("unknown sort key %r") % pycompat.bytestr(fk) | 2279 _(b"unknown sort key %r") % pycompat.bytestr(fk) |
2270 ) | 2280 ) |
2271 keyflags.append((k, reverse)) | 2281 keyflags.append((k, reverse)) |
2272 | 2282 |
2273 if len(keyflags) > 1 and any(k == 'topo' for k, reverse in keyflags): | 2283 if len(keyflags) > 1 and any(k == b'topo' for k, reverse in keyflags): |
2274 # i18n: "topo" is a keyword | 2284 # i18n: "topo" is a keyword |
2275 raise error.ParseError( | 2285 raise error.ParseError( |
2276 _('topo sort order cannot be combined ' 'with other sort keys') | 2286 _(b'topo sort order cannot be combined ' b'with other sort keys') |
2277 ) | 2287 ) |
2278 | 2288 |
2279 opts = {} | 2289 opts = {} |
2280 if 'topo.firstbranch' in args: | 2290 if b'topo.firstbranch' in args: |
2281 if any(k == 'topo' for k, reverse in keyflags): | 2291 if any(k == b'topo' for k, reverse in keyflags): |
2282 opts['topo.firstbranch'] = args['topo.firstbranch'] | 2292 opts[b'topo.firstbranch'] = args[b'topo.firstbranch'] |
2283 else: | 2293 else: |
2284 # i18n: "topo" and "topo.firstbranch" are keywords | 2294 # i18n: "topo" and "topo.firstbranch" are keywords |
2285 raise error.ParseError( | 2295 raise error.ParseError( |
2286 _( | 2296 _( |
2287 'topo.firstbranch can only be used ' | 2297 b'topo.firstbranch can only be used ' |
2288 'when using the topo sort key' | 2298 b'when using the topo sort key' |
2289 ) | 2299 ) |
2290 ) | 2300 ) |
2291 | 2301 |
2292 return args['set'], keyflags, opts | 2302 return args[b'set'], keyflags, opts |
2293 | 2303 |
2294 | 2304 |
2295 @predicate( | 2305 @predicate( |
2296 'sort(set[, [-]key... [, ...]])', safe=True, takeorder=True, weight=10 | 2306 b'sort(set[, [-]key... [, ...]])', safe=True, takeorder=True, weight=10 |
2297 ) | 2307 ) |
2298 def sort(repo, subset, x, order): | 2308 def sort(repo, subset, x, order): |
2299 """Sort set by keys. The default sort order is ascending, specify a key | 2309 """Sort set by keys. The default sort order is ascending, specify a key |
2300 as ``-key`` to sort in descending order. | 2310 as ``-key`` to sort in descending order. |
2301 | 2311 |
2316 s, keyflags, opts = _getsortargs(x) | 2326 s, keyflags, opts = _getsortargs(x) |
2317 revs = getset(repo, subset, s, order) | 2327 revs = getset(repo, subset, s, order) |
2318 | 2328 |
2319 if not keyflags or order != defineorder: | 2329 if not keyflags or order != defineorder: |
2320 return revs | 2330 return revs |
2321 if len(keyflags) == 1 and keyflags[0][0] == "rev": | 2331 if len(keyflags) == 1 and keyflags[0][0] == b"rev": |
2322 revs.sort(reverse=keyflags[0][1]) | 2332 revs.sort(reverse=keyflags[0][1]) |
2323 return revs | 2333 return revs |
2324 elif keyflags[0][0] == "topo": | 2334 elif keyflags[0][0] == b"topo": |
2325 firstbranch = () | 2335 firstbranch = () |
2326 if 'topo.firstbranch' in opts: | 2336 if b'topo.firstbranch' in opts: |
2327 firstbranch = getset(repo, subset, opts['topo.firstbranch']) | 2337 firstbranch = getset(repo, subset, opts[b'topo.firstbranch']) |
2328 revs = baseset( | 2338 revs = baseset( |
2329 dagop.toposort(revs, repo.changelog.parentrevs, firstbranch), | 2339 dagop.toposort(revs, repo.changelog.parentrevs, firstbranch), |
2330 istopo=True, | 2340 istopo=True, |
2331 ) | 2341 ) |
2332 if keyflags[0][1]: | 2342 if keyflags[0][1]: |
2338 for k, reverse in reversed(keyflags): | 2348 for k, reverse in reversed(keyflags): |
2339 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse) | 2349 ctxs.sort(key=_sortkeyfuncs[k], reverse=reverse) |
2340 return baseset([c.rev() for c in ctxs]) | 2350 return baseset([c.rev() for c in ctxs]) |
2341 | 2351 |
2342 | 2352 |
2343 @predicate('subrepo([pattern])') | 2353 @predicate(b'subrepo([pattern])') |
2344 def subrepo(repo, subset, x): | 2354 def subrepo(repo, subset, x): |
2345 """Changesets that add, modify or remove the given subrepo. If no subrepo | 2355 """Changesets that add, modify or remove the given subrepo. If no subrepo |
2346 pattern is named, any subrepo changes are returned. | 2356 pattern is named, any subrepo changes are returned. |
2347 """ | 2357 """ |
2348 # i18n: "subrepo" is a keyword | 2358 # i18n: "subrepo" is a keyword |
2349 args = getargs(x, 0, 1, _('subrepo takes at most one argument')) | 2359 args = getargs(x, 0, 1, _(b'subrepo takes at most one argument')) |
2350 pat = None | 2360 pat = None |
2351 if len(args) != 0: | 2361 if len(args) != 0: |
2352 pat = getstring(args[0], _("subrepo requires a pattern")) | 2362 pat = getstring(args[0], _(b"subrepo requires a pattern")) |
2353 | 2363 |
2354 m = matchmod.exact(['.hgsubstate']) | 2364 m = matchmod.exact([b'.hgsubstate']) |
2355 | 2365 |
2356 def submatches(names): | 2366 def submatches(names): |
2357 k, p, m = stringutil.stringmatcher(pat) | 2367 k, p, m = stringutil.stringmatcher(pat) |
2358 for name in names: | 2368 for name in names: |
2359 if m(name): | 2369 if m(name): |
2380 if s.removed: | 2390 if s.removed: |
2381 return any(submatches(c.p1().substate.keys())) | 2391 return any(submatches(c.p1().substate.keys())) |
2382 | 2392 |
2383 return False | 2393 return False |
2384 | 2394 |
2385 return subset.filter(matches, condrepr=('<subrepo %r>', pat)) | 2395 return subset.filter(matches, condrepr=(b'<subrepo %r>', pat)) |
2386 | 2396 |
2387 | 2397 |
2388 def _mapbynodefunc(repo, s, f): | 2398 def _mapbynodefunc(repo, s, f): |
2389 """(repo, smartset, [node] -> [node]) -> smartset | 2399 """(repo, smartset, [node] -> [node]) -> smartset |
2390 | 2400 |
2398 nodemap = cl.nodemap | 2408 nodemap = cl.nodemap |
2399 result = set(torev(n) for n in f(tonode(r) for r in s) if n in nodemap) | 2409 result = set(torev(n) for n in f(tonode(r) for r in s) if n in nodemap) |
2400 return smartset.baseset(result - repo.changelog.filteredrevs) | 2410 return smartset.baseset(result - repo.changelog.filteredrevs) |
2401 | 2411 |
2402 | 2412 |
2403 @predicate('successors(set)', safe=True) | 2413 @predicate(b'successors(set)', safe=True) |
2404 def successors(repo, subset, x): | 2414 def successors(repo, subset, x): |
2405 """All successors for set, including the given set themselves""" | 2415 """All successors for set, including the given set themselves""" |
2406 s = getset(repo, fullreposet(repo), x) | 2416 s = getset(repo, fullreposet(repo), x) |
2407 f = lambda nodes: obsutil.allsuccessors(repo.obsstore, nodes) | 2417 f = lambda nodes: obsutil.allsuccessors(repo.obsstore, nodes) |
2408 d = _mapbynodefunc(repo, s, f) | 2418 d = _mapbynodefunc(repo, s, f) |
2411 | 2421 |
2412 def _substringmatcher(pattern, casesensitive=True): | 2422 def _substringmatcher(pattern, casesensitive=True): |
2413 kind, pattern, matcher = stringutil.stringmatcher( | 2423 kind, pattern, matcher = stringutil.stringmatcher( |
2414 pattern, casesensitive=casesensitive | 2424 pattern, casesensitive=casesensitive |
2415 ) | 2425 ) |
2416 if kind == 'literal': | 2426 if kind == b'literal': |
2417 if not casesensitive: | 2427 if not casesensitive: |
2418 pattern = encoding.lower(pattern) | 2428 pattern = encoding.lower(pattern) |
2419 matcher = lambda s: pattern in encoding.lower(s) | 2429 matcher = lambda s: pattern in encoding.lower(s) |
2420 else: | 2430 else: |
2421 matcher = lambda s: pattern in s | 2431 matcher = lambda s: pattern in s |
2422 return kind, pattern, matcher | 2432 return kind, pattern, matcher |
2423 | 2433 |
2424 | 2434 |
2425 @predicate('tag([name])', safe=True) | 2435 @predicate(b'tag([name])', safe=True) |
2426 def tag(repo, subset, x): | 2436 def tag(repo, subset, x): |
2427 """The specified tag by name, or all tagged revisions if no name is given. | 2437 """The specified tag by name, or all tagged revisions if no name is given. |
2428 | 2438 |
2429 Pattern matching is supported for `name`. See | 2439 Pattern matching is supported for `name`. See |
2430 :hg:`help revisions.patterns`. | 2440 :hg:`help revisions.patterns`. |
2431 """ | 2441 """ |
2432 # i18n: "tag" is a keyword | 2442 # i18n: "tag" is a keyword |
2433 args = getargs(x, 0, 1, _("tag takes one or no arguments")) | 2443 args = getargs(x, 0, 1, _(b"tag takes one or no arguments")) |
2434 cl = repo.changelog | 2444 cl = repo.changelog |
2435 if args: | 2445 if args: |
2436 pattern = getstring( | 2446 pattern = getstring( |
2437 args[0], | 2447 args[0], |
2438 # i18n: "tag" is a keyword | 2448 # i18n: "tag" is a keyword |
2439 _('the argument to tag must be a string'), | 2449 _(b'the argument to tag must be a string'), |
2440 ) | 2450 ) |
2441 kind, pattern, matcher = stringutil.stringmatcher(pattern) | 2451 kind, pattern, matcher = stringutil.stringmatcher(pattern) |
2442 if kind == 'literal': | 2452 if kind == b'literal': |
2443 # avoid resolving all tags | 2453 # avoid resolving all tags |
2444 tn = repo._tagscache.tags.get(pattern, None) | 2454 tn = repo._tagscache.tags.get(pattern, None) |
2445 if tn is None: | 2455 if tn is None: |
2446 raise error.RepoLookupError( | 2456 raise error.RepoLookupError( |
2447 _("tag '%s' does not exist") % pattern | 2457 _(b"tag '%s' does not exist") % pattern |
2448 ) | 2458 ) |
2449 s = {repo[tn].rev()} | 2459 s = {repo[tn].rev()} |
2450 else: | 2460 else: |
2451 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)} | 2461 s = {cl.rev(n) for t, n in repo.tagslist() if matcher(t)} |
2452 else: | 2462 else: |
2453 s = {cl.rev(n) for t, n in repo.tagslist() if t != 'tip'} | 2463 s = {cl.rev(n) for t, n in repo.tagslist() if t != b'tip'} |
2454 return subset & s | 2464 return subset & s |
2455 | 2465 |
2456 | 2466 |
2457 @predicate('tagged', safe=True) | 2467 @predicate(b'tagged', safe=True) |
2458 def tagged(repo, subset, x): | 2468 def tagged(repo, subset, x): |
2459 return tag(repo, subset, x) | 2469 return tag(repo, subset, x) |
2460 | 2470 |
2461 | 2471 |
2462 @predicate('orphan()', safe=True) | 2472 @predicate(b'orphan()', safe=True) |
2463 def orphan(repo, subset, x): | 2473 def orphan(repo, subset, x): |
2464 """Non-obsolete changesets with obsolete ancestors. (EXPERIMENTAL) | 2474 """Non-obsolete changesets with obsolete ancestors. (EXPERIMENTAL) |
2465 """ | 2475 """ |
2466 # i18n: "orphan" is a keyword | 2476 # i18n: "orphan" is a keyword |
2467 getargs(x, 0, 0, _("orphan takes no arguments")) | 2477 getargs(x, 0, 0, _(b"orphan takes no arguments")) |
2468 orphan = obsmod.getrevs(repo, 'orphan') | 2478 orphan = obsmod.getrevs(repo, b'orphan') |
2469 return subset & orphan | 2479 return subset & orphan |
2470 | 2480 |
2471 | 2481 |
2472 @predicate('user(string)', safe=True, weight=10) | 2482 @predicate(b'user(string)', safe=True, weight=10) |
2473 def user(repo, subset, x): | 2483 def user(repo, subset, x): |
2474 """User name contains string. The match is case-insensitive. | 2484 """User name contains string. The match is case-insensitive. |
2475 | 2485 |
2476 Pattern matching is supported for `string`. See | 2486 Pattern matching is supported for `string`. See |
2477 :hg:`help revisions.patterns`. | 2487 :hg:`help revisions.patterns`. |
2478 """ | 2488 """ |
2479 return author(repo, subset, x) | 2489 return author(repo, subset, x) |
2480 | 2490 |
2481 | 2491 |
2482 @predicate('wdir()', safe=True, weight=0) | 2492 @predicate(b'wdir()', safe=True, weight=0) |
2483 def wdir(repo, subset, x): | 2493 def wdir(repo, subset, x): |
2484 """Working directory. (EXPERIMENTAL)""" | 2494 """Working directory. (EXPERIMENTAL)""" |
2485 # i18n: "wdir" is a keyword | 2495 # i18n: "wdir" is a keyword |
2486 getargs(x, 0, 0, _("wdir takes no arguments")) | 2496 getargs(x, 0, 0, _(b"wdir takes no arguments")) |
2487 if node.wdirrev in subset or isinstance(subset, fullreposet): | 2497 if node.wdirrev in subset or isinstance(subset, fullreposet): |
2488 return baseset([node.wdirrev]) | 2498 return baseset([node.wdirrev]) |
2489 return baseset() | 2499 return baseset() |
2490 | 2500 |
2491 | 2501 |
2492 def _orderedlist(repo, subset, x): | 2502 def _orderedlist(repo, subset, x): |
2493 s = getstring(x, "internal error") | 2503 s = getstring(x, b"internal error") |
2494 if not s: | 2504 if not s: |
2495 return baseset() | 2505 return baseset() |
2496 # remove duplicates here. it's difficult for caller to deduplicate sets | 2506 # remove duplicates here. it's difficult for caller to deduplicate sets |
2497 # because different symbols can point to the same rev. | 2507 # because different symbols can point to the same rev. |
2498 cl = repo.changelog | 2508 cl = repo.changelog |
2499 ls = [] | 2509 ls = [] |
2500 seen = set() | 2510 seen = set() |
2501 for t in s.split('\0'): | 2511 for t in s.split(b'\0'): |
2502 try: | 2512 try: |
2503 # fast path for integer revision | 2513 # fast path for integer revision |
2504 r = int(t) | 2514 r = int(t) |
2505 if ('%d' % r) != t or r not in cl: | 2515 if (b'%d' % r) != t or r not in cl: |
2506 raise ValueError | 2516 raise ValueError |
2507 revs = [r] | 2517 revs = [r] |
2508 except ValueError: | 2518 except ValueError: |
2509 revs = stringset(repo, subset, t, defineorder) | 2519 revs = stringset(repo, subset, t, defineorder) |
2510 | 2520 |
2520 seen.add(r) | 2530 seen.add(r) |
2521 return baseset(ls) | 2531 return baseset(ls) |
2522 | 2532 |
2523 | 2533 |
2524 # for internal use | 2534 # for internal use |
2525 @predicate('_list', safe=True, takeorder=True) | 2535 @predicate(b'_list', safe=True, takeorder=True) |
2526 def _list(repo, subset, x, order): | 2536 def _list(repo, subset, x, order): |
2527 if order == followorder: | 2537 if order == followorder: |
2528 # slow path to take the subset order | 2538 # slow path to take the subset order |
2529 return subset & _orderedlist(repo, fullreposet(repo), x) | 2539 return subset & _orderedlist(repo, fullreposet(repo), x) |
2530 else: | 2540 else: |
2531 return _orderedlist(repo, subset, x) | 2541 return _orderedlist(repo, subset, x) |
2532 | 2542 |
2533 | 2543 |
2534 def _orderedintlist(repo, subset, x): | 2544 def _orderedintlist(repo, subset, x): |
2535 s = getstring(x, "internal error") | 2545 s = getstring(x, b"internal error") |
2536 if not s: | 2546 if not s: |
2537 return baseset() | 2547 return baseset() |
2538 ls = [int(r) for r in s.split('\0')] | 2548 ls = [int(r) for r in s.split(b'\0')] |
2539 s = subset | 2549 s = subset |
2540 return baseset([r for r in ls if r in s]) | 2550 return baseset([r for r in ls if r in s]) |
2541 | 2551 |
2542 | 2552 |
2543 # for internal use | 2553 # for internal use |
2544 @predicate('_intlist', safe=True, takeorder=True, weight=0) | 2554 @predicate(b'_intlist', safe=True, takeorder=True, weight=0) |
2545 def _intlist(repo, subset, x, order): | 2555 def _intlist(repo, subset, x, order): |
2546 if order == followorder: | 2556 if order == followorder: |
2547 # slow path to take the subset order | 2557 # slow path to take the subset order |
2548 return subset & _orderedintlist(repo, fullreposet(repo), x) | 2558 return subset & _orderedintlist(repo, fullreposet(repo), x) |
2549 else: | 2559 else: |
2550 return _orderedintlist(repo, subset, x) | 2560 return _orderedintlist(repo, subset, x) |
2551 | 2561 |
2552 | 2562 |
2553 def _orderedhexlist(repo, subset, x): | 2563 def _orderedhexlist(repo, subset, x): |
2554 s = getstring(x, "internal error") | 2564 s = getstring(x, b"internal error") |
2555 if not s: | 2565 if not s: |
2556 return baseset() | 2566 return baseset() |
2557 cl = repo.changelog | 2567 cl = repo.changelog |
2558 ls = [cl.rev(node.bin(r)) for r in s.split('\0')] | 2568 ls = [cl.rev(node.bin(r)) for r in s.split(b'\0')] |
2559 s = subset | 2569 s = subset |
2560 return baseset([r for r in ls if r in s]) | 2570 return baseset([r for r in ls if r in s]) |
2561 | 2571 |
2562 | 2572 |
2563 # for internal use | 2573 # for internal use |
2564 @predicate('_hexlist', safe=True, takeorder=True) | 2574 @predicate(b'_hexlist', safe=True, takeorder=True) |
2565 def _hexlist(repo, subset, x, order): | 2575 def _hexlist(repo, subset, x, order): |
2566 if order == followorder: | 2576 if order == followorder: |
2567 # slow path to take the subset order | 2577 # slow path to take the subset order |
2568 return subset & _orderedhexlist(repo, fullreposet(repo), x) | 2578 return subset & _orderedhexlist(repo, fullreposet(repo), x) |
2569 else: | 2579 else: |
2570 return _orderedhexlist(repo, subset, x) | 2580 return _orderedhexlist(repo, subset, x) |
2571 | 2581 |
2572 | 2582 |
2573 methods = { | 2583 methods = { |
2574 "range": rangeset, | 2584 b"range": rangeset, |
2575 "rangeall": rangeall, | 2585 b"rangeall": rangeall, |
2576 "rangepre": rangepre, | 2586 b"rangepre": rangepre, |
2577 "rangepost": rangepost, | 2587 b"rangepost": rangepost, |
2578 "dagrange": dagrange, | 2588 b"dagrange": dagrange, |
2579 "string": stringset, | 2589 b"string": stringset, |
2580 "symbol": stringset, | 2590 b"symbol": stringset, |
2581 "and": andset, | 2591 b"and": andset, |
2582 "andsmally": andsmallyset, | 2592 b"andsmally": andsmallyset, |
2583 "or": orset, | 2593 b"or": orset, |
2584 "not": notset, | 2594 b"not": notset, |
2585 "difference": differenceset, | 2595 b"difference": differenceset, |
2586 "relation": relationset, | 2596 b"relation": relationset, |
2587 "relsubscript": relsubscriptset, | 2597 b"relsubscript": relsubscriptset, |
2588 "subscript": subscriptset, | 2598 b"subscript": subscriptset, |
2589 "list": listset, | 2599 b"list": listset, |
2590 "keyvalue": keyvaluepair, | 2600 b"keyvalue": keyvaluepair, |
2591 "func": func, | 2601 b"func": func, |
2592 "ancestor": ancestorspec, | 2602 b"ancestor": ancestorspec, |
2593 "parent": parentspec, | 2603 b"parent": parentspec, |
2594 "parentpost": parentpost, | 2604 b"parentpost": parentpost, |
2595 "smartset": rawsmartset, | 2605 b"smartset": rawsmartset, |
2596 } | 2606 } |
2597 | 2607 |
2598 subscriptrelations = { | 2608 subscriptrelations = { |
2599 "g": generationsrel, | 2609 b"g": generationsrel, |
2600 "generations": generationsrel, | 2610 b"generations": generationsrel, |
2601 } | 2611 } |
2602 | 2612 |
2603 | 2613 |
2604 def lookupfn(repo): | 2614 def lookupfn(repo): |
2605 return lambda symbol: scmutil.isrevsymbol(repo, symbol) | 2615 return lambda symbol: scmutil.isrevsymbol(repo, symbol) |
2625 def mfunc(repo, subset=None): | 2635 def mfunc(repo, subset=None): |
2626 return baseset() | 2636 return baseset() |
2627 | 2637 |
2628 return mfunc | 2638 return mfunc |
2629 if not all(specs): | 2639 if not all(specs): |
2630 raise error.ParseError(_("empty query")) | 2640 raise error.ParseError(_(b"empty query")) |
2631 if len(specs) == 1: | 2641 if len(specs) == 1: |
2632 tree = revsetlang.parse(specs[0], lookup) | 2642 tree = revsetlang.parse(specs[0], lookup) |
2633 else: | 2643 else: |
2634 tree = ( | 2644 tree = ( |
2635 'or', | 2645 b'or', |
2636 ('list',) + tuple(revsetlang.parse(s, lookup) for s in specs), | 2646 (b'list',) + tuple(revsetlang.parse(s, lookup) for s in specs), |
2637 ) | 2647 ) |
2638 | 2648 |
2639 aliases = [] | 2649 aliases = [] |
2640 warn = None | 2650 warn = None |
2641 if ui: | 2651 if ui: |
2642 aliases.extend(ui.configitems('revsetalias')) | 2652 aliases.extend(ui.configitems(b'revsetalias')) |
2643 warn = ui.warn | 2653 warn = ui.warn |
2644 if localalias: | 2654 if localalias: |
2645 aliases.extend(localalias.items()) | 2655 aliases.extend(localalias.items()) |
2646 if aliases: | 2656 if aliases: |
2647 tree = revsetlang.expandaliases(tree, aliases, warn=warn) | 2657 tree = revsetlang.expandaliases(tree, aliases, warn=warn) |