summaryrefslogtreecommitdiff
path: root/script/bisect-test.py
blob: e5f91b02f131557004cf9f3052c998ea208d3baa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/env python
# use git bisect to work out what commit caused a test failure
# Copyright Andrew Tridgell 2010
# released under GNU GPL v3 or later


from subprocess import call, check_call, Popen, PIPE
import os, tempfile, sys
from optparse import OptionParser

parser = OptionParser()
parser.add_option("", "--tests", help="list of tests to run", default='*')
parser.add_option("", "--quick", help="use make quicktest", default='')
parser.add_option("", "--good", help="known good revision (default HEAD~100)", default='HEAD~100')
parser.add_option("", "--bad", help="known bad revision (default HEAD)", default='HEAD')
parser.add_option("", "--skip-build-errors", help="skip revision where make fails",
                  action='store_true', default=False)
parser.add_option("", "--autogen", help="run autogen before each build",action="store_true", default=False)
parser.add_option("", "--configure", help="run configure.developer before each build",
    action="store_true", default=False)
parser.add_option("", "--clean", help="run make clean before each build",
    action="store_true", default=False)
parser.add_option("-j", "", help="use make -j N", dest='N', type='int', action="store", default=1)

(opts, args) = parser.parse_args()


def run_cmd(cmd, dir=".", show=True, output=False, checkfail=True):
    if show:
        print("Running: '%s' in '%s'" % (cmd, dir))
    if output:
        return Popen([cmd], shell=True, stdout=PIPE, cwd=dir).communicate()[0]
    elif checkfail:
        return check_call(cmd, shell=True, cwd=dir)
    else:
        return call(cmd, shell=True, cwd=dir)

def find_git_root():
    '''get to the top of the git repo'''
    p=os.getcwd()
    while p != '/':
        if os.path.isdir(os.path.join(p, ".git")):
            return p
        p = os.path.abspath(os.path.join(p, '..'))
    return None

cwd = os.getcwd()
gitroot = find_git_root()

# create a bisect script
f = tempfile.NamedTemporaryFile(delete=False)
f.write("set -x\n")
f.write("cd %s || exit 125\n" % cwd)
if opts.autogen:
    f.write("./autogen.sh || exit 125\n")
if opts.configure:
    f.write("./configure.developer || exit 125\n")
if opts.clean:
    f.write("make clean || exit 125\n")
if opts.skip_build_errors:
    f.write("make -j %u || exit 125\n" % opts.N)
else:
    f.write("make -j %u || exit 1\n" % opts.N)
if opts.quick:
    target="quicktest"
else:
    target="test"
f.write("make -j %u %s TESTS='%s' FAIL_IMMEDIATELY=1 || exit 1\n" % (opts.N, target, opts.tests))
f.write("exit 0\n")
f.close()

def cleanup():
    run_cmd("git bisect reset", dir=gitroot)
    os.unlink(f.name)
    sys.exit(-1)

# run bisect
ret = -1
try:
    run_cmd("git bisect reset", dir=gitroot, show=False, checkfail=False)
    run_cmd("git bisect start %s %s --" % (opts.bad, opts.good), dir=gitroot)
    ret = run_cmd("git bisect run bash %s" % f.name, dir=gitroot, show=True, checkfail=False)
except KeyboardInterrupt:
    print("Cleaning up")
    cleanup()
except Exception, reason:
    print("Failed bisect: %s" % reason)
    cleanup()

os.unlink(f.name)
sys.exit(ret)