From 24d7cc71af3cef5b288b7b9b2e297a66c8796385 Mon Sep 17 00:00:00 2001 From: Gabor Mezei Date: Tue, 6 Aug 2024 15:11:24 +0200 Subject: [PATCH] Create a class for command line config manipulation Signed-off-by: Gabor Mezei --- scripts/config.py | 207 +++++++++++++++++++++++++++------------------- 1 file changed, 122 insertions(+), 85 deletions(-) diff --git a/scripts/config.py b/scripts/config.py index d2de7a7233..d2735ee214 100755 --- a/scripts/config.py +++ b/scripts/config.py @@ -11,8 +11,10 @@ Basic usage, to read the Mbed TLS configuration: ## SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later ## +import argparse import os import re +import sys from abc import ABCMeta @@ -738,66 +740,132 @@ class CombinedConfig(Config): return self._get_configfile(name).filename -if __name__ == '__main__': - #pylint: disable=too-many-statements - def main(): - """Command line mbedtls_config.h manipulation tool.""" - parser = argparse.ArgumentParser(description=""" - Mbed TLS configuration file manipulation tool. - """) - parser.add_argument('--file', '-f', - help="""File to read (and modify if requested). - Default: {}. - """.format(MbedTLSConfigFile.default_path)) - parser.add_argument('--cryptofile', '-c', - help="""Crypto file to read (and modify if requested). - Default: {}. - """.format(CryptoConfigFile.default_path)) - parser.add_argument('--force', '-o', - action='store_true', - help="""For the set command, if SYMBOL is not - present, add a definition for it.""") - parser.add_argument('--write', '-w', metavar='FILE', - help="""File to write to instead of the input file.""") - subparsers = parser.add_subparsers(dest='command', - title='Commands') - parser_get = subparsers.add_parser('get', - help="""Find the value of SYMBOL - and print it. Exit with - status 0 if a #define for SYMBOL is - found, 1 otherwise. - """) + +class ConfigTool(metaclass=ABCMeta): + """Command line config manipulation tool. + + Custom parser option can be added by overriding 'custom_parser_options'. + """ + + def __init__(self, file_type): + """Create parser for config manipulation tool.""" + + self.parser = argparse.ArgumentParser(description=""" + Configuration file manipulation tool.""") + self.subparsers = self.parser.add_subparsers(dest='command', + title='Commands') + self._common_parser_options(file_type) + self.custom_parser_options() + self.parser_args = self.parser.parse_args() + self.config = Config() # Make the pylint happy + + def add_adapter(self, name, function, description): + """Creates a command in the tool for a configuration adapter.""" + + subparser = self.subparsers.add_parser(name, help=description) + subparser.set_defaults(adapter=function) + + def _common_parser_options(self, file_type): + """Common parser options for config manipulation tool.""" + + self.parser.add_argument('--file', '-f', + help="""File to read (and modify if requested). + Default: {}. + """.format(file_type.default_path)) + self.parser.add_argument('--force', '-o', + action='store_true', + help="""For the set command, if SYMBOL is not + present, add a definition for it.""") + self.parser.add_argument('--write', '-w', metavar='FILE', + help="""File to write to instead of the input file.""") + + parser_get = self.subparsers.add_parser('get', + help="""Find the value of SYMBOL + and print it. Exit with + status 0 if a #define for SYMBOL is + found, 1 otherwise. + """) parser_get.add_argument('symbol', metavar='SYMBOL') - parser_set = subparsers.add_parser('set', - help="""Set SYMBOL to VALUE. - If VALUE is omitted, just uncomment - the #define for SYMBOL. - Error out of a line defining - SYMBOL (commented or not) is not - found, unless --force is passed. - """) + parser_set = self.subparsers.add_parser('set', + help="""Set SYMBOL to VALUE. + If VALUE is omitted, just uncomment + the #define for SYMBOL. + Error out of a line defining + SYMBOL (commented or not) is not + found, unless --force is passed. + """) parser_set.add_argument('symbol', metavar='SYMBOL') parser_set.add_argument('value', metavar='VALUE', nargs='?', default='') - parser_set_all = subparsers.add_parser('set-all', - help="""Uncomment all #define - whose name contains a match for - REGEX.""") + parser_set_all = self.subparsers.add_parser('set-all', + help="""Uncomment all #define + whose name contains a match for + REGEX.""") parser_set_all.add_argument('regexs', metavar='REGEX', nargs='*') - parser_unset = subparsers.add_parser('unset', - help="""Comment out the #define - for SYMBOL. Do nothing if none - is present.""") + parser_unset = self.subparsers.add_parser('unset', + help="""Comment out the #define + for SYMBOL. Do nothing if none + is present.""") parser_unset.add_argument('symbol', metavar='SYMBOL') - parser_unset_all = subparsers.add_parser('unset-all', - help="""Comment out all #define - whose name contains a match for - REGEX.""") + parser_unset_all = self.subparsers.add_parser('unset-all', + help="""Comment out all #define + whose name contains a match for + REGEX.""") parser_unset_all.add_argument('regexs', metavar='REGEX', nargs='*') - def add_adapter(name, function, description): - subparser = subparsers.add_parser(name, help=description) - subparser.set_defaults(adapter=function) + def custom_parser_options(self): + """Adds custom options for the parser. Designed for overridden by descendant.""" + pass + + def main(self): + """Common main fuction for config manipulation tool.""" + + if self.parser_args.command is None: + self.parser.print_help() + return 1 + if self.parser_args.command == 'get': + if self.parser_args.symbol in self.config: + value = self.config[self.parser_args.symbol] + if value: + sys.stdout.write(value + '\n') + return 0 if self.parser_args.symbol in self.config else 1 + elif self.parser_args.command == 'set': + if not self.parser_args.force and self.parser_args.symbol not in self.config.settings: + sys.stderr.write( + "A #define for the symbol {} was not found in {}\n" + .format(self.parser_args.symbol, + self.config.filename(self.parser_args.symbol))) + return 1 + self.config.set(self.parser_args.symbol, value=self.parser_args.value) + elif self.parser_args.command == 'set-all': + self.config.change_matching(self.parser_args.regexs, True) + elif self.parser_args.command == 'unset': + self.config.unset(self.parser_args.symbol) + elif self.parser_args.command == 'unset-all': + self.config.change_matching(self.parser_args.regexs, False) + else: + self.config.adapt(self.parser_args.adapter) + self.config.write(self.parser_args.write) + + return 0 + + +class MbedTLSConfigTool(ConfigTool): + """Command line mbedtls_config.h and crypto_config.h manipulation tool.""" + + def __init__(self): + super().__init__(MbedTLSConfigFile) + self.config = CombinedConfig(MbedTLSConfigFile(self.parser_args.file), + CryptoConfigFile(self.parser_args.cryptofile)) + + def custom_parser_options(self): + """Adds MbedTLS specific options for the parser.""" + + self.parser.add_argument('--cryptofile', '-c', + help="""Crypto file to read (and modify if requested). + Default: {}. + """.format(CryptoConfigFile.default_path)) + add_adapter('baremetal', baremetal_adapter, """Like full, but exclude features that require platform features such as file input-output.""") @@ -829,37 +897,6 @@ if __name__ == '__main__': """Like full, but with only crypto features, excluding X.509 and TLS.""") - args = parser.parse_args() - config = CombinedConfig(MbedTLSConfigFile(args.file), CryptoConfigFile(args.cryptofile)) - if args.command is None: - parser.print_help() - return 1 - elif args.command == 'get': - if args.symbol in config: - value = config[args.symbol] - if value: - sys.stdout.write(value + '\n') - return 0 if args.symbol in config else 1 - elif args.command == 'set': - if not args.force and args.symbol not in config.settings: - sys.stderr.write("A #define for the symbol {} " - "was not found in {}\n" - .format(args.symbol, config.filename(args.symbol))) - return 1 - config.set(args.symbol, value=args.value) - elif args.command == 'set-all': - config.change_matching(args.regexs, True) - elif args.command == 'unset': - config.unset(args.symbol) - elif args.command == 'unset-all': - config.change_matching(args.regexs, False) - else: - config.adapt(args.adapter) - config.write(args.write) - return 0 - # Import modules only used by main only if main is defined and called. - # pylint: disable=wrong-import-position - import argparse - import sys - sys.exit(main()) +if __name__ == '__main__': + sys.exit(MbedTLSConfigTool().main())