diff options
author | Gabriel Ganne <gabriel.ganne@enea.com> | 2018-02-20 12:07:36 +0100 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2018-02-24 16:53:44 +0100 |
commit | ed0001727225b9acd84420156d3b18820c7a11f5 (patch) | |
tree | f6da4a8204cbf343596f63bc9d32ade98f1a8f5d | |
parent | c0aa1dd1915d89dbdacb1265f48ed83ebc02708d (diff) |
tools/build_configs.py: improve pep8 and pylint compliance
pep8 fixes:
* remove whitespaces in dict declarations
(E203 whitespace before ':')
* two blank lines between functions
(E302 expected 2 blank lines, found 1)
* no spaces in set function arguments
(E251 unexpected spaces around keyword / parameter equals)
pylint fixes:
* rename some variables to fix some redefined-outer-name warnings
passing <- passing_filters_list
blocking <- blocking_filters_list
* explicit config file name (invalid-name warning)
* fix many map/filter deprecated-lambda warnings [1]
eg. for values as below, replace map/lambda by comprehension as follow
# values = [1, 2, 3]
# doubles = map(lambda x: x * 2, values)
# doubles = [x * 2 for x in values]
* un-name some unused variables with '_' to silence unused-variable
eg.
# for used_val_1, used_val_2 in my_list:
# ...
# for used_val_1, _ in my_list:
[1] https://docs.quantifiedcode.com/python-anti-patterns/readability/using_map_or_filter_where_list_comprehension_is_possible.html
-rwxr-xr-x | tools/build_configs.py | 209 |
1 files changed, 120 insertions, 89 deletions
diff --git a/tools/build_configs.py b/tools/build_configs.py index b44c77b..cd71459 100755 --- a/tools/build_configs.py +++ b/tools/build_configs.py @@ -1,11 +1,13 @@ #!/usr/bin/env python -# -# Generate a large number of valid configurations, build them concurrently, -# and report. +''' +Configuration builder. + +Generate a large number of valid configurations, build them concurrently, +and report. +''' from __future__ import print_function -import argparse import itertools import multiprocessing import os @@ -15,9 +17,13 @@ import subprocess import sys import tempfile +from argparse import Action, ArgumentParser, RawDescriptionHelpFormatter + + def print_fn(*args): - map(sys.stdout.write, args + tuple('\n')) - return None + for arg in args: + print(arg) + def quote_if_needed(value): if not value.isdigit() and value != 'y' and value != 'n': @@ -25,24 +31,30 @@ def quote_if_needed(value): return value -# Generate a list of all possible combinations of options. + def gen_configs_list(options_dict): + 'Generate a list of all possible combinations of options.' names = options_dict.keys() product = itertools.product(*options_dict.values()) - return map(lambda x: dict(zip(names, x)), product) + return [dict(zip(names, x)) for x in product] + -# Generate a list of all possible combinations of options as strings. def gen_configs_values_str(options_dict): - return map(lambda x: ' '.join(x.values()), gen_configs_list(options_dict)) + 'Generate a list of all possible combinations of options as strings.' + return [' '.join(x.values()) for x in gen_configs_list(options_dict)] + -# Does the same as gen_configs_values_str() but adds the -Werror option -# to all generated strings. def gen_cc_options_list(options_dict): - return map(lambda x: '%s -Werror' % x, gen_configs_values_str(options_dict)) + ''' + Does the same as gen_configs_values_str() but adds the -Werror option + to all generated strings. + ''' + return ['{} -Werror'.format(x) for x in gen_configs_values_str(options_dict)] + def gen_exclusive_boolean_filter(args): enabled_option, options_list = args - filter = dict() + option_filter = dict() for option in options_list: if option == enabled_option: @@ -50,24 +62,28 @@ def gen_exclusive_boolean_filter(args): else: value = [True, 'n'] - filter.update({option : value}) + option_filter.update({option: value}) + + return option_filter - return filter -# Generate a list of passing filters on a list of boolean options. -# -# The resulting filters match configurations that have only one of the given -# options enabled, unless all_disabled is true, in which case an additional -# filter is generated to match configurations where none of the options -# are enabled. def gen_exclusive_boolean_filters_list(options_list, all_disabled=False): - option_and_options = list(map(lambda x: (x, options_list), options_list)) + ''' + Generate a list of passing filters on a list of boolean options. + + The resulting filters match configurations that have only one of the given + options enabled, unless all_disabled is true, in which case an additional + filter is generated to match configurations where none of the options + are enabled. + ''' + option_and_options = [(x, options_list) for x in options_list] if all_disabled: option_and_options.append((None, options_list)) return list(map(gen_exclusive_boolean_filter, option_and_options)) + # Dictionary of compiler options. # # Each entry describes a single compiler option. The key is mostly ignored @@ -75,9 +91,9 @@ def gen_exclusive_boolean_filters_list(options_list, all_disabled=False): # gen_configs_list() function. The value is a list of all values that may # be used for this compiler option when building a configuration. all_cc_options_dict = { - 'O' : ['-O0', '-O2', '-Os'], - 'LTO' : ['-flto', '-fno-lto'], - 'SSP' : ['-fno-stack-protector', '-fstack-protector'], + 'O': ['-O0', '-O2', '-Os'], + 'LTO': ['-flto', '-fno-lto'], + 'SSP': ['-fno-stack-protector', '-fstack-protector'], } # Dictionaries of options. @@ -87,22 +103,22 @@ all_cc_options_dict = { # option when building a configuration. small_options_dict = { - 'CONFIG_CC_OPTIONS' : gen_cc_options_list(all_cc_options_dict), - 'CONFIG_SMP' : ['y', 'n'], - 'CONFIG_MAX_CPUS' : ['1', '128'], - 'CONFIG_ASSERT' : ['y', 'n'], + 'CONFIG_CC_OPTIONS': gen_cc_options_list(all_cc_options_dict), + 'CONFIG_SMP': ['y', 'n'], + 'CONFIG_MAX_CPUS': ['1', '128'], + 'CONFIG_ASSERT': ['y', 'n'], } large_options_dict = dict(small_options_dict) large_options_dict.update({ - 'CONFIG_CC_EXE' : ['gcc', 'clang'], - 'CONFIG_64BITS' : ['y', 'n'], - 'CONFIG_X86_PAE' : ['y', 'n'], - 'CONFIG_MUTEX_ADAPTIVE' : ['y', 'n'], - 'CONFIG_MUTEX_PI' : ['y', 'n'], - 'CONFIG_MUTEX_PLAIN' : ['y', 'n'], - 'CONFIG_SHELL' : ['y', 'n'], - 'CONFIG_THREAD_STACK_GUARD' : ['y', 'n'], + 'CONFIG_CC_EXE': ['gcc', 'clang'], + 'CONFIG_64BITS': ['y', 'n'], + 'CONFIG_X86_PAE': ['y', 'n'], + 'CONFIG_MUTEX_ADAPTIVE': ['y', 'n'], + 'CONFIG_MUTEX_PI': ['y', 'n'], + 'CONFIG_MUTEX_PLAIN': ['y', 'n'], + 'CONFIG_SHELL': ['y', 'n'], + 'CONFIG_THREAD_STACK_GUARD': ['y', 'n'], }) test_list = [ @@ -120,12 +136,12 @@ test_list = [ test_options_dict = dict(small_options_dict) for test in test_list: - test_options_dict.update({test : ['y', 'n']}) + test_options_dict.update({test: ['y', 'n']}) all_options_sets = { - 'small' : small_options_dict, - 'large' : large_options_dict, - 'test' : test_options_dict, + 'small': small_options_dict, + 'large': large_options_dict, + 'test': test_options_dict, } # Filters. @@ -149,51 +165,55 @@ passing_filters_list += gen_exclusive_boolean_filters_list(test_list, blocking_filters_list = [ # XXX Clang currently cannot build the kernel with LTO. { - 'CONFIG_CC_EXE' : [True, 'clang'], - 'CONFIG_CC_OPTIONS' : [True, re.compile('-flto')], + 'CONFIG_CC_EXE': [True, 'clang'], + 'CONFIG_CC_OPTIONS': [True, re.compile('-flto')], }, { - 'CONFIG_SMP' : [True, 'y'], - 'CONFIG_MAX_CPUS' : [True, '1'], + 'CONFIG_SMP': [True, 'y'], + 'CONFIG_MAX_CPUS': [True, '1'], }, { - 'CONFIG_SMP' : [True, 'n'], - 'CONFIG_MAX_CPUS' : [False, '1'], + 'CONFIG_SMP': [True, 'n'], + 'CONFIG_MAX_CPUS': [False, '1'], }, { - 'CONFIG_64BITS' : [True, 'y'], - 'CONFIG_X86_PAE' : [True, 'y'], + 'CONFIG_64BITS': [True, 'y'], + 'CONFIG_X86_PAE': [True, 'y'], }, ] + def gen_config_line(config_entry): name, value = config_entry return '%s=%s\n' % (name, quote_if_needed(value)) + def gen_config_content(config_dict): return map(gen_config_line, config_dict.items()) + def test_config_run(command, check, buildlog): buildlog.writelines(['$ %s\n' % command]) buildlog.flush() if check: - return subprocess.check_call(command.split(), stdout = buildlog, - stderr = subprocess.STDOUT) + return subprocess.check_call(command.split(), stdout=buildlog, + stderr=subprocess.STDOUT) else: - return subprocess.call(command.split(), stdout = buildlog, - stderr = subprocess.STDOUT) + return subprocess.call(command.split(), stdout=buildlog, + stderr=subprocess.STDOUT) + -# This function is run in multiprocessing.Pool workers. def test_config(args): + 'This function is run in multiprocessing.Pool workers.' topbuilddir, config_dict = args srctree = os.path.abspath(os.getcwd()) - buildtree = tempfile.mkdtemp(dir = topbuilddir) + buildtree = tempfile.mkdtemp(dir=topbuilddir) os.chdir(buildtree) buildlog = open('build.log', 'w') - f = open('.testconfig', 'w') - f.writelines(gen_config_content(config_dict)) - f.close() + config_file = open('.testconfig', 'w') + config_file.writelines(gen_config_content(config_dict)) + config_file.close() try: test_config_run('%s/tools/kconfig/merge_config.sh' @@ -217,10 +237,11 @@ def test_config(args): return [retval, buildtree] -# Return true if a filter completely matches a configuration. + def check_filter(config_dict, filter_dict): + 'Return true if a filter completely matches a configuration.' for name, value in filter_dict.items(): - if not name in config_dict: + if name not in config_dict: return False if isinstance(value[1], str): @@ -232,13 +253,15 @@ def check_filter(config_dict, filter_dict): return True + def check_filter_relevant(config_dict, filter_dict): - for name, value in filter_dict.items(): + for name, _ in filter_dict.items(): if name in config_dict: return True return False + def check_filters_list_relevant(config_dict, filters_list): for filter_dict in filters_list: if check_filter_relevant(config_dict, filter_dict): @@ -246,12 +269,15 @@ def check_filters_list_relevant(config_dict, filters_list): return False -# Return true if a configuration doesn't pass any given filter. -# -# If the given filters list is irrelevant, i.e. it applies to none of -# the options in the given configuration, the filters are considered -# to match. + def check_passing_filters(args): + ''' + If the given filters list is irrelevant, i.e. it applies to none of + the options in the given configuration, the filters are considered + to match. + + @return true if a configuration doesn't pass any given filter. + ''' config_dict, filters_list = args if not check_filters_list_relevant(config_dict, filters_list): @@ -263,8 +289,9 @@ def check_passing_filters(args): return False -# Return true if a configuration passes all the given filters. + def check_blocking_filters(args): + 'Return true if a configuration passes all the given filters.' config_dict, filters_list = args for filter_dict in filters_list: @@ -273,29 +300,31 @@ def check_blocking_filters(args): return True -def filter_configs_list(configs_list, passing_filters_list, - blocking_filters_list): - configs_and_filters = map(lambda x: (x, passing_filters_list), - configs_list) - configs_list = map(lambda x: x[0], filter(check_passing_filters, - configs_and_filters)) - configs_and_filters = map(lambda x: (x, blocking_filters_list), - configs_list) - configs_list = map(lambda x: x[0], filter(check_blocking_filters, - configs_and_filters)) + +def filter_configs_list(configs_list, passing, blocking): + configs_and_filters = [(x, passing) for x in configs_list] + configs_list = [x[0] for x in filter(check_passing_filters, + configs_and_filters)] + configs_and_filters = [(x, blocking) for x in configs_list] + configs_list = [x[0] for x in filter(check_blocking_filters, + configs_and_filters)] return list(configs_list) + def find_options_dict(options_sets, name): if name not in options_sets: return None return options_sets[name] + def print_set(name, options_dict): print(name) - map(lambda x: print_fn(' ' + x), sorted(iter(options_dict))) + for opt in sorted(iter(options_dict)): + print_fn(' ' + opt) -class BuildConfigListSetsAction(argparse.Action): + +class BuildConfigListSetsAction(Action): def __init__(self, nargs=0, **kwargs): if nargs != 0: raise ValueError("nargs not allowed") @@ -303,12 +332,14 @@ class BuildConfigListSetsAction(argparse.Action): super(BuildConfigListSetsAction, self).__init__(nargs=nargs, **kwargs) def __call__(self, parser, namespace, values, option_string=None): - map(print_set, all_options_sets.iterkeys(), + map(print_set, all_options_sets.keys(), all_options_sets.values()) sys.exit(0) + def main(): - parser = argparse.ArgumentParser(description='Configuration builder') + parser = ArgumentParser(description=__doc__, + formatter_class=RawDescriptionHelpFormatter) parser.add_argument('-s', '--set', default='small', help='select a set of options (default=small)') parser.add_argument('-l', '--list-sets', action=BuildConfigListSetsAction, @@ -319,7 +350,7 @@ def main(): if not options_dict: print('error: invalid set') - sys.exit(2); + sys.exit(2) print('set: {}'.format(args.set)) configs_list = filter_configs_list(gen_configs_list(options_dict), @@ -331,11 +362,11 @@ def main(): # This tool performs out-of-tree builds and requires a clean source tree print('cleaning source tree...') subprocess.check_call(['make', 'distclean']) - topbuilddir = os.path.abspath(tempfile.mkdtemp(prefix = 'build', dir = '.')) + topbuilddir = os.path.abspath(tempfile.mkdtemp(prefix='build', dir='.')) print('top build directory: {}'.format(topbuilddir)) pool = multiprocessing.Pool() - worker_args = map(lambda x: (topbuilddir, x), configs_list) + worker_args = [(topbuilddir, x) for x in configs_list] try: results = pool.map(test_config, worker_args) @@ -345,10 +376,9 @@ def main(): shutil.rmtree(topbuilddir) raise - failures = list(filter(lambda x: x[0] != 0, results)) - map(lambda buildtree: print_fn('failed: %s/.config (%s/build.log)' - % (buildtree, buildtree)), - [buildtree for retval, buildtree in failures]) + failures = [x for x in results if x[0] != 0] + for _, buildtree in failures: + print_fn('failed: {0}/.config ({0}/build.log)'.format(buildtree)) print('passed: {:d}'.format(nr_configs - len(failures))) print('failed: {:d}'.format(len(failures))) @@ -357,5 +387,6 @@ def main(): finally: sys.exit(len(failures) != 0) + if __name__ == '__main__': main() |