From 811c8e17117880badf0ea218dda44c06a3e02a2e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 11 Jul 2022 19:04:10 -0600 Subject: [PATCH] Drop genboardscfg.py Now that buildman can generate this with the -R option, drop the script. Signed-off-by: Simon Glass Suggested-by: Tom Rini --- scripts/pylint.base | 1 - tools/genboardscfg.py | 444 -------------------------------------------------- 2 files changed, 445 deletions(-) delete mode 100755 tools/genboardscfg.py diff --git a/scripts/pylint.base b/scripts/pylint.base index 9ebebf4..dd6360e 100644 --- a/scripts/pylint.base +++ b/scripts/pylint.base @@ -201,7 +201,6 @@ tools_dtoc_test_fdt 6.88 tools_dtoc_test_src_scan 9.43 tools_efivar 6.71 tools_endian-swap 9.29 -tools_genboardscfg 7.95 tools_microcode-tool 7.25 tools_moveconfig 8.34 tools_patman___init__ 0.00 diff --git a/tools/genboardscfg.py b/tools/genboardscfg.py deleted file mode 100755 index 07bf681..0000000 --- a/tools/genboardscfg.py +++ /dev/null @@ -1,444 +0,0 @@ -#!/usr/bin/env python3 -# SPDX-License-Identifier: GPL-2.0+ -# -# Author: Masahiro Yamada -# - -""" -Converter from Kconfig and MAINTAINERS to a board database. - -Run 'tools/genboardscfg.py' to create a board database. - -Run 'tools/genboardscfg.py -h' for available options. -""" - -import errno -import fnmatch -import glob -import multiprocessing -import optparse -import os -import sys -import tempfile -import time - -from buildman import kconfiglib - -### constant variables ### -OUTPUT_FILE = 'boards.cfg' -CONFIG_DIR = 'configs' -SLEEP_TIME = 0.03 -COMMENT_BLOCK = '''# -# List of boards -# Automatically generated by %s: don't edit -# -# Status, Arch, CPU, SoC, Vendor, Board, Target, Options, Maintainers - -''' % __file__ - -### helper functions ### -def try_remove(f): - """Remove a file ignoring 'No such file or directory' error.""" - try: - os.remove(f) - except OSError as exception: - # Ignore 'No such file or directory' error - if exception.errno != errno.ENOENT: - raise - -def check_top_directory(): - """Exit if we are not at the top of source directory.""" - for f in ('README', 'Licenses'): - if not os.path.exists(f): - sys.exit('Please run at the top of source directory.') - -def output_is_new(output): - """Check if the output file is up to date. - - Returns: - True if the given output file exists and is newer than any of - *_defconfig, MAINTAINERS and Kconfig*. False otherwise. - """ - try: - ctime = os.path.getctime(output) - except OSError as exception: - if exception.errno == errno.ENOENT: - # return False on 'No such file or directory' error - return False - else: - raise - - for (dirpath, dirnames, filenames) in os.walk(CONFIG_DIR): - for filename in fnmatch.filter(filenames, '*_defconfig'): - if fnmatch.fnmatch(filename, '.*'): - continue - filepath = os.path.join(dirpath, filename) - if ctime < os.path.getctime(filepath): - return False - - for (dirpath, dirnames, filenames) in os.walk('.'): - for filename in filenames: - if (fnmatch.fnmatch(filename, '*~') or - not fnmatch.fnmatch(filename, 'Kconfig*') and - not filename == 'MAINTAINERS'): - continue - filepath = os.path.join(dirpath, filename) - if ctime < os.path.getctime(filepath): - return False - - # Detect a board that has been removed since the current board database - # was generated - with open(output, encoding="utf-8") as f: - for line in f: - if line[0] == '#' or line == '\n': - continue - defconfig = line.split()[6] + '_defconfig' - if not os.path.exists(os.path.join(CONFIG_DIR, defconfig)): - return False - - return True - -### classes ### -class KconfigScanner: - - """Kconfig scanner.""" - - ### constant variable only used in this class ### - _SYMBOL_TABLE = { - 'arch' : 'SYS_ARCH', - 'cpu' : 'SYS_CPU', - 'soc' : 'SYS_SOC', - 'vendor' : 'SYS_VENDOR', - 'board' : 'SYS_BOARD', - 'config' : 'SYS_CONFIG_NAME', - 'options' : 'SYS_EXTRA_OPTIONS' - } - - def __init__(self): - """Scan all the Kconfig files and create a Kconfig object.""" - # Define environment variables referenced from Kconfig - os.environ['srctree'] = os.getcwd() - os.environ['UBOOTVERSION'] = 'dummy' - os.environ['KCONFIG_OBJDIR'] = '' - self._conf = kconfiglib.Kconfig(warn=False) - - def __del__(self): - """Delete a leftover temporary file before exit. - - The scan() method of this class creates a temporay file and deletes - it on success. If scan() method throws an exception on the way, - the temporary file might be left over. In that case, it should be - deleted in this destructor. - """ - if hasattr(self, '_tmpfile') and self._tmpfile: - try_remove(self._tmpfile) - - def scan(self, defconfig): - """Load a defconfig file to obtain board parameters. - - Arguments: - defconfig: path to the defconfig file to be processed - - Returns: - A dictionary of board parameters. It has a form of: - { - 'arch': , - 'cpu': , - 'soc': , - 'vendor': , - 'board': , - 'target': , - 'config': , - 'options': - } - """ - # strip special prefixes and save it in a temporary file - fd, self._tmpfile = tempfile.mkstemp() - with os.fdopen(fd, 'w') as f: - for line in open(defconfig): - colon = line.find(':CONFIG_') - if colon == -1: - f.write(line) - else: - f.write(line[colon + 1:]) - - self._conf.load_config(self._tmpfile) - try_remove(self._tmpfile) - self._tmpfile = None - - params = {} - - # Get the value of CONFIG_SYS_ARCH, CONFIG_SYS_CPU, ... etc. - # Set '-' if the value is empty. - for key, symbol in list(self._SYMBOL_TABLE.items()): - value = self._conf.syms.get(symbol).str_value - if value: - params[key] = value - else: - params[key] = '-' - - defconfig = os.path.basename(defconfig) - params['target'], match, rear = defconfig.partition('_defconfig') - assert match and not rear, '%s : invalid defconfig' % defconfig - - # fix-up for aarch64 - if params['arch'] == 'arm' and params['cpu'] == 'armv8': - params['arch'] = 'aarch64' - - # fix-up options field. It should have the form: - # [:comma separated config options] - if params['options'] != '-': - params['options'] = params['config'] + ':' + \ - params['options'].replace(r'\"', '"') - elif params['config'] != params['target']: - params['options'] = params['config'] - - return params - -def scan_defconfigs_for_multiprocess(queue, defconfigs): - """Scan defconfig files and queue their board parameters - - This function is intended to be passed to - multiprocessing.Process() constructor. - - Arguments: - queue: An instance of multiprocessing.Queue(). - The resulting board parameters are written into it. - defconfigs: A sequence of defconfig files to be scanned. - """ - kconf_scanner = KconfigScanner() - for defconfig in defconfigs: - queue.put(kconf_scanner.scan(defconfig)) - -def read_queues(queues, params_list): - """Read the queues and append the data to the paramers list""" - for q in queues: - while not q.empty(): - params_list.append(q.get()) - -def scan_defconfigs(jobs=1): - """Collect board parameters for all defconfig files. - - This function invokes multiple processes for faster processing. - - Arguments: - jobs: The number of jobs to run simultaneously - """ - all_defconfigs = [] - for (dirpath, dirnames, filenames) in os.walk(CONFIG_DIR): - for filename in fnmatch.filter(filenames, '*_defconfig'): - if fnmatch.fnmatch(filename, '.*'): - continue - all_defconfigs.append(os.path.join(dirpath, filename)) - - total_boards = len(all_defconfigs) - processes = [] - queues = [] - for i in range(jobs): - defconfigs = all_defconfigs[total_boards * i // jobs : - total_boards * (i + 1) // jobs] - q = multiprocessing.Queue(maxsize=-1) - p = multiprocessing.Process(target=scan_defconfigs_for_multiprocess, - args=(q, defconfigs)) - p.start() - processes.append(p) - queues.append(q) - - # The resulting data should be accumulated to this list - params_list = [] - - # Data in the queues should be retrieved preriodically. - # Otherwise, the queues would become full and subprocesses would get stuck. - while any([p.is_alive() for p in processes]): - read_queues(queues, params_list) - # sleep for a while until the queues are filled - time.sleep(SLEEP_TIME) - - # Joining subprocesses just in case - # (All subprocesses should already have been finished) - for p in processes: - p.join() - - # retrieve leftover data - read_queues(queues, params_list) - - return params_list - -class MaintainersDatabase: - - """The database of board status and maintainers.""" - - def __init__(self): - """Create an empty database.""" - self.database = {} - - def get_status(self, target): - """Return the status of the given board. - - The board status is generally either 'Active' or 'Orphan'. - Display a warning message and return '-' if status information - is not found. - - Returns: - 'Active', 'Orphan' or '-'. - """ - if not target in self.database: - print("WARNING: no status info for '%s'" % target, file=sys.stderr) - return '-' - - tmp = self.database[target][0] - if tmp.startswith('Maintained'): - return 'Active' - elif tmp.startswith('Supported'): - return 'Active' - elif tmp.startswith('Orphan'): - return 'Orphan' - else: - print(("WARNING: %s: unknown status for '%s'" % - (tmp, target)), file=sys.stderr) - return '-' - - def get_maintainers(self, target): - """Return the maintainers of the given board. - - Returns: - Maintainers of the board. If the board has two or more maintainers, - they are separated with colons. - """ - if not target in self.database: - print("WARNING: no maintainers for '%s'" % target, file=sys.stderr) - return '' - - return ':'.join(self.database[target][1]) - - def parse_file(self, file): - """Parse a MAINTAINERS file. - - Parse a MAINTAINERS file and accumulates board status and - maintainers information. - - Arguments: - file: MAINTAINERS file to be parsed - """ - targets = [] - maintainers = [] - status = '-' - for line in open(file, encoding="utf-8"): - # Check also commented maintainers - if line[:3] == '#M:': - line = line[1:] - tag, rest = line[:2], line[2:].strip() - if tag == 'M:': - maintainers.append(rest) - elif tag == 'F:': - # expand wildcard and filter by 'configs/*_defconfig' - for f in glob.glob(rest): - front, match, rear = f.partition('configs/') - if not front and match: - front, match, rear = rear.rpartition('_defconfig') - if match and not rear: - targets.append(front) - elif tag == 'S:': - status = rest - elif line == '\n': - for target in targets: - self.database[target] = (status, maintainers) - targets = [] - maintainers = [] - status = '-' - if targets: - for target in targets: - self.database[target] = (status, maintainers) - -def insert_maintainers_info(params_list): - """Add Status and Maintainers information to the board parameters list. - - Arguments: - params_list: A list of the board parameters - """ - database = MaintainersDatabase() - for (dirpath, dirnames, filenames) in os.walk('.'): - if 'MAINTAINERS' in filenames: - database.parse_file(os.path.join(dirpath, 'MAINTAINERS')) - - for i, params in enumerate(params_list): - target = params['target'] - params['status'] = database.get_status(target) - params['maintainers'] = database.get_maintainers(target) - params_list[i] = params - -def format_and_output(params_list, output): - """Write board parameters into a file. - - Columnate the board parameters, sort lines alphabetically, - and then write them to a file. - - Arguments: - params_list: The list of board parameters - output: The path to the output file - """ - FIELDS = ('status', 'arch', 'cpu', 'soc', 'vendor', 'board', 'target', - 'options', 'maintainers') - - # First, decide the width of each column - max_length = dict([ (f, 0) for f in FIELDS]) - for params in params_list: - for f in FIELDS: - max_length[f] = max(max_length[f], len(params[f])) - - output_lines = [] - for params in params_list: - line = '' - for f in FIELDS: - # insert two spaces between fields like column -t would - line += ' ' + params[f].ljust(max_length[f]) - output_lines.append(line.strip()) - - # ignore case when sorting - output_lines.sort(key=str.lower) - - with open(output, 'w', encoding="utf-8") as f: - f.write(COMMENT_BLOCK + '\n'.join(output_lines) + '\n') - -def gen_boards_cfg(output, jobs=1, force=False, quiet=False): - """Generate a board database file. - - Arguments: - output: The name of the output file - jobs: The number of jobs to run simultaneously - force: Force to generate the output even if it is new - quiet: True to avoid printing a message if nothing needs doing - """ - check_top_directory() - - if not force and output_is_new(output): - if not quiet: - print("%s is up to date. Nothing to do." % output) - sys.exit(0) - - params_list = scan_defconfigs(jobs) - insert_maintainers_info(params_list) - format_and_output(params_list, output) - -def main(): - try: - cpu_count = multiprocessing.cpu_count() - except NotImplementedError: - cpu_count = 1 - - parser = optparse.OptionParser() - # Add options here - parser.add_option('-f', '--force', action="store_true", default=False, - help='regenerate the output even if it is new') - parser.add_option('-j', '--jobs', type='int', default=min(cpu_count, 240), - help='the number of jobs to run simultaneously') - parser.add_option('-o', '--output', default=OUTPUT_FILE, - help='output file [default=%s]' % OUTPUT_FILE) - parser.add_option('-q', '--quiet', action="store_true", help='run silently') - (options, args) = parser.parse_args() - - gen_boards_cfg(options.output, jobs=options.jobs, force=options.force, - quiet=options.quiet) - -if __name__ == '__main__': - main() -- 2.7.4