@ -14,87 +14,123 @@
from mesonbuild import environment
import sys , os , subprocess , pathlib
import argparse , sys , os , subprocess , pathlib
def coverage ( outputs , source_root , build_root , log_dir ) :
outfiles = [ ]
exitcode = 0
def coverage ( source_root , build_root , log_dir ) :
( gcovr_exe , gcovr_new_rootdir , lcov_exe , genhtml_exe ) = environment . find_coverage_tools ( )
if gcovr_exe :
# gcovr >= 3.1 interprets rootdir differently
if gcovr_new_rootdir :
rootdir = build_root
else :
rootdir = source_root
subprocess . check_call ( [ gcovr_exe ,
' -x ' ,
' -r ' , rootdir ,
' -o ' , os . path . join ( log_dir , ' coverage.xml ' ) ,
] )
subprocess . check_call ( [ gcovr_exe ,
' -r ' , rootdir ,
' -o ' , os . path . join ( log_dir , ' coverage.txt ' ) ,
] )
if lcov_exe and genhtml_exe :
htmloutdir = os . path . join ( log_dir , ' coveragereport ' )
covinfo = os . path . join ( log_dir , ' coverage.info ' )
initial_tracefile = covinfo + ' .initial '
run_tracefile = covinfo + ' .run '
raw_tracefile = covinfo + ' .raw '
subprocess . check_call ( [ lcov_exe ,
' --directory ' , build_root ,
' --capture ' ,
' --initial ' ,
' --output-file ' ,
initial_tracefile ] )
subprocess . check_call ( [ lcov_exe ,
' --directory ' , build_root ,
' --capture ' ,
' --output-file ' , run_tracefile ,
' --no-checksum ' ,
' --rc ' , ' lcov_branch_coverage=1 ' ,
] )
# Join initial and test results.
subprocess . check_call ( [ lcov_exe ,
' -a ' , initial_tracefile ,
' -a ' , run_tracefile ,
' -o ' , raw_tracefile ] )
# Remove all directories outside the source_root from the covinfo
subprocess . check_call ( [ lcov_exe ,
' --extract ' , raw_tracefile ,
os . path . join ( source_root , ' * ' ) ,
' --output-file ' , covinfo ] )
subprocess . check_call ( [ genhtml_exe ,
' --prefix ' , build_root ,
' --output-directory ' , htmloutdir ,
' --title ' , ' Code coverage ' ,
' --legend ' ,
' --show-details ' ,
' --branch-coverage ' ,
covinfo ] )
elif gcovr_exe and gcovr_new_rootdir :
htmloutdir = os . path . join ( log_dir , ' coveragereport ' )
subprocess . check_call ( [ gcovr_exe ,
' --html ' ,
' --html-details ' ,
' -r ' , build_root ,
' -o ' , os . path . join ( htmloutdir , ' index.html ' ) ,
] )
if gcovr_exe :
# gcovr >= 3.1 interprets rootdir differently
if gcovr_new_rootdir :
gcovr_rootdir = build_root
else :
gcovr_rootdir = source_root
if not outputs or ' xml ' in outputs :
if gcovr_exe :
subprocess . check_call ( [ gcovr_exe ,
' -x ' ,
' -r ' , gcovr_rootdir ,
' -o ' , os . path . join ( log_dir , ' coverage.xml ' ) ,
] )
outfiles . append ( ( ' Xml ' , pathlib . Path ( log_dir , ' coverage.xml ' ) ) )
elif outputs :
print ( ' gcovr needed to generate Xml coverage report ' )
exitcode = 1
if not outputs or ' text ' in outputs :
if gcovr_exe :
subprocess . check_call ( [ gcovr_exe ,
' -r ' , gcovr_rootdir ,
' -o ' , os . path . join ( log_dir , ' coverage.txt ' ) ,
] )
outfiles . append ( ( ' Text ' , pathlib . Path ( log_dir , ' coverage.txt ' ) ) )
elif outputs :
print ( ' gcovr needed to generate text coverage report ' )
exitcode = 1
if not outputs or ' html ' in outputs :
if lcov_exe and genhtml_exe :
htmloutdir = os . path . join ( log_dir , ' coveragereport ' )
covinfo = os . path . join ( log_dir , ' coverage.info ' )
initial_tracefile = covinfo + ' .initial '
run_tracefile = covinfo + ' .run '
raw_tracefile = covinfo + ' .raw '
subprocess . check_call ( [ lcov_exe ,
' --directory ' , build_root ,
' --capture ' ,
' --initial ' ,
' --output-file ' ,
initial_tracefile ] )
subprocess . check_call ( [ lcov_exe ,
' --directory ' , build_root ,
' --capture ' ,
' --output-file ' , run_tracefile ,
' --no-checksum ' ,
' --rc ' , ' lcov_branch_coverage=1 ' ,
] )
# Join initial and test results.
subprocess . check_call ( [ lcov_exe ,
' -a ' , initial_tracefile ,
' -a ' , run_tracefile ,
' -o ' , raw_tracefile ] )
# Remove all directories outside the source_root from the covinfo
subprocess . check_call ( [ lcov_exe ,
' --extract ' , raw_tracefile ,
os . path . join ( source_root , ' * ' ) ,
' --output-file ' , covinfo ] )
subprocess . check_call ( [ genhtml_exe ,
' --prefix ' , build_root ,
' --output-directory ' , htmloutdir ,
' --title ' , ' Code coverage ' ,
' --legend ' ,
' --show-details ' ,
' --branch-coverage ' ,
covinfo ] )
outfiles . append ( ( ' Html ' , pathlib . Path ( htmloutdir , ' index.html ' ) ) )
elif gcovr_exe and gcovr_new_rootdir :
htmloutdir = os . path . join ( log_dir , ' coveragereport ' )
subprocess . check_call ( [ gcovr_exe ,
' --html ' ,
' --html-details ' ,
' -r ' , build_root ,
' -o ' , os . path . join ( htmloutdir , ' index.html ' ) ,
] )
outfiles . append ( ( ' Html ' , pathlib . Path ( htmloutdir , ' index.html ' ) ) )
elif outputs :
print ( ' lcov/genhtml or gcovr >= 3.1 needed to generate Html coverage report ' )
exitcode = 1
if not outputs and not outfiles :
print ( ' Need gcovr or lcov/genhtml to generate any coverage reports ' )
exitcode = 1
if outfiles :
print ( ' ' )
print ( ' XML coverage report can be found at ' ,
pathlib . Path ( log_dir , ' coverage.xml ' ) . as_uri ( ) )
print ( ' Text coverage report can be found at ' ,
pathlib . Path ( log_dir , ' coverage.txt ' ) . as_uri ( ) )
if ( lcov_exe and genhtml_exe ) or ( gcovr_exe and gcovr_new_rootdir ) :
print ( ' Html coverage report can be found at ' ,
pathlib . Path ( htmloutdir , ' index.html ' ) . as_uri ( ) )
return 0
for ( filetype , path ) in outfiles :
print ( filetype + ' coverage report can be found at ' , path . as_uri ( ) )
return exitcode
def run ( args ) :
if not os . path . isfile ( ' build.ninja ' ) :
print ( ' Coverage currently only works with the Ninja backend. ' )
return 1
source_root , build_root , log_dir = args [ : ]
return coverage ( source_root , build_root , log_dir )
parser = argparse . ArgumentParser ( description = ' Generate coverage reports ' )
parser . add_argument ( ' --text ' , dest = ' outputs ' , action = ' append_const ' ,
const = ' text ' , help = ' generate Text report ' )
parser . add_argument ( ' --xml ' , dest = ' outputs ' , action = ' append_const ' ,
const = ' xml ' , help = ' generate Xml report ' )
parser . add_argument ( ' --html ' , dest = ' outputs ' , action = ' append_const ' ,
const = ' html ' , help = ' generate Html report ' )
parser . add_argument ( ' source_root ' )
parser . add_argument ( ' build_root ' )
parser . add_argument ( ' log_dir ' )
options = parser . parse_args ( args )
return coverage ( options . outputs , options . source_root ,
options . build_root , options . log_dir )
if __name__ == ' __main__ ' :
sys . exit ( run ( sys . argv [ 1 : ] ) )