diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py --- a/mercurial/debugcommands.py +++ b/mercurial/debugcommands.py @@ -1947,6 +1947,7 @@ _('print parsed tree at the given stage'), _('NAME')), ('', 'no-optimized', False, _('evaluate tree without optimization')), ('', 'verify-optimized', False, _('verify optimized result')), + ('', 'check-ordering', False, _('try to detect ordering issues')), ], ('REVSPEC')) def debugrevspec(ui, repo, expr, **opts): @@ -2007,6 +2008,25 @@ ui.write(revsetlang.prettyformat(tree), "\n") printedtree = tree + if opts['check_ordering']: + problematic = [] + for name in ('defineorder', 'followorder'): + m = revset.makematcher(tree, order=getattr(revset, name)) + s = smartset.fullreposet(repo) + revs1 = list(m(repo, s)) + s.reverse() + revs2 = list(m(repo, s)) + if len(revs1) <= 1: + ui.write(('ordering: cannot detect issues if len(revs) <= 1\n')) + break + if ((revs1 == revs2 and name == 'followorder') or + (revs1 != revs2 and name == 'defineorder')): + problematic.append(name) + if problematic: + ui.write(('ordering: %s not respected\n') + % (' and '.join(problematic))) + return 1 + if opts['verify_optimized']: arevs = revset.makematcher(treebystage['analyzed'])(repo) brevs = revset.makematcher(treebystage['optimized'])(repo) diff --git a/tests/test-completion.t b/tests/test-completion.t --- a/tests/test-completion.t +++ b/tests/test-completion.t @@ -282,7 +282,7 @@ debugrebuildfncache: debugrename: rev debugrevlog: changelog, manifest, dir, dump - debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized + debugrevspec: optimize, show-revs, show-set, show-stage, no-optimized, verify-optimized, check-ordering debugsetparents: debugssl: debugsub: rev diff --git a/tests/test-revset-ordering.t b/tests/test-revset-ordering.t new file mode 100644 --- /dev/null +++ b/tests/test-revset-ordering.t @@ -0,0 +1,103 @@ +Check if revset predicates respect order as told + + $ check() { + > hg debugrevspec --no-show-revs --check-ordering "$@"; : + > } + $ cat >> $HGRCPATH < [extensions] + > drawdag=$TESTDIR/drawdag.py + > EOF + + $ hg init repo1 + $ hg clone repo1 repo2 -q + $ cd repo2 + $ hg debugdrawdag <<'EOS' + > C E # B/A = A1 + > |/| # C/A = A2 + > B D # D/A = A3 + > |/| # E/A = A4 + > A Z X Y + > EOS + + $ for i in A B D; do + > hg bookmark -ir $i book-$i + > done + $ hg phase -r B --public -q + $ hg phase -r E+C --secret -f -q + $ hg update A -q + $ hg graft X -q + $ hg update B -q + $ hg graft Y -q + $ hg rm * + $ hg commit -m REMOVEALL1 + $ hg update C -q + $ hg rm * + $ hg commit -m REMOVEALL2 + $ hg commit -m CLOSE1 --close-branch + $ hg update E -q + $ hg commit -m CLOSE2 --close-branch + $ hg bisect --good A -q + $ hg bisect --bad E -q >/dev/null + + $ check '3+1+2' + $ check '(3+1+2)-1' + $ check '(3+1+2) & (1+3+4)' + $ check 'A::E' + $ check 'E:A' + $ check 'E % C' + $ check 'not E' + ordering: defineorder not respected + + $ check 'adds("*")' + ordering: defineorder not respected + $ check 'all()' + $ check 'ancestors(E)' + $ check 'author(test)' + ordering: defineorder not respected + $ check 'bisect(untested)' + $ check 'bookmark()' + $ check 'branch(default)' + ordering: defineorder not respected + $ check 'branchpoint()' + ordering: defineorder not respected + $ check 'children(A)' + $ check 'closed()' + ordering: defineorder not respected + $ check 'contains(A)' + ordering: defineorder not respected + $ check 'date("0 0")' + ordering: defineorder not respected + $ check 'desc("")' + ordering: defineorder not respected + $ check 'descendants(A)' + $ check 'destination()' + ordering: defineorder not respected + $ check 'draft()' + $ check 'file("*")' + ordering: defineorder not respected + $ check 'filelog("A")' + $ check 'follow()' + $ check 'grep("A")' + ordering: defineorder not respected + $ check 'head()' + $ check 'heads(E+C)' + ordering: followorder not respected + $ check 'merge()' + ordering: defineorder not respected + $ check 'modifies("A")' + ordering: defineorder not respected + $ check 'named("tags")' + $ check 'origin()' + $ check 'outgoing()' + $ check 'p1(B+E+D)' + $ check 'p2(B+E+D)' + $ check 'parents(E)' + $ check 'public()' + ordering: defineorder not respected + $ check 'reverse(B+E+D)' + $ check 'removes("A")' + ordering: defineorder not respected + $ check 'roots(B+E+D)' + $ check 'secret()' + $ check 'sort(all())' + $ check 'tagged()'