[PATCH 00/24] qconfig: Tidy up main() and add a small feature

This series improves the code a little by reducing the size of the main() function. It also allows searching for CONFIG values.
Simon Glass (24): qconfig: Fix pylint error in read_database() qconfig: Drop the try_expand() function qconfig: Make KconfigScanner a function qconfig: Tidy up some pylint warnings qconfig: Correct format string in do_imply_config() qconfig: Rename the doc link qconfig: Move arg parsing into a separate function qconfig: Move arg checking a little higher qconfig: Move arg checking to the top of main() qconfig: Move getting the colour to where it is needed qconfig: Move checking directory to the top qconfig: Move converting config args to the top qconfig: Move testing into a separate function qconfig: Add a return value to do_scan_source() qconfig: Move imply into a separate function qconfig: Add a return value to do_find_config() qconfig: Move all move_config code into move_config() qconfig: Move commit code into a separate function qconfig: Move progress output into the class qconfig: Move the last two operations into their own functions qconfig: Use the Color object in Progress qconfig: Drop col argument from Slots() qconfig: Move operation check into parse_args() qconfig: Allow searching for CONFIG values
doc/develop/qconfig.rst | 14 ++ tools/qconfig.py | 403 ++++++++++++++++++++++++---------------- 2 files changed, 256 insertions(+), 161 deletions(-)

Fix this error by initing the variable before the loop:
tools/qconfig.py:880:22: E0606: Possibly using variable 'defconfig' before assignment (possibly-used-before-assignment)
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 1 + 1 file changed, 1 insertion(+)
diff --git a/tools/qconfig.py b/tools/qconfig.py index 04118d942da..2492b37444a 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -873,6 +873,7 @@ def read_database(): all_defconfigs = set()
defconfig_db = collections.defaultdict(set) + defconfig = None for line in read_file(CONFIG_DATABASE): line = line.rstrip() if not line: # Separator between defconfigs

Fix this error by initing the variable before the loop:
tools/qconfig.py:880:22: E0606: Possibly using variable 'defconfig' before assignment (possibly-used-before-assignment)
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 1 + 1 file changed, 1 insertion(+)
Applied to u-boot-dm, thanks!

This is not used anymore, so drop it.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 21 --------------------- 1 file changed, 21 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index 2492b37444a..7d3989c7c3e 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -29,7 +29,6 @@ import threading import time import unittest
-import asteval from buildman import bsettings from buildman import kconfiglib from buildman import toolchain @@ -216,26 +215,6 @@ def read_file(fname, as_lines=True, skip_unicode=False): print(f"Failed on file '{fname}: {exc}") return None
-def try_expand(line): - """If value looks like an expression, try expanding it - Otherwise just return the existing value - """ - if line.find('=') == -1: - return line - - try: - aeval = asteval.Interpreter( usersyms=SIZES, minimal=True ) - cfg, val = re.split("=", line) - val= val.strip('"') - if re.search(r'[*+-/]|<<|SZ_+|(([^)]+))', val): - newval = hex(aeval(val)) - print(f'\tExpanded expression {val} to {newval}') - return cfg+'='+newval - except: - print(f'\tFailed to expand expression in {line}') - - return line -
### classes ### class Progress:

This is not used anymore, so drop it.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 21 --------------------- 1 file changed, 21 deletions(-)
Applied to u-boot-dm, thanks!

This doesn't have any methods so is not good as a class. Make it a function instead, to keep pylint happy.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index 7d3989c7c3e..a11ed5303d0 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -254,17 +254,18 @@ class Progress: sys.stdout.flush()
-class KconfigScanner: - """Kconfig scanner.""" +def scan_kconfig(): + """Scan all the Kconfig files and create a Config object
- def __init__(self): - """Scan all the Kconfig files and create a Config object.""" - # Define environment variables referenced from Kconfig - os.environ['srctree'] = os.getcwd() - os.environ['UBOOTVERSION'] = 'dummy' - os.environ['KCONFIG_OBJDIR'] = '' - os.environ['CC'] = 'gcc' - self.conf = kconfiglib.Kconfig() + Returns: + Kconfig object + """ + # Define environment variables referenced from Kconfig + os.environ['srctree'] = os.getcwd() + os.environ['UBOOTVERSION'] = 'dummy' + os.environ['KCONFIG_OBJDIR'] = '' + os.environ['CC'] = 'gcc' + return kconfiglib.Kconfig()
class KconfigParser: @@ -912,7 +913,7 @@ def do_imply_config(config_list, add_imply, imply_flags, skip_added, config - a CONFIG_XXX options (a string, e.g. 'CONFIG_CMD_EEPROM') defconfig - a defconfig file (a string, e.g. 'configs/snow_defconfig') """ - kconf = KconfigScanner().conf if check_kconfig else None + kconf = scan_kconfig() if check_kconfig else None if add_imply and add_imply != 'all': add_imply = add_imply.split(',')
@@ -1342,7 +1343,7 @@ def do_scan_source(path, do_update):
print('Scanning Kconfig') - kconf = KconfigScanner().conf + kconf = scan_kconfig() print(f'Scanning source in {path}') args = ['git', 'grep', '-E', r'IS_ENABLED|\bCONFIG'] with subprocess.Popen(args, stdout=subprocess.PIPE) as proc:

This doesn't have any methods so is not good as a class. Make it a function instead, to keep pylint happy.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-)
Applied to u-boot-dm, thanks!

Reduce the number of warnings in this file a little bit.
Add my own name to the copyright message.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index a11ed5303d0..4f1ad2703c7 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -1,13 +1,12 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: GPL-2.0+ -# -# Author: Masahiro Yamada yamada.masahiro@socionext.com -#
-""" -Build and query a Kconfig database for boards. +"""Build and query a Kconfig database for boards.
See doc/develop/moveconfig.rst for documentation. + +Author: Masahiro Yamada yamada.masahiro@socionext.com +Author: Simon Glass sjg@chromium.org """
from argparse import ArgumentParser @@ -268,8 +267,8 @@ def scan_kconfig(): return kconfiglib.Kconfig()
+# pylint: disable=R0903 class KconfigParser: - """A parser of .config and include/autoconf.mk."""
re_arch = re.compile(r'CONFIG_SYS_ARCH="(.*)"') @@ -481,6 +480,7 @@ class Slot:
cmd = list(self.make_cmd) cmd.append(self.defconfig) + # pylint: disable=R1732 self.proc = subprocess.Popen(cmd, stdout=self.devnull, stderr=subprocess.PIPE, cwd=self.current_src_dir) @@ -503,6 +503,7 @@ class Slot: cmd = list(self.make_cmd) cmd.append('KCONFIG_IGNORE_DUPLICATES=1') cmd.append(AUTO_CONF_PATH) + # pylint: disable=R1732 self.proc = subprocess.Popen(cmd, stdout=self.devnull, env=env, stderr=subprocess.PIPE, cwd=self.current_src_dir) @@ -526,6 +527,7 @@ class Slot:
cmd = list(self.make_cmd) cmd.append('savedefconfig') + # pylint: disable=R1732 self.proc = subprocess.Popen(cmd, stdout=self.devnull, stderr=subprocess.PIPE) self.state = STATE_SAVEDEFCONFIG @@ -752,7 +754,7 @@ def find_kconfig_rules(kconf, config, imply_config): return sym return None
-def check_imply_rule(kconf, config, imply_config): +def check_imply_rule(kconf, imply_config): """Check if we can add an 'imply' option
This finds imply_config in the Kconfig and looks to see if it is possible @@ -760,7 +762,6 @@ def check_imply_rule(kconf, config, imply_config):
Args: kconf (Kconfiglib.Kconfig): Kconfig object - config (str): Name of config to check (without CONFIG_ prefix) imply_config (str): Implying config (without CONFIG_ prefix) which may or may not have an 'imply' for 'config')
@@ -1032,7 +1033,7 @@ def do_imply_config(config_list, add_imply, imply_flags, skip_added, if add_imply and (add_imply == 'all' or iconfig in add_imply): fname, linenum, kconfig_info = (check_imply_rule(kconf, - config[CONFIG_LEN:], iconfig[CONFIG_LEN:])) + iconfig[CONFIG_LEN:])) if fname: add_list[fname].append(linenum)
@@ -1136,7 +1137,16 @@ RE_C_CONFIGS = re.compile(r'CONFIG_([A-Za-z0-9_]*)') RE_CONFIG_IS = re.compile(r'CONFIG_IS_ENABLED(([A-Za-z0-9_]*))')
class ConfigUse: + """Tracks whether a config relates to SPL or not""" def __init__(self, cfg, is_spl, fname, rest): + """Set up a new ConfigUse + + Args: + cfg (str): CONFIG option, without any CONFIG_ or SPL_ prefix + is_spl (bool): True if this option relates to SPL + fname (str): Makefile filename where the CONFIG option was found + rest (str): Line of the Makefile + """ self.cfg = cfg self.is_spl = is_spl self.fname = fname @@ -1444,6 +1454,7 @@ def do_scan_source(path, do_update):
def main(): + """Main program""" try: cpu_count = multiprocessing.cpu_count() except NotImplementedError: @@ -1569,8 +1580,8 @@ doc/develop/moveconfig.rst for documentation.''' if args.commit: subprocess.call(['git', 'add', '-u']) if configs: - msg = 'Convert %s %sto Kconfig' % (configs[0], - 'et al ' if len(configs) > 1 else '') + part = 'et al ' if len(configs) > 1 else '' + msg = f'Convert {configs[0]} {part}to Kconfig' msg += ('\n\nThis converts the following to Kconfig:\n %s\n' % '\n '.join(configs)) else:

Reduce the number of warnings in this file a little bit.
Add my own name to the copyright message.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-)
Applied to u-boot-dm, thanks!

One of the strings was converted incorrectly. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org Fixes: 1bd43060b3e ("moveconfig: Use f strings where possible") ---
tools/qconfig.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index 4f1ad2703c7..8a2384d895b 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -1038,8 +1038,8 @@ def do_imply_config(config_list, add_imply, imply_flags, skip_added, add_list[fname].append(linenum)
if show and kconfig_info != 'skip': - print(f'{num_common:5d} : ' - f'{iconfig.ljust(30):-30s}{kconfig_info:-25s} {missing_str}') + print(f'{num_common:5} : ' + f'{iconfig.ljust(30)}{kconfig_info.ljust(25)} {missing_str}')
# Having collected a list of things to add, now we add them. We process # each file from the largest line number to the smallest so that

One of the strings was converted incorrectly. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org Fixes: 1bd43060b3e ("moveconfig: Use f strings where possible") ---
tools/qconfig.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
Applied to u-boot-dm, thanks!

This was missed during the renaming of the tool. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org Fixes: ea4d6dead37 ("moveconfig: Rename the tool to qconfig") ---
tools/qconfig.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index 8a2384d895b..07d78387465 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -3,7 +3,7 @@
"""Build and query a Kconfig database for boards.
-See doc/develop/moveconfig.rst for documentation. +See doc/develop/qconfig.rst for documentation.
Author: Masahiro Yamada yamada.masahiro@socionext.com Author: Simon Glass sjg@chromium.org

This was missed during the renaming of the tool. Fix it.
Signed-off-by: Simon Glass sjg@chromium.org Fixes: ea4d6dead37 ("moveconfig: Rename the tool to qconfig") ---
tools/qconfig.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Applied to u-boot-dm, thanks!

Reduce the size of main() by putting this code into its own function. For now the parser object needs to be returned too.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index 07d78387465..d8f0a716fe9 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -1453,8 +1453,14 @@ def do_scan_source(path, do_update): print(item, file=out)
-def main(): - """Main program""" +def parse_args(): + """Parse the program arguments + + Returns: + tuple: + argparse.ArgumentParser: parser + argparse.Namespace: Parsed arguments + """ try: cpu_count = multiprocessing.cpu_count() except NotImplementedError: @@ -1512,8 +1518,12 @@ doc/develop/moveconfig.rst for documentation.''' help='show any build errors as boards are built') parser.add_argument('configs', nargs='*')
- args = parser.parse_args() + return parser, parser.parse_args() +
+def main(): + """Main program""" + parser, args = parse_args() if args.test: sys.argv = [sys.argv[0]] fail, _ = doctest.testmod()

Reduce the size of main() by putting this code into its own function. For now the parser object needs to be returned too.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
Applied to u-boot-dm, thanks!

Check for scan_source as one of the possible operations for this tool, moving the check above the scan_source implementation.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index d8f0a716fe9..6d263ce30db 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -1534,14 +1534,15 @@ def main(): col = terminal.Color(terminal.COLOR_NEVER if args.nocolour else terminal.COLOR_IF_TERMINAL)
+ if not any((args.force_sync, args.build_db, args.imply, args.find, + args.scan_source)): + parser.print_usage() + sys.exit(1) + if args.scan_source: do_scan_source(os.getcwd(), args.update) return 0
- if not any((args.force_sync, args.build_db, args.imply, args.find)): - parser.print_usage() - sys.exit(1) - # prefix the option name with CONFIG_ if missing configs = [prefix_config(cfg) for cfg in args.configs]

Check for scan_source as one of the possible operations for this tool, moving the check above the scan_source implementation.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
Applied to u-boot-dm, thanks!

Check for 'test' as one of the possible operations for this tool, moving the check above the implementation.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index 6d263ce30db..9052aedf57d 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -1524,6 +1524,10 @@ doc/develop/moveconfig.rst for documentation.''' def main(): """Main program""" parser, args = parse_args() + if not any((args.force_sync, args.build_db, args.imply, args.find, + args.scan_source, args.test)): + parser.print_usage() + sys.exit(1) if args.test: sys.argv = [sys.argv[0]] fail, _ = doctest.testmod() @@ -1534,11 +1538,6 @@ def main(): col = terminal.Color(terminal.COLOR_NEVER if args.nocolour else terminal.COLOR_IF_TERMINAL)
- if not any((args.force_sync, args.build_db, args.imply, args.find, - args.scan_source)): - parser.print_usage() - sys.exit(1) - if args.scan_source: do_scan_source(os.getcwd(), args.update) return 0

Check for 'test' as one of the possible operations for this tool, moving the check above the implementation.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
Applied to u-boot-dm, thanks!

Move this assignment down to just above where it is needed.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index 9052aedf57d..5d6e468d1d8 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -1535,9 +1535,6 @@ def main(): return 1 unittest.main()
- col = terminal.Color(terminal.COLOR_NEVER if args.nocolour - else terminal.COLOR_IF_TERMINAL) - if args.scan_source: do_scan_source(os.getcwd(), args.update) return 0 @@ -1584,6 +1581,9 @@ def main(): toolchains = toolchain.Toolchains() toolchains.GetSettings() toolchains.Scan(verbose=False) + + col = terminal.Color(terminal.COLOR_NEVER if args.nocolour + else terminal.COLOR_IF_TERMINAL) progress = move_config(toolchains, args, db_queue, col) db_queue.join()

Move this assignment down to just above where it is needed.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
Applied to u-boot-dm, thanks!

Move this check to the top, so it happens always. The tool should be run from the U-Boot source directory.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index 5d6e468d1d8..832e524c25c 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -1528,6 +1528,9 @@ def main(): args.scan_source, args.test)): parser.print_usage() sys.exit(1) + + check_top_directory() + if args.test: sys.argv = [sys.argv[0]] fail, _ = doctest.testmod() @@ -1542,8 +1545,6 @@ def main(): # prefix the option name with CONFIG_ if missing configs = [prefix_config(cfg) for cfg in args.configs]
- check_top_directory() - if args.imply: imply_flags = 0 if args.imply_flags == 'all':

Move this check to the top, so it happens always. The tool should be run from the U-Boot source directory.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
Applied to u-boot-dm, thanks!

Move this check to the top, so it happens always. There is no harm to doing this earlier and it separates the setup from actual program logic.
Update the arg rather than adding a new variable, with the new variable only created when moving or building, since it is used more heavily.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index 832e524c25c..a33fb2aa22b 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -1531,6 +1531,9 @@ def main():
check_top_directory()
+ # prefix the option name with CONFIG_ if missing + args.configs = [prefix_config(cfg) for cfg in args.configs] + if args.test: sys.argv = [sys.argv[0]] fail, _ = doctest.testmod() @@ -1542,9 +1545,6 @@ def main(): do_scan_source(os.getcwd(), args.update) return 0
- # prefix the option name with CONFIG_ if missing - configs = [prefix_config(cfg) for cfg in args.configs] - if args.imply: imply_flags = 0 if args.imply_flags == 'all': @@ -1563,11 +1563,11 @@ def main(): sys.exit(1) imply_flags |= IMPLY_FLAGS[flag][0]
- do_imply_config(configs, args.add_imply, imply_flags, args.skip_added) + do_imply_config(args.configs, args.add_imply, imply_flags, args.skip_added) return 0
if args.find: - do_find_config(configs) + do_find_config(args.configs) return 0
# We are either building the database or forcing a sync of defconfigs @@ -1588,6 +1588,7 @@ def main(): progress = move_config(toolchains, args, db_queue, col) db_queue.join()
+ configs = args.configs if args.commit: subprocess.call(['git', 'add', '-u']) if configs:

Move this check to the top, so it happens always. There is no harm to doing this earlier and it separates the setup from actual program logic.
Update the arg rather than adding a new variable, with the new variable only created when moving or building, since it is used more heavily.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
Applied to u-boot-dm, thanks!

Reduce the size of main() by putting this code into its own function.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index a33fb2aa22b..0bdabccba07 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -1521,6 +1521,16 @@ doc/develop/moveconfig.rst for documentation.''' return parser, parser.parse_args()
+def do_tests(): + """Run doctests and unit tests (so far there are no unit tests)""" + sys.argv = [sys.argv[0]] + fail, _ = doctest.testmod() + if fail: + return 1 + unittest.main() + return 0 + + def main(): """Main program""" parser, args = parse_args() @@ -1535,11 +1545,7 @@ def main(): args.configs = [prefix_config(cfg) for cfg in args.configs]
if args.test: - sys.argv = [sys.argv[0]] - fail, _ = doctest.testmod() - if fail: - return 1 - unittest.main() + return do_tests()
if args.scan_source: do_scan_source(os.getcwd(), args.update)

Reduce the size of main() by putting this code into its own function.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-)
Applied to u-boot-dm, thanks!

Return an exit code so we can use this function like do_tests(). Refactor the caller to handle this.
Reduce the size of main() by putting this code into its own function.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index 0bdabccba07..4365d8d75db 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -1451,6 +1451,7 @@ def do_scan_source(path, do_update): file=out) for item in sorted(proper_not_found): print(item, file=out) + return 0
def parse_args(): @@ -1546,10 +1547,8 @@ def main():
if args.test: return do_tests() - if args.scan_source: - do_scan_source(os.getcwd(), args.update) - return 0 + return do_scan_source(os.getcwd(), args.update)
if args.imply: imply_flags = 0

Return an exit code so we can use this function like do_tests(). Refactor the caller to handle this.
Reduce the size of main() by putting this code into its own function.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
Applied to u-boot-dm, thanks!

Reduce the size of main() by putting this code into its own function, with the usage message staying in main().
Tidy up the comments for do_imply_config() while we are here.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 66 ++++++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 27 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index 4365d8d75db..8cba6896667 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -896,15 +896,15 @@ def do_imply_config(config_list, add_imply, imply_flags, skip_added, - If imply_defconfigs contains anything not in defconfigs then this config does not imply the target config
- Params: - config_list: List of CONFIG options to check (each a string) - add_imply: Automatically add an 'imply' for each config. - imply_flags: Flags which control which implying configs are allowed + Args: + config_list (list of str): List of CONFIG options to check + add_imply (bool): Automatically add an 'imply' for each config. + imply_flags (int): Flags which control which implying configs are allowed (IMPLY_...) - skip_added: Don't show options which already have an imply added. - check_kconfig: Check if implied symbols already have an 'imply' or + skip_added (bool): Don't show options which already have an imply added. + check_kconfig (bool): Check if implied symbols already have an 'imply' or 'select' for the target config, and show this information if so. - find_superset: True to look for configs which are a superset of those + find_superset (bool): True to look for configs which are a superset of those already found. So for example if CONFIG_EXYNOS5 implies an option, but CONFIG_EXYNOS covers a larger set of defconfigs and also implies that option, this will drop the former in favour of the @@ -1522,6 +1522,35 @@ doc/develop/moveconfig.rst for documentation.''' return parser, parser.parse_args()
+def imply(args): + """Handle checking for flags which imply others + + Args: + args (argparse.Namespace): Program arguments + + Returns: + int: exit code (0 for success) + """ + imply_flags = 0 + if args.imply_flags == 'all': + imply_flags = -1 + + elif args.imply_flags: + for flag in args.imply_flags.split(','): + bad = flag not in IMPLY_FLAGS + if bad: + print(f"Invalid flag '{flag}'") + if flag == 'help' or bad: + print("Imply flags: (separate with ',')") + for name, info in IMPLY_FLAGS.items(): + print(f' {name:-15s}: {info[1]}') + return 1 + imply_flags |= IMPLY_FLAGS[flag][0] + + do_imply_config(args.configs, args.add_imply, imply_flags, args.skip_added) + return 0 + + def do_tests(): """Run doctests and unit tests (so far there are no unit tests)""" sys.argv = [sys.argv[0]] @@ -1549,28 +1578,11 @@ def main(): return do_tests() if args.scan_source: return do_scan_source(os.getcwd(), args.update) - if args.imply: - imply_flags = 0 - if args.imply_flags == 'all': - imply_flags = -1 - - elif args.imply_flags: - for flag in args.imply_flags.split(','): - bad = flag not in IMPLY_FLAGS - if bad: - print(f"Invalid flag '{flag}'") - if flag == 'help' or bad: - print("Imply flags: (separate with ',')") - for name, info in IMPLY_FLAGS.items(): - print(f' {name:-15s}: {info[1]}') - parser.print_usage() - sys.exit(1) - imply_flags |= IMPLY_FLAGS[flag][0] - - do_imply_config(args.configs, args.add_imply, imply_flags, args.skip_added) + if imply(args): + parser.print_usage() + sys.exit(1) return 0 - if args.find: do_find_config(args.configs) return 0

Reduce the size of main() by putting this code into its own function, with the usage message staying in main().
Tidy up the comments for do_imply_config() while we are here.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 66 ++++++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 27 deletions(-)
Applied to u-boot-dm, thanks!

Return an exit code so we can use this function like do_tests(). Refactor the caller to handle this.
Reduce the size of main() by putting this code into its own function.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index 8cba6896667..b1487928613 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -1072,11 +1072,14 @@ def defconfig_matches(configs, re_match): def do_find_config(config_list): """Find boards with a given combination of CONFIGs
- Params: - config_list: List of CONFIG options to check (each a regex consisting - of a config option, with or without a CONFIG_ prefix. If an option - is preceded by a tilde (~) then it must be false, otherwise it must - be true) + Args: + config_list (list of str): List of CONFIG options to check (each a regex + consisting of a config option, with or without a CONFIG_ prefix. If + an option is preceded by a tilde (~) then it must be false, + otherwise it must be true) + + Returns: + int: exit code (0 for success) """ _, all_defconfigs, config_db, _ = read_database()
@@ -1104,6 +1107,7 @@ def do_find_config(config_list): out.add(defc) print(f'{len(out)} matches') print(' '.join(item.split('_defconfig')[0] for item in out)) + return 0
def prefix_config(cfg): @@ -1584,8 +1588,7 @@ def main(): sys.exit(1) return 0 if args.find: - do_find_config(args.configs) - return 0 + return do_find_config(args.configs)
# We are either building the database or forcing a sync of defconfigs config_db = {}

Return an exit code so we can use this function like do_tests(). Refactor the caller to handle this.
Reduce the size of main() by putting this code into its own function.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-)
Applied to u-boot-dm, thanks!

Move the setup and completion code into the move_config() function so it is all in one place.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index b1487928613..74d7d1bd175 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -693,18 +693,36 @@ class ReferenceSource:
return self.src_dir
-def move_config(toolchains, args, db_queue, col): +def move_config(args, col): """Build database or sync config options to defconfig files.
Args: - toolchains (Toolchains): Toolchains to use args (Namespace): Program arguments - db_queue (Queue): Queue for database updates col (terminal.Color): Colour object
Returns: - Progress: Progress indicator + tuple: + config_db (dict of configs for each defconfig): + key: defconfig name, e.g. "MPC8548CDS_legacy_defconfig" + value: dict: + key: CONFIG option + value: Value of option + Progress: Progress indicator """ + config_db = {} + db_queue = queue.Queue() + dbt = DatabaseThread(config_db, db_queue) + dbt.daemon = True + dbt.start() + + check_clean_directory() + bsettings.setup('') + + # Get toolchains to use + toolchains = toolchain.Toolchains() + toolchains.GetSettings() + toolchains.Scan(verbose=False) + if args.git_ref: reference_src = ReferenceSource(args.git_ref) reference_src_dir = reference_src.get_dir() @@ -733,7 +751,8 @@ def move_config(toolchains, args, db_queue, col): time.sleep(SLEEP_TIME)
slots.write_failed_boards() - return progress + db_queue.join() + return config_db, progress
def find_kconfig_rules(kconf, config, imply_config): """Check whether a config has a 'select' or 'imply' keyword @@ -1590,23 +1609,9 @@ def main(): if args.find: return do_find_config(args.configs)
- # We are either building the database or forcing a sync of defconfigs - config_db = {} - db_queue = queue.Queue() - dbt = DatabaseThread(config_db, db_queue) - dbt.daemon = True - dbt.start() - - check_clean_directory() - bsettings.setup('') - toolchains = toolchain.Toolchains() - toolchains.GetSettings() - toolchains.Scan(verbose=False) - col = terminal.Color(terminal.COLOR_NEVER if args.nocolour else terminal.COLOR_IF_TERMINAL) - progress = move_config(toolchains, args, db_queue, col) - db_queue.join() + config_db, progress = move_config(args, col)
configs = args.configs if args.commit:

Move the setup and completion code into the move_config() function so it is all in one place.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 45 +++++++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 20 deletions(-)
Applied to u-boot-dm, thanks!

Reduce the size of main() by putting this code into its own function.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index 74d7d1bd175..dc5b7691064 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -1574,6 +1574,24 @@ def imply(args): return 0
+def add_commit(configs): + """Add a commit indicating which CONFIG options were converted + + Args: + configs (list of str) List of CONFIG_... options to process + """ + subprocess.call(['git', 'add', '-u']) + if configs: + part = 'et al ' if len(configs) > 1 else '' + msg = f'Convert {configs[0]} {part}to Kconfig' + msg += ('\n\nThis converts the following to Kconfig:\n %s\n' % + '\n '.join(configs)) + else: + msg = 'configs: Resync with savedefconfig' + msg += '\n\nRsync all defconfig files using moveconfig.py' + subprocess.call(['git', 'commit', '-s', '-m', msg]) + + def do_tests(): """Run doctests and unit tests (so far there are no unit tests)""" sys.argv = [sys.argv[0]] @@ -1613,22 +1631,13 @@ def main(): else terminal.COLOR_IF_TERMINAL) config_db, progress = move_config(args, col)
- configs = args.configs if args.commit: - subprocess.call(['git', 'add', '-u']) - if configs: - part = 'et al ' if len(configs) > 1 else '' - msg = f'Convert {configs[0]} {part}to Kconfig' - msg += ('\n\nThis converts the following to Kconfig:\n %s\n' % - '\n '.join(configs)) - else: - msg = 'configs: Resync with savedefconfig' - msg += '\n\nRsync all defconfig files using moveconfig.py' - subprocess.call(['git', 'commit', '-s', '-m', msg]) + add_commit(args.configs)
failed = progress.total - progress.good failure = f'{failed} failed, ' if failed else '' if args.build_db: + configs = args.configs with open(CONFIG_DATABASE, 'w', encoding='utf-8') as outf: for defconfig, configs in config_db.items(): outf.write(f'{defconfig}\n')

Reduce the size of main() by putting this code into its own function.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-)
Applied to u-boot-dm, thanks!

Rather than create these outputs separately, put them in the class so that the main program doesn't need to deal with them.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index dc5b7691064..405981938e5 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -217,20 +217,26 @@ def read_file(fname, as_lines=True, skip_unicode=False):
### classes ### class Progress: - """Progress Indicator"""
def __init__(self, col, total): """Create a new progress indicator.
Args: - color_enabled (bool): True for colour output + col (terminal.Color): Colour-output class total (int): A number of defconfig files to process. + + current (int): Number of boards processed so far + failed (int): Number of failed boards + failure_msg (str): Message indicating number of failures, '' if none """ self.col = col + self.total = total + self.current = 0 self.good = 0 - self.total = total + self.failed = None + self.failure_msg = None
def inc(self, success): """Increment the number of processed defconfig files. @@ -252,6 +258,11 @@ class Progress: print(f'{line} \r', end='') sys.stdout.flush()
+ def completed(self): + """Set up extra properties when completed""" + self.failed = self.total - self.good + self.failure_msg = f'{self.failed} failed, ' if self.failed else '' +
def scan_kconfig(): """Scan all the Kconfig files and create a Config object @@ -752,6 +763,7 @@ def move_config(args, col):
slots.write_failed_boards() db_queue.join() + progress.completed() return config_db, progress
def find_kconfig_rules(kconf, config, imply_config): @@ -1634,8 +1646,6 @@ def main(): if args.commit: add_commit(args.configs)
- failed = progress.total - progress.good - failure = f'{failed} failed, ' if failed else '' if args.build_db: configs = args.configs with open(CONFIG_DATABASE, 'w', encoding='utf-8') as outf: @@ -1645,11 +1655,11 @@ def main(): outf.write(f' {config}={configs[config]}\n') outf.write('\n') print(col.build( - col.RED if failed else col.GREEN, - f'{failure}{len(config_db)} boards written to {CONFIG_DATABASE}')) + col.RED if progress.failed else col.GREEN, + f'{progress.failure_msg}{len(config_db)} boards written to {CONFIG_DATABASE}')) else: - if failed: - print(col.build(col.RED, f'{failure}see {FAILED_LIST}', True)) + if progress.failed: + print(col.build(col.RED, f'{progress.failure_msg}see {FAILED_LIST}', True)) else: # Add enough spaces to overwrite the progress indicator print(col.build(

Rather than create these outputs separately, put them in the class so that the main program doesn't need to deal with them.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-)
Applied to u-boot-dm, thanks!

Put the summary and database-writing code into separate functions to reduce the size of main().
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 66 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 19 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index 405981938e5..ec59ef4ec71 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -1604,6 +1604,51 @@ def add_commit(configs): subprocess.call(['git', 'commit', '-s', '-m', msg])
+def write_db(config_db, col, progress): + """Write the database to a file + + Args: + config_db (dict of dict): configs for each defconfig + key: defconfig name, e.g. "MPC8548CDS_legacy_defconfig" + value: dict: + key: CONFIG option + value: Value of option + col (terminal.Color): Colour-output class + progress (Progress): Progress indicator. + + Returns: + int: exit code (0 for success) + """ + with open(CONFIG_DATABASE, 'w', encoding='utf-8') as outf: + for defconfig, configs in config_db.items(): + outf.write(f'{defconfig}\n') + for config in sorted(configs.keys()): + outf.write(f' {config}={configs[config]}\n') + outf.write('\n') + print(col.build( + col.RED if progress.failed else col.GREEN, + f'{progress.failure_msg}{len(config_db)} boards written to {CONFIG_DATABASE}')) + return 0 + + +def move_done(col, progress): + """Write a message indicating that the move is done + + Args: + col (terminal.Color): Colour-output class + progress (Progress): Progress indicator. + + Returns: + int: exit code (0 for success) + """ + if progress.failed: + print(col.build(col.RED, f'{progress.failure_msg}see {FAILED_LIST}', True)) + else: + # Add enough spaces to overwrite the progress indicator + print(col.build( + col.GREEN, f'{progress.total} processed ', bright=True)) + return 0 + def do_tests(): """Run doctests and unit tests (so far there are no unit tests)""" sys.argv = [sys.argv[0]] @@ -1647,25 +1692,8 @@ def main(): add_commit(args.configs)
if args.build_db: - configs = args.configs - with open(CONFIG_DATABASE, 'w', encoding='utf-8') as outf: - for defconfig, configs in config_db.items(): - outf.write(f'{defconfig}\n') - for config in sorted(configs.keys()): - outf.write(f' {config}={configs[config]}\n') - outf.write('\n') - print(col.build( - col.RED if progress.failed else col.GREEN, - f'{progress.failure_msg}{len(config_db)} boards written to {CONFIG_DATABASE}')) - else: - if progress.failed: - print(col.build(col.RED, f'{progress.failure_msg}see {FAILED_LIST}', True)) - else: - # Add enough spaces to overwrite the progress indicator - print(col.build( - col.GREEN, f'{progress.total} processed ', bright=True)) - - return 0 + return write_db(config_db, col, progress) + return move_done(col, progress)
if __name__ == '__main__':

Put the summary and database-writing code into separate functions to reduce the size of main().
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 66 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 19 deletions(-)
Applied to u-boot-dm, thanks!

Since the Progress class has the required object, use it from there instead of passing it around.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index ec59ef4ec71..c4171cf9076 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -704,12 +704,11 @@ class ReferenceSource:
return self.src_dir
-def move_config(args, col): +def move_config(args): """Build database or sync config options to defconfig files.
Args: args (Namespace): Program arguments - col (terminal.Color): Colour object
Returns: tuple: @@ -745,6 +744,8 @@ def move_config(args, col): else: defconfigs = get_all_defconfigs()
+ col = terminal.Color(terminal.COLOR_NEVER if args.nocolour + else terminal.COLOR_IF_TERMINAL) progress = Progress(col, len(defconfigs)) slots = Slots(toolchains, args, progress, reference_src_dir, db_queue, col)
@@ -1604,7 +1605,7 @@ def add_commit(configs): subprocess.call(['git', 'commit', '-s', '-m', msg])
-def write_db(config_db, col, progress): +def write_db(config_db, progress): """Write the database to a file
Args: @@ -1613,12 +1614,12 @@ def write_db(config_db, col, progress): value: dict: key: CONFIG option value: Value of option - col (terminal.Color): Colour-output class progress (Progress): Progress indicator.
Returns: int: exit code (0 for success) """ + col = progress.col with open(CONFIG_DATABASE, 'w', encoding='utf-8') as outf: for defconfig, configs in config_db.items(): outf.write(f'{defconfig}\n') @@ -1631,16 +1632,16 @@ def write_db(config_db, col, progress): return 0
-def move_done(col, progress): +def move_done(progress): """Write a message indicating that the move is done
Args: - col (terminal.Color): Colour-output class progress (Progress): Progress indicator.
Returns: int: exit code (0 for success) """ + col = progress.col if progress.failed: print(col.build(col.RED, f'{progress.failure_msg}see {FAILED_LIST}', True)) else: @@ -1684,16 +1685,14 @@ def main(): if args.find: return do_find_config(args.configs)
- col = terminal.Color(terminal.COLOR_NEVER if args.nocolour - else terminal.COLOR_IF_TERMINAL) - config_db, progress = move_config(args, col) + config_db, progress = move_config(args)
if args.commit: add_commit(args.configs)
if args.build_db: - return write_db(config_db, col, progress) - return move_done(col, progress) + return write_db(config_db, progress) + return move_done(progress)
if __name__ == '__main__':

Since the Progress class has the required object, use it from there instead of passing it around.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-)
Applied to u-boot-dm, thanks!

This is not needed since the progress indicator has the object. Use that instead.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index c4171cf9076..dd24e4b398b 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -364,7 +364,7 @@ class Slot: """
def __init__(self, toolchains, args, progress, devnull, make_cmd, - reference_src_dir, db_queue, col): + reference_src_dir, db_queue): """Create a new process slot.
Args: @@ -386,7 +386,7 @@ class Slot: self.make_cmd = (make_cmd, 'O=' + self.build_dir) self.reference_src_dir = reference_src_dir self.db_queue = db_queue - self.col = col + self.col = progress.col self.parser = KconfigParser(args, self.build_dir) self.state = STATE_IDLE self.failed_boards = set() @@ -594,11 +594,9 @@ class Slot: return self.failed_boards
class Slots: - """Controller of the array of subprocess slots."""
- def __init__(self, toolchains, args, progress, reference_src_dir, db_queue, - col): + def __init__(self, toolchains, args, progress, reference_src_dir, db_queue): """Create a new slots controller.
Args: @@ -608,17 +606,16 @@ class Slots: reference_src_dir (str): Determine the true starting config state from this source tree (None for none) db_queue (Queue): output queue to write config info for the database - col (terminal.Color): Colour object """ self.args = args self.slots = [] self.progress = progress - self.col = col + self.col = progress.col devnull = subprocess.DEVNULL make_cmd = get_make_cmd() for _ in range(args.jobs): self.slots.append(Slot(toolchains, args, progress, devnull, - make_cmd, reference_src_dir, db_queue, col)) + make_cmd, reference_src_dir, db_queue))
def add(self, defconfig): """Add a new subprocess if a vacant slot is found. @@ -747,7 +744,7 @@ def move_config(args): col = terminal.Color(terminal.COLOR_NEVER if args.nocolour else terminal.COLOR_IF_TERMINAL) progress = Progress(col, len(defconfigs)) - slots = Slots(toolchains, args, progress, reference_src_dir, db_queue, col) + slots = Slots(toolchains, args, progress, reference_src_dir, db_queue)
# Main loop to process defconfig files: # Add a new subprocess into a vacant slot.

This is not needed since the progress indicator has the object. Use that instead.
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-)
Applied to u-boot-dm, thanks!

Put the check for an operation being provided into the parse_args() function, to reduce the size of main().
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/tools/qconfig.py b/tools/qconfig.py index dd24e4b398b..408807931ff 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -1552,7 +1552,13 @@ doc/develop/moveconfig.rst for documentation.''' help='show any build errors as boards are built') parser.add_argument('configs', nargs='*')
- return parser, parser.parse_args() + args = parser.parse_args() + if not any((args.force_sync, args.build_db, args.imply, args.find, + args.scan_source, args.test)): + parser.print_usage() + sys.exit(1) + + return parser, args
def imply(args): @@ -1660,11 +1666,6 @@ def do_tests(): def main(): """Main program""" parser, args = parse_args() - if not any((args.force_sync, args.build_db, args.imply, args.find, - args.scan_source, args.test)): - parser.print_usage() - sys.exit(1) - check_top_directory()
# prefix the option name with CONFIG_ if missing

Put the check for an operation being provided into the parse_args() function, to reduce the size of main().
Signed-off-by: Simon Glass sjg@chromium.org ---
tools/qconfig.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
Applied to u-boot-dm, thanks!

Add basic support for searching for matching of non-matching values.
Signed-off-by: Simon Glass sjg@chromium.org Fixes: https://source.denx.de/u-boot/custodians/u-boot-dm/-/issues/20
---
doc/develop/qconfig.rst | 14 ++++++++++++++ tools/qconfig.py | 16 ++++++++++++---- 2 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/doc/develop/qconfig.rst b/doc/develop/qconfig.rst index 8efb1eb2685..123779eab17 100644 --- a/doc/develop/qconfig.rst +++ b/doc/develop/qconfig.rst @@ -85,6 +85,20 @@ example, to find boards which enabled CONFIG_SCSI but not CONFIG_BLK:: 3 matches pg_wcom_seli8_defconfig highbank_defconfig pg_wcom_expu1_defconfig
+It is also possible to search for particular values. For example, this finds all +boards with an empty string for `CONFIG_DEFAULT_FDT_FILE`:: + + ./tools/qconfig.py -f DEFAULT_FDT_FILE="" + 1092 matches + ... + +This finds boards which have a value for SYS_MAXARGS other than 64:: + + ./tools/qconfig.py -f ~SYS_MAXARGS=64 + cfg CONFIG_SYS_MAXARGS + 281 matches + ... +
Finding implied CONFIGs ----------------------- diff --git a/tools/qconfig.py b/tools/qconfig.py index 408807931ff..3e7d42223dc 100755 --- a/tools/qconfig.py +++ b/tools/qconfig.py @@ -1079,7 +1079,7 @@ def do_imply_config(config_list, add_imply, imply_flags, skip_added, for linenum in sorted(linenums, reverse=True): add_imply_rule(config[CONFIG_LEN:], fname, linenum)
-def defconfig_matches(configs, re_match): +def defconfig_matches(configs, re_match, re_val): """Check if any CONFIG option matches a regex
The match must be complete, i.e. from the start to end of the CONFIG option. @@ -1089,13 +1089,15 @@ def defconfig_matches(configs, re_match): key: CONFIG option value: Value of option re_match (re.Pattern): Match to check + re_val (re.Pattern): Regular expression to check against value (or None)
Returns: bool: True if any CONFIG matches the regex """ - for cfg in configs: + for cfg, val in configs.items(): if re_match.fullmatch(cfg): - return True + if not re_val or re_val.fullmatch(val): + return True return False
def do_find_config(config_list): @@ -1123,15 +1125,21 @@ def do_find_config(config_list): if cfg[0] == '~': want = False cfg = cfg[1:] + val = None + re_val = None + if '=' in cfg: + cfg, val = cfg.split('=', maxsplit=1) + re_val = re.compile(val)
# Search everything that is still in the running. If it has a config # that we want, or doesn't have one that we don't, add it into the # running for the next stage in_list = out out = set() + print('cfg', cfg) re_match = re.compile(cfg) for defc in in_list: - has_cfg = defconfig_matches(config_db[defc], re_match) + has_cfg = defconfig_matches(config_db[defc], re_match, re_val) if has_cfg == want: out.add(defc) print(f'{len(out)} matches')
participants (1)
-
Simon Glass