Create a class for command line config manipulation

Signed-off-by: Gabor Mezei <gabor.mezei@arm.com>
This commit is contained in:
Gabor Mezei 2024-08-06 15:11:24 +02:00
parent 776ee9068d
commit 24d7cc71af
No known key found for this signature in database
GPG Key ID: 6310BD29B0BFF98C

View File

@ -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())