diff options
Diffstat (limited to 'script/bisect-test.py')
-rwxr-xr-x | script/bisect-test.py | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/script/bisect-test.py b/script/bisect-test.py new file mode 100755 index 0000000..7c5cd63 --- /dev/null +++ b/script/bisect-test.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# 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 +import tempfile +import sys +from optparse import OptionParser + +parser = OptionParser() +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("", "--autogen-command", help="command to use for autogen (default ./autogen.sh)", + type='str', default="./autogen.sh") +parser.add_option("", "--configure", help="run configure.developer before each build", + action="store_true", default=False) +parser.add_option("", "--configure-command", help="the command for configure (default ./configure.developer)", + type='str', default="./configure.developer") +parser.add_option("", "--build-command", help="the command to build the tree (default 'make -j')", + type='str', default="make -j") +parser.add_option("", "--test-command", help="the command to test the tree (default 'make test')", + type='str', default="make test") +parser.add_option("", "--clean", help="run make clean before each build", + action="store_true", default=False) + + +(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.exists(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, mode="w+t") +f.write("set -x\n") +f.write("cd %s || exit 125\n" % cwd) +if opts.autogen: + f.write("%s || exit 125\n" % opts.autogen_command) +if opts.configure: + f.write("%s || exit 125\n" % opts.configure_command) +if opts.clean: + f.write("make clean || exit 125\n") +if opts.skip_build_errors: + build_err = 125 +else: + build_err = 1 +f.write("%s || exit %u\n" % (opts.build_command, build_err)) +f.write("%s || exit 1\n" % opts.test_command) +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 as reason: + print("Failed bisect: %s" % reason) + cleanup() + +run_cmd("git bisect reset", dir=gitroot) +os.unlink(f.name) +sys.exit(ret) |