Create a class for command line config manipulation

Signed-off-by: Gabor Mezei <gabor.mezei@arm.com>
diff --git a/scripts/config.py b/scripts/config.py
index d2de7a7..d2735ee 100755
--- a/scripts/config.py
+++ b/scripts/config.py
@@ -11,8 +11,10 @@
 ## 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 @@
 
         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 @@
                     """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())