@ -96,6 +96,13 @@ OUTCOME_OK, OUTCOME_WARNING, OUTCOME_ERROR, OUTCOME_UNKNOWN = range(4)
# Translate a commit subject into a valid filename
trans_valid_chars = string . maketrans ( " /: " , " --- " )
CONFIG_FILENAMES = [
' .config ' , ' .config-spl ' , ' .config-tpl ' ,
' autoconf.mk ' , ' autoconf-spl.mk ' , ' autoconf-tpl.mk ' ,
' autoconf.h ' , ' autoconf-spl.h ' , ' autoconf-tpl.h ' ,
' u-boot.cfg ' , ' u-boot-spl.cfg ' , ' u-boot-tpl.cfg '
]
class Builder :
""" Class for building U-Boot for a particular commit.
@ -166,12 +173,17 @@ class Builder:
value is itself a dictionary :
key : function name
value : Size of function in bytes
config : Dictionary keyed by filename - e . g . ' .config ' . Each
value is itself a dictionary :
key : config name
value : config value
"""
def __init__ ( self , rc , err_lines , sizes , func_sizes ) :
def __init__ ( self , rc , err_lines , sizes , func_sizes , config ) :
self . rc = rc
self . err_lines = err_lines
self . sizes = sizes
self . func_sizes = func_sizes
self . config = config
def __init__ ( self , toolchains , base_dir , git_dir , num_threads , num_jobs ,
gnu_make = ' make ' , checkout = True , show_unknown = True , step = 1 ,
@ -254,7 +266,7 @@ class Builder:
def SetDisplayOptions ( self , show_errors = False , show_sizes = False ,
show_detail = False , show_bloat = False ,
list_error_boards = False ) :
list_error_boards = False , show_config = False ) :
""" Setup display options for the builder.
show_errors : True to show summarised error / warning info
@ -262,12 +274,14 @@ class Builder:
show_detail : Show detail for each board
show_bloat : Show detail for each function
list_error_boards : Show the boards which caused each error / warning
show_config : Show config deltas
"""
self . _show_errors = show_errors
self . _show_sizes = show_sizes
self . _show_detail = show_detail
self . _show_bloat = show_bloat
self . _list_error_boards = list_error_boards
self . _show_config = show_config
def _AddTimestamp ( self ) :
""" Add a new timestamp to the list and record the build period.
@ -519,13 +533,50 @@ class Builder:
sym [ name ] = sym . get ( name , 0 ) + int ( size , 16 )
return sym
def GetBuildOutcome ( self , commit_upto , target , read_func_sizes ) :
def _ProcessConfig ( self , fname ) :
""" Read in a .config, autoconf.mk or autoconf.h file
This function handles all config file types . It ignores comments and
any #defines which don't start with CONFIG_.
Args :
fname : Filename to read
Returns :
Dictionary :
key : Config name ( e . g . CONFIG_DM )
value : Config value ( e . g . 1 )
"""
config = { }
if os . path . exists ( fname ) :
with open ( fname ) as fd :
for line in fd :
line = line . strip ( )
if line . startswith ( ' #define ' ) :
values = line [ 8 : ] . split ( ' ' , 1 )
if len ( values ) > 1 :
key , value = values
else :
key = values [ 0 ]
value = ' '
if not key . startswith ( ' CONFIG_ ' ) :
continue
elif not line or line [ 0 ] in [ ' # ' , ' * ' , ' / ' ] :
continue
else :
key , value = line . split ( ' = ' , 1 )
config [ key ] = value
return config
def GetBuildOutcome ( self , commit_upto , target , read_func_sizes ,
read_config ) :
""" Work out the outcome of a build.
Args :
commit_upto : Commit number to check ( 0. . n - 1 )
target : Target board to check
read_func_sizes : True to read function size information
read_config : True to read . config and autoconf . h files
Returns :
Outcome object
@ -534,6 +585,7 @@ class Builder:
sizes_file = self . GetSizesFile ( commit_upto , target )
sizes = { }
func_sizes = { }
config = { }
if os . path . exists ( done_file ) :
with open ( done_file , ' r ' ) as fd :
return_code = int ( fd . readline ( ) )
@ -577,17 +629,25 @@ class Builder:
' ' )
func_sizes [ dict_name ] = self . ReadFuncSizes ( fname , fd )
return Builder . Outcome ( rc , err_lines , sizes , func_sizes )
if read_config :
output_dir = self . GetBuildDir ( commit_upto , target )
for name in CONFIG_FILENAMES :
fname = os . path . join ( output_dir , name )
config [ name ] = self . _ProcessConfig ( fname )
return Builder . Outcome ( rc , err_lines , sizes , func_sizes , config )
return Builder . Outcome ( OUTCOME_UNKNOWN , [ ] , { } , { } )
return Builder . Outcome ( OUTCOME_UNKNOWN , [ ] , { } , { } , { } )
def GetResultSummary ( self , boards_selected , commit_upto , read_func_sizes ) :
def GetResultSummary ( self , boards_selected , commit_upto , read_func_sizes ,
read_config ) :
""" Calculate a summary of the results of building a commit.
Args :
board_selected : Dict containing boards to summarise
commit_upto : Commit number to summarize ( 0. . self . count - 1 )
read_func_sizes : True to read function size information
read_config : True to read . config and autoconf . h files
Returns :
Tuple :
@ -599,6 +659,10 @@ class Builder:
List containing a summary of warning lines
Dict keyed by error line , containing a list of the Board
objects with that warning
Dictionary keyed by filename - e . g . ' .config ' . Each
value is itself a dictionary :
key : config name
value : config value
"""
def AddLine ( lines_summary , lines_boards , line , board ) :
line = line . rstrip ( )
@ -613,10 +677,13 @@ class Builder:
err_lines_boards = { }
warn_lines_summary = [ ]
warn_lines_boards = { }
config = { }
for fname in CONFIG_FILENAMES :
config [ fname ] = { }
for board in boards_selected . itervalues ( ) :
outcome = self . GetBuildOutcome ( commit_upto , board . target ,
read_func_sizes )
read_func_sizes , read_config )
board_dict [ board . target ] = outcome
last_func = None
last_was_warning = False
@ -642,8 +709,14 @@ class Builder:
line , board )
last_was_warning = is_warning
last_func = None
for fname in CONFIG_FILENAMES :
config [ fname ] = { }
if outcome . config :
for key , value in outcome . config [ fname ] . iteritems ( ) :
config [ fname ] [ key ] = value
return ( board_dict , err_lines_summary , err_lines_boards ,
warn_lines_summary , warn_lines_boards )
warn_lines_summary , warn_lines_boards , config )
def AddOutcome ( self , board_dict , arch_list , changes , char , color ) :
""" Add an output to our list of outcomes for each architecture
@ -696,11 +769,14 @@ class Builder:
"""
self . _base_board_dict = { }
for board in board_selected :
self . _base_board_dict [ board ] = Builder . Outcome ( 0 , [ ] , [ ] , { } )
self . _base_board_dict [ board ] = Builder . Outcome ( 0 , [ ] , [ ] , { } , { } )
self . _base_err_lines = [ ]
self . _base_warn_lines = [ ]
self . _base_err_line_boards = { }
self . _base_warn_line_boards = { }
self . _base_config = { }
for fname in CONFIG_FILENAMES :
self . _base_config [ fname ] = { }
def PrintFuncSizeDetail ( self , fname , old , new ) :
grow , shrink , add , remove , up , down = 0 , 0 , 0 , 0 , 0 , 0
@ -895,7 +971,8 @@ class Builder:
def PrintResultSummary ( self , board_selected , board_dict , err_lines ,
err_line_boards , warn_lines , warn_line_boards ,
show_sizes , show_detail , show_bloat ) :
config , show_sizes , show_detail , show_bloat ,
show_config ) :
""" Compare results with the base results and display delta.
Only boards mentioned in board_selected will be considered . This
@ -916,9 +993,14 @@ class Builder:
none , or we don ' t want to print errors
warn_line_boards : Dict keyed by warning line , containing a list of
the Board objects with that warning
config : Dictionary keyed by filename - e . g . ' .config ' . Each
value is itself a dictionary :
key : config name
value : config value
show_sizes : Show image size deltas
show_detail : Show detail for each board
show_bloat : Show detail for each function
show_config : Show config changes
"""
def _BoardList ( line , line_boards ) :
""" Helper function to get a line of boards containing a line
@ -953,6 +1035,48 @@ class Builder:
_BoardList ( line , base_line_boards ) + line )
return better_lines , worse_lines
def _CalcConfig ( delta , name , config ) :
""" Calculate configuration changes
Args :
delta : Type of the delta , e . g . ' + '
name : name of the file which changed ( e . g . . config )
config : configuration change dictionary
key : config name
value : config value
Returns :
String containing the configuration changes which can be
printed
"""
out = ' '
for key in sorted ( config . keys ( ) ) :
out + = ' %s = %s ' % ( key , config [ key ] )
return ' %5s %s : %s ' % ( delta , name , out )
def _ShowConfig ( name , config_plus , config_minus , config_change ) :
""" Show changes in configuration
Args :
config_plus : configurations added , dictionary
key : config name
value : config value
config_minus : configurations removed , dictionary
key : config name
value : config value
config_change : configurations changed , dictionary
key : config name
value : config value
"""
if config_plus :
Print ( _CalcConfig ( ' + ' , name , config_plus ) ,
colour = self . col . GREEN )
if config_minus :
Print ( _CalcConfig ( ' - ' , name , config_minus ) ,
colour = self . col . RED )
if config_change :
Print ( _CalcConfig ( ' +/- ' , name , config_change ) ,
colour = self . col . YELLOW )
better = [ ] # List of boards fixed since last commit
worse = [ ] # List of new broken boards since last commit
new = [ ] # List of boards that didn't exist last time
@ -1013,12 +1137,42 @@ class Builder:
self . PrintSizeSummary ( board_selected , board_dict , show_detail ,
show_bloat )
if show_config :
all_config_plus = { }
all_config_minus = { }
all_config_change = { }
for name in CONFIG_FILENAMES :
if not config [ name ] :
continue
config_plus = { }
config_minus = { }
config_change = { }
base = self . _base_config [ name ]
for key , value in config [ name ] . iteritems ( ) :
if key not in base :
config_plus [ key ] = value
all_config_plus [ key ] = value
for key , value in base . iteritems ( ) :
if key not in config [ name ] :
config_minus [ key ] = value
all_config_minus [ key ] = value
for key , value in base . iteritems ( ) :
new_value = base [ key ]
if key in config [ name ] and value != new_value :
desc = ' %s -> %s ' % ( value , new_value )
config_change [ key ] = desc
all_config_change [ key ] = desc
_ShowConfig ( name , config_plus , config_minus , config_change )
_ShowConfig ( ' all ' , all_config_plus , all_config_minus ,
all_config_change )
# Save our updated information for the next call to this function
self . _base_board_dict = board_dict
self . _base_err_lines = err_lines
self . _base_warn_lines = warn_lines
self . _base_err_line_boards = err_line_boards
self . _base_warn_line_boards = warn_line_boards
self . _base_config = config
# Get a list of boards that did not get built, if needed
not_built = [ ]
@ -1031,9 +1185,10 @@ class Builder:
def ProduceResultSummary ( self , commit_upto , commits , board_selected ) :
( board_dict , err_lines , err_line_boards , warn_lines ,
warn_line_boards ) = self . GetResultSummary (
warn_line_boards , config ) = self . GetResultSummary (
board_selected , commit_upto ,
read_func_sizes = self . _show_bloat )
read_func_sizes = self . _show_bloat ,
read_config = self . _show_config )
if commits :
msg = ' %02d : %s ' % ( commit_upto + 1 ,
commits [ commit_upto ] . subject )
@ -1041,7 +1196,8 @@ class Builder:
self . PrintResultSummary ( board_selected , board_dict ,
err_lines if self . _show_errors else [ ] , err_line_boards ,
warn_lines if self . _show_errors else [ ] , warn_line_boards ,
self . _show_sizes , self . _show_detail , self . _show_bloat )
config , self . _show_sizes , self . _show_detail ,
self . _show_bloat , self . _show_config )
def ShowSummary ( self , commits , board_selected ) :
""" Show a build summary for U-Boot for a given board list.