2018-12-12 03:18:40 +03:00
#!/usr/bin/env python3
2010-10-02 08:10:39 +04:00
# 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
2018-07-30 09:21:38 +03:00
import os
import tempfile
import sys
2010-10-02 08:10:39 +04:00
from optparse import OptionParser
parser = OptionParser ( )
2010-10-02 09:07:04 +04:00
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 )
2018-07-30 09:19:05 +03:00
parser . add_option ( " " , " --autogen " , help = " run autogen before each build " , action = " store_true " , default = False )
2010-10-07 07:20:15 +04:00
parser . add_option ( " " , " --autogen-command " , help = " command to use for autogen (default ./autogen.sh) " ,
type = ' str ' , default = " ./autogen.sh " )
2010-10-02 08:10:39 +04:00
parser . add_option ( " " , " --configure " , help = " run configure.developer before each build " ,
2018-07-30 09:16:12 +03:00
action = " store_true " , default = False )
2010-10-07 07:20:15 +04:00
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 " )
2010-10-02 08:10:39 +04:00
parser . add_option ( " " , " --clean " , help = " run make clean before each build " ,
2010-10-07 07:20:15 +04:00
action = " store_true " , default = False )
2010-10-02 08:10:39 +04:00
( 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 )
2018-07-30 09:20:39 +03:00
2010-10-02 08:10:39 +04:00
def find_git_root ( ) :
''' get to the top of the git repo '''
2018-07-30 09:18:03 +03:00
p = os . getcwd ( )
2010-10-02 08:10:39 +04:00
while p != ' / ' :
if os . path . isdir ( os . path . join ( p , " .git " ) ) :
return p
p = os . path . abspath ( os . path . join ( p , ' .. ' ) )
return None
2018-07-30 09:21:29 +03:00
2010-10-02 08:10:39 +04:00
cwd = os . getcwd ( )
gitroot = find_git_root ( )
# create a bisect script
2019-03-17 05:38:43 +03:00
f = tempfile . NamedTemporaryFile ( delete = False , mode = " w+t " )
2010-10-02 08:10:39 +04:00
f . write ( " set -x \n " )
f . write ( " cd %s || exit 125 \n " % cwd )
if opts . autogen :
2010-10-07 07:20:15 +04:00
f . write ( " %s || exit 125 \n " % opts . autogen_command )
2010-10-02 08:10:39 +04:00
if opts . configure :
2010-10-07 07:20:15 +04:00
f . write ( " %s || exit 125 \n " % opts . configure_command )
2010-10-02 08:10:39 +04:00
if opts . clean :
f . write ( " make clean || exit 125 \n " )
if opts . skip_build_errors :
2010-10-07 07:20:15 +04:00
build_err = 125
2010-10-02 09:07:04 +04:00
else :
2010-10-07 07:20:15 +04:00
build_err = 1
f . write ( " %s || exit %u \n " % ( opts . build_command , build_err ) )
f . write ( " %s || exit 1 \n " % opts . test_command )
2010-10-02 08:10:39 +04:00
f . write ( " exit 0 \n " )
f . close ( )
2018-07-30 09:20:39 +03:00
2010-10-02 08:10:39 +04:00
def cleanup ( ) :
run_cmd ( " git bisect reset " , dir = gitroot )
os . unlink ( f . name )
sys . exit ( - 1 )
2018-07-30 09:21:29 +03:00
2010-10-02 08:10:39 +04:00
# run bisect
ret = - 1
try :
run_cmd ( " git bisect reset " , dir = gitroot , show = False , checkfail = False )
2010-10-02 09:07:04 +04:00
run_cmd ( " git bisect start %s %s -- " % ( opts . bad , opts . good ) , dir = gitroot )
2010-10-02 08:10:39 +04:00
ret = run_cmd ( " git bisect run bash %s " % f . name , dir = gitroot , show = True , checkfail = False )
except KeyboardInterrupt :
print ( " Cleaning up " )
cleanup ( )
2018-02-14 00:36:22 +03:00
except Exception as reason :
2010-10-02 08:10:39 +04:00
print ( " Failed bisect: %s " % reason )
cleanup ( )
2010-10-07 07:20:15 +04:00
run_cmd ( " git bisect reset " , dir = gitroot )
2010-10-02 08:10:39 +04:00
os . unlink ( f . name )
sys . exit ( ret )