hgext/hbisect.py
author Matt Mackall <mpm@selenic.com>
Mon, 31 Dec 2007 18:20:34 -0600
changeset 5772 4c46636eafe5
parent 5771 9d3f49f52a4a
child 5773 2f6105ab4c54
permissions -rw-r--r--
bisect: skip calculations on candidates with too many ancestors Once an ancestor list has grown past the perfect threshold, all descendants are less optimal. Use a poison dict to avoid pointless operations on their long ancestor lists, thus eliminating most of the work.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
1855
0ba9dee8cfbd Fixed spacing/indentation, removed #! script header, added short description.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 1854
diff changeset
     1
# bisect extension for mercurial
1367
a7678cbd7c28 bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff changeset
     2
#
1861
65949d1c9bf7 Added copyright information to hbisect.py
Thomas Arendsen Hein <thomas@intevation.de>
parents: 1856
diff changeset
     3
# Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
65949d1c9bf7 Added copyright information to hbisect.py
Thomas Arendsen Hein <thomas@intevation.de>
parents: 1856
diff changeset
     4
# Inspired by git bisect, extension skeleton taken from mq.py.
65949d1c9bf7 Added copyright information to hbisect.py
Thomas Arendsen Hein <thomas@intevation.de>
parents: 1856
diff changeset
     5
#
1367
a7678cbd7c28 bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff changeset
     6
# This software may be used and distributed according to the terms
a7678cbd7c28 bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff changeset
     7
# of the GNU General Public License, incorporated herein by reference.
a7678cbd7c28 bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff changeset
     8
3891
6b4127c7d52a Simplify i18n imports
Matt Mackall <mpm@selenic.com>
parents: 3877
diff changeset
     9
from mercurial.i18n import _
5731
19691160d7f5 bisect: remove unused imports
Matt Mackall <mpm@selenic.com>
parents: 5730
diff changeset
    10
from mercurial import hg, util, cmdutil
5767
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    11
import os
1367
a7678cbd7c28 bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff changeset
    12
5737
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    13
def _bisect(changelog, state):
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    14
    clparents = changelog.parentrevs
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    15
    # only the earliest bad revision matters
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    16
    badrev = min([changelog.rev(n) for n in state['bad']])
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    17
    bad = changelog.node(badrev)
5770
f5b858fc8067 bisect: find best node in ancestor collection pass
Matt Mackall <mpm@selenic.com>
parents: 5769
diff changeset
    18
    skip = dict.fromkeys([changelog.rev(n) for n in state['skip']])
1367
a7678cbd7c28 bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff changeset
    19
5737
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    20
    # build ancestors array
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    21
    ancestors = [[]] * (changelog.count() + 1) # an extra for [-1]
1367
a7678cbd7c28 bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff changeset
    22
5737
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    23
    # clear good revs from array
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    24
    for node in state['good']:
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    25
        ancestors[changelog.rev(node)] = None
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    26
    for rev in xrange(changelog.count(), -1, -1):
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    27
        if ancestors[rev] is None:
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    28
            for prev in clparents(rev):
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    29
                ancestors[prev] = None
1367
a7678cbd7c28 bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff changeset
    30
5737
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    31
    if ancestors[badrev] is None:
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    32
        raise util.Abort(_("Inconsistent state, %s:%s is good and bad")
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
    33
                         % (badrev, hg.short(bad)))
5723
e3b09819496b bisect: switch to rev-based calculation
Matt Mackall <mpm@selenic.com>
parents: 5722
diff changeset
    34
5768
78d14403bdc7 bisect: use a dict for children
Matt Mackall <mpm@selenic.com>
parents: 5767
diff changeset
    35
    # build children dict
78d14403bdc7 bisect: use a dict for children
Matt Mackall <mpm@selenic.com>
parents: 5767
diff changeset
    36
    children = {}
78d14403bdc7 bisect: use a dict for children
Matt Mackall <mpm@selenic.com>
parents: 5767
diff changeset
    37
    visit = [badrev]
5769
49809f4a38d8 bisect: calculate candidate set while finding children
Matt Mackall <mpm@selenic.com>
parents: 5768
diff changeset
    38
    candidates = []
5768
78d14403bdc7 bisect: use a dict for children
Matt Mackall <mpm@selenic.com>
parents: 5767
diff changeset
    39
    while visit:
78d14403bdc7 bisect: use a dict for children
Matt Mackall <mpm@selenic.com>
parents: 5767
diff changeset
    40
        rev = visit.pop(0)
5767
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    41
        if ancestors[rev] == []:
5769
49809f4a38d8 bisect: calculate candidate set while finding children
Matt Mackall <mpm@selenic.com>
parents: 5768
diff changeset
    42
            candidates.append(rev)
5767
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    43
            for prev in clparents(rev):
5768
78d14403bdc7 bisect: use a dict for children
Matt Mackall <mpm@selenic.com>
parents: 5767
diff changeset
    44
                if prev != -1:
78d14403bdc7 bisect: use a dict for children
Matt Mackall <mpm@selenic.com>
parents: 5767
diff changeset
    45
                    if prev in children:
78d14403bdc7 bisect: use a dict for children
Matt Mackall <mpm@selenic.com>
parents: 5767
diff changeset
    46
                        children[prev].append(rev)
78d14403bdc7 bisect: use a dict for children
Matt Mackall <mpm@selenic.com>
parents: 5767
diff changeset
    47
                    else:
78d14403bdc7 bisect: use a dict for children
Matt Mackall <mpm@selenic.com>
parents: 5767
diff changeset
    48
                        children[prev] = [rev]
78d14403bdc7 bisect: use a dict for children
Matt Mackall <mpm@selenic.com>
parents: 5767
diff changeset
    49
                        visit.append(prev)
5767
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    50
5769
49809f4a38d8 bisect: calculate candidate set while finding children
Matt Mackall <mpm@selenic.com>
parents: 5768
diff changeset
    51
    candidates.sort()
5770
f5b858fc8067 bisect: find best node in ancestor collection pass
Matt Mackall <mpm@selenic.com>
parents: 5769
diff changeset
    52
    # have we narrowed it down to one entry?
f5b858fc8067 bisect: find best node in ancestor collection pass
Matt Mackall <mpm@selenic.com>
parents: 5769
diff changeset
    53
    tot = len(candidates)
f5b858fc8067 bisect: find best node in ancestor collection pass
Matt Mackall <mpm@selenic.com>
parents: 5769
diff changeset
    54
    if tot == 1:
f5b858fc8067 bisect: find best node in ancestor collection pass
Matt Mackall <mpm@selenic.com>
parents: 5769
diff changeset
    55
        return (bad, 0)
5771
9d3f49f52a4a bisect: stop early if we find a perfect candidate
Matt Mackall <mpm@selenic.com>
parents: 5770
diff changeset
    56
    perfect = tot / 2
5769
49809f4a38d8 bisect: calculate candidate set while finding children
Matt Mackall <mpm@selenic.com>
parents: 5768
diff changeset
    57
5770
f5b858fc8067 bisect: find best node in ancestor collection pass
Matt Mackall <mpm@selenic.com>
parents: 5769
diff changeset
    58
    # find the best node to test
f5b858fc8067 bisect: find best node in ancestor collection pass
Matt Mackall <mpm@selenic.com>
parents: 5769
diff changeset
    59
    best_rev = None
f5b858fc8067 bisect: find best node in ancestor collection pass
Matt Mackall <mpm@selenic.com>
parents: 5769
diff changeset
    60
    best_len = -1
5772
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    61
    poison = {}
5769
49809f4a38d8 bisect: calculate candidate set while finding children
Matt Mackall <mpm@selenic.com>
parents: 5768
diff changeset
    62
    for rev in candidates:
5772
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    63
        if rev in poison:
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    64
            for c in children.get(rev, []):
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    65
                poison[c] = True # poison children
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    66
            continue
5767
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    67
        l = ancestors[rev]
5770
f5b858fc8067 bisect: find best node in ancestor collection pass
Matt Mackall <mpm@selenic.com>
parents: 5769
diff changeset
    68
        ancestors[rev] = None
5767
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    69
        if l != None:
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    70
            if not l:
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    71
                a = [rev]
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    72
            elif len(l) == 1:
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    73
                a = l[0] + [rev]
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    74
            else:
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    75
                a = {}
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    76
                for s in l:
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    77
                    a.update(dict.fromkeys(s))
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    78
                a[rev] = None
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    79
                a = a.keys()
5772
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    80
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    81
            x = len(a) # number of ancestors
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    82
            y = tot - x # number of non-ancestors
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    83
            value = min(x, y) # how good is this test?
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    84
            if value > best_len and rev not in skip:
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    85
                best_len = value
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    86
                best_rev = rev
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    87
                if value == perfect: # found a perfect candidate? quit early
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    88
                    break
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    89
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    90
            if y < perfect: # all downhill from here?
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    91
                for c in children.get(rev, []):
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    92
                    poison[c] = True # poison children
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    93
                continue
4c46636eafe5 bisect: skip calculations on candidates with too many ancestors
Matt Mackall <mpm@selenic.com>
parents: 5771
diff changeset
    94
5768
78d14403bdc7 bisect: use a dict for children
Matt Mackall <mpm@selenic.com>
parents: 5767
diff changeset
    95
            for c in children.get(rev, []):
5767
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    96
                if ancestors[c]:
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    97
                    ancestors[c].append(a)
5726
19cbe2aea2bc bisect: switch individual ancestor lists from dict to list
Matt Mackall <mpm@selenic.com>
parents: 5725
diff changeset
    98
                else:
5767
dd5f8ed31057 bisect: propagate ancestor lists directly to children
Matt Mackall <mpm@selenic.com>
parents: 5766
diff changeset
    99
                    ancestors[c] = [a]
5734
944b231fa0e7 bisect: move reporting out of core bisect function
Matt Mackall <mpm@selenic.com>
parents: 5733
diff changeset
   100
5737
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   101
    assert best_rev is not None
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   102
    best_node = changelog.node(best_rev)
1367
a7678cbd7c28 bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff changeset
   103
5737
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   104
    return (best_node, tot)
5733
47ec288456bb bisect: add skip command
Matt Mackall <mpm@selenic.com>
parents: 5732
diff changeset
   105
5737
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   106
def bisect(ui, repo, rev=None, extra=None,
5766
23caedc5a28f bisect: add noupdate option
Matt Mackall <mpm@selenic.com>
parents: 5738
diff changeset
   107
               reset=None, good=None, bad=None, skip=None, noupdate=None):
5729
73646515c435 bisect: slightly improve the help message
Matt Mackall <mpm@selenic.com>
parents: 5728
diff changeset
   108
    """Subdivision search of changesets
4390
052062b98f26 Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents: 3891
diff changeset
   109
5729
73646515c435 bisect: slightly improve the help message
Matt Mackall <mpm@selenic.com>
parents: 5728
diff changeset
   110
This extension helps to find changesets which introduce problems.
73646515c435 bisect: slightly improve the help message
Matt Mackall <mpm@selenic.com>
parents: 5728
diff changeset
   111
To use, mark the earliest changeset you know exhibits the problem
4390
052062b98f26 Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents: 3891
diff changeset
   112
as bad, then mark the latest changeset which is free from the problem
052062b98f26 Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents: 3891
diff changeset
   113
as good. Bisect will update your working directory to a revision for
052062b98f26 Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents: 3891
diff changeset
   114
testing. Once you have performed tests, mark the working directory
052062b98f26 Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents: 3891
diff changeset
   115
as bad or good and bisect will either update to another candidate
052062b98f26 Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents: 3891
diff changeset
   116
changeset or announce that it has found the bad revision.
052062b98f26 Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents: 3891
diff changeset
   117
052062b98f26 Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents: 3891
diff changeset
   118
Note: bisect expects bad revisions to be descendants of good revisions.
052062b98f26 Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents: 3891
diff changeset
   119
If you are looking for the point at which a problem was fixed, then make
052062b98f26 Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents: 3891
diff changeset
   120
the problem-free state "bad" and the problematic state "good."
052062b98f26 Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents: 3891
diff changeset
   121
1367
a7678cbd7c28 bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff changeset
   122
    """
5735
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   123
    # backward compatibility
5737
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   124
    if rev in "good bad reset init".split():
5735
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   125
        ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
5737
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   126
        cmd, rev, extra = rev, extra, None
5735
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   127
        if cmd == "good":
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   128
            good = True
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   129
        elif cmd == "bad":
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   130
            bad = True
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   131
        else:
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   132
            reset = True
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   133
    elif extra or good + bad + skip + reset > 1:
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   134
        raise util.Abort("Incompatible arguments")
1855
0ba9dee8cfbd Fixed spacing/indentation, removed #! script header, added short description.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 1854
diff changeset
   135
5737
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   136
    if reset:
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   137
        p = repo.join("bisect.state")
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   138
        if os.path.exists(p):
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   139
            os.unlink(p)
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   140
        return
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   141
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   142
    # load state
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   143
    state = {'good': [], 'bad': [], 'skip': []}
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   144
    if os.path.exists(repo.join("bisect.state")):
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   145
        for l in repo.opener("bisect.state"):
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   146
            kind, node = l[:-1].split()
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   147
            node = repo.lookup(node)
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   148
            if kind not in state:
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   149
                raise util.Abort(_("unknown bisect kind %s") % kind)
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   150
            state[kind].append(node)
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   151
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   152
    # update state
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   153
    node = repo.lookup(rev or '.')
5735
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   154
    if good:
5737
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   155
        state['good'].append(node)
5735
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   156
    elif bad:
5737
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   157
        state['bad'].append(node)
5735
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   158
    elif skip:
5737
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   159
        state['skip'].append(node)
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   160
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   161
    # save state
5738
2a54e2b177b6 bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents: 5737
diff changeset
   162
    f = repo.opener("bisect.state", "w", atomictemp=True)
2a54e2b177b6 bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents: 5737
diff changeset
   163
    wlock = repo.wlock()
2a54e2b177b6 bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents: 5737
diff changeset
   164
    try:
2a54e2b177b6 bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents: 5737
diff changeset
   165
        for kind in state:
2a54e2b177b6 bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents: 5737
diff changeset
   166
            for node in state[kind]:
2a54e2b177b6 bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents: 5737
diff changeset
   167
                f.write("%s %s\n" % (kind, hg.hex(node)))
2a54e2b177b6 bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents: 5737
diff changeset
   168
        f.rename()
2a54e2b177b6 bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents: 5737
diff changeset
   169
    finally:
2a54e2b177b6 bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents: 5737
diff changeset
   170
        del wlock
5737
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   171
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   172
    if not state['good'] or not state['bad']:
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   173
        return
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   174
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   175
    # actually bisect
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   176
    node, changesets = _bisect(repo.changelog, state)
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   177
    if changesets == 0:
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   178
        ui.write(_("The first bad revision is:\n"))
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   179
        displayer = cmdutil.show_changeset(ui, repo, {})
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   180
        displayer.show(changenode=node)
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   181
    elif node is not None:
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   182
        # compute the approximate number of remaining tests
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   183
        tests, size = 0, 2
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   184
        while size <= changesets:
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   185
            tests, size = tests + 1, size * 2
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   186
        rev = repo.changelog.rev(node)
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   187
        ui.write(_("Testing changeset %s:%s "
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   188
                   "(%s changesets remaining, ~%s tests)\n")
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   189
                 % (rev, hg.short(node), changesets, tests))
5766
23caedc5a28f bisect: add noupdate option
Matt Mackall <mpm@selenic.com>
parents: 5738
diff changeset
   190
        if not noupdate:
23caedc5a28f bisect: add noupdate option
Matt Mackall <mpm@selenic.com>
parents: 5738
diff changeset
   191
            cmdutil.bail_if_changed(repo)
23caedc5a28f bisect: add noupdate option
Matt Mackall <mpm@selenic.com>
parents: 5738
diff changeset
   192
            return hg.clean(repo, node)
1367
a7678cbd7c28 bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff changeset
   193
a7678cbd7c28 bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff changeset
   194
cmdtable = {
5737
6c8df073c3ee bisect: remove class
Matt Mackall <mpm@selenic.com>
parents: 5736
diff changeset
   195
    "bisect": (bisect,
5735
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   196
               [('r', 'reset', False, _('reset bisect state')),
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   197
                ('g', 'good', False, _('mark changeset good')),
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   198
                ('b', 'bad', False, _('mark changeset bad')),
5766
23caedc5a28f bisect: add noupdate option
Matt Mackall <mpm@selenic.com>
parents: 5738
diff changeset
   199
                ('s', 'skip', False, _('skip testing changeset')),
23caedc5a28f bisect: add noupdate option
Matt Mackall <mpm@selenic.com>
parents: 5738
diff changeset
   200
                ('U', 'noupdate', False, _('do not update to target'))],
5735
9079081b8982 bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents: 5734
diff changeset
   201
               _("hg bisect [-gbsr] [REV]"))
1367
a7678cbd7c28 bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff changeset
   202
}