2 # use git bisect to work out what commit caused a test failure
3 # Copyright Andrew Tridgell 2010
4 # released under GNU GPL v3 or later
7 from subprocess
import call
, check_call
, Popen
, PIPE
11 from optparse
import OptionParser
13 parser
= OptionParser()
14 parser
.add_option("", "--good", help="known good revision (default HEAD~100)", default
='HEAD~100')
15 parser
.add_option("", "--bad", help="known bad revision (default HEAD)", default
='HEAD')
16 parser
.add_option("", "--skip-build-errors", help="skip revision where make fails",
17 action
='store_true', default
=False)
18 parser
.add_option("", "--autogen", help="run autogen before each build", action
="store_true", default
=False)
19 parser
.add_option("", "--autogen-command", help="command to use for autogen (default ./autogen.sh)",
20 type='str', default
="./autogen.sh")
21 parser
.add_option("", "--configure", help="run configure.developer before each build",
22 action
="store_true", default
=False)
23 parser
.add_option("", "--configure-command", help="the command for configure (default ./configure.developer)",
24 type='str', default
="./configure.developer")
25 parser
.add_option("", "--build-command", help="the command to build the tree (default 'make -j')",
26 type='str', default
="make -j")
27 parser
.add_option("", "--test-command", help="the command to test the tree (default 'make test')",
28 type='str', default
="make test")
29 parser
.add_option("", "--clean", help="run make clean before each build",
30 action
="store_true", default
=False)
33 (opts
, args
) = parser
.parse_args()
36 def run_cmd(cmd
, dir=".", show
=True, output
=False, checkfail
=True):
38 print("Running: '%s' in '%s'" % (cmd
, dir))
40 return Popen([cmd
], shell
=True, stdout
=PIPE
, cwd
=dir).communicate()[0]
42 return check_call(cmd
, shell
=True, cwd
=dir)
44 return call(cmd
, shell
=True, cwd
=dir)
48 '''get to the top of the git repo'''
51 if os
.path
.exists(os
.path
.join(p
, ".git")):
53 p
= os
.path
.abspath(os
.path
.join(p
, '..'))
58 gitroot
= find_git_root()
60 # create a bisect script
61 f
= tempfile
.NamedTemporaryFile(delete
=False, mode
="w+t")
63 f
.write("cd %s || exit 125\n" % cwd
)
65 f
.write("%s || exit 125\n" % opts
.autogen_command
)
67 f
.write("%s || exit 125\n" % opts
.configure_command
)
69 f
.write("make clean || exit 125\n")
70 if opts
.skip_build_errors
:
74 f
.write("%s || exit %u\n" % (opts
.build_command
, build_err
))
75 f
.write("%s || exit 1\n" % opts
.test_command
)
81 run_cmd("git bisect reset", dir=gitroot
)
89 run_cmd("git bisect reset", dir=gitroot
, show
=False, checkfail
=False)
90 run_cmd("git bisect start %s %s --" % (opts
.bad
, opts
.good
), dir=gitroot
)
91 ret
= run_cmd("git bisect run bash %s" % f
.name
, dir=gitroot
, show
=True, checkfail
=False)
92 except KeyboardInterrupt:
95 except Exception as reason
:
96 print("Failed bisect: %s" % reason
)
99 run_cmd("git bisect reset", dir=gitroot
)