| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564 |
- #!/usr/bin/env python3
- # Copyright (c) 2022, Arm Limited, All Rights Reserved.
- # SPDX-License-Identifier: Apache-2.0
- #
- # Licensed under the Apache License, Version 2.0 (the "License"); you may
- # not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- #
- # This file is part of Mbed TLS (https://tls.mbed.org)
- """
- Test Mbed TLS with a subset of algorithms.
- This script can be divided into several steps:
- First, include/mbedtls/mbedtls_config.h or a different config file passed
- in the arguments is parsed to extract any configuration options (using config.py).
- Then, test domains (groups of jobs, tests) are built based on predefined data
- collected in the DomainData class. Here, each domain has five major traits:
- - domain name, can be used to run only specific tests via command-line;
- - configuration building method, described in detail below;
- - list of symbols passed to the configuration building method;
- - commands to be run on each job (only build, build and test, or any other custom);
- - optional list of symbols to be excluded from testing.
- The configuration building method can be one of the three following:
- - ComplementaryDomain - build a job for each passed symbol by disabling a single
- symbol and its reverse dependencies (defined in REVERSE_DEPENDENCIES);
- - ExclusiveDomain - build a job where, for each passed symbol, only this particular
- one is defined and other symbols from the list are unset. For each job look for
- any non-standard symbols to set/unset in EXCLUSIVE_GROUPS. These are usually not
- direct dependencies, but rather non-trivial results of other configs missing. Then
- look for any unset symbols and handle their reverse dependencies.
- Examples of EXCLUSIVE_GROUPS usage:
- - MBEDTLS_SHA512_C job turns off all hashes except SHA512. MBEDTLS_SSL_COOKIE_C
- requires either SHA256 or SHA384 to work, so it also has to be disabled.
- This is not a dependency on SHA512_C, but a result of an exclusive domain
- config building method. Relevant field:
- 'MBEDTLS_SHA512_C': ['-MBEDTLS_SSL_COOKIE_C'],
- - DualDomain - combination of the two above - both complementary and exclusive domain
- job generation code will be run. Currently only used for hashes.
- Lastly, the collected jobs are executed and (optionally) tested, with
- error reporting and coloring as configured in options. Each test starts with
- a full config without a couple of slowing down or unnecessary options
- (see set_reference_config), then the specific job config is derived.
- """
- import argparse
- import os
- import re
- import shutil
- import subprocess
- import sys
- import traceback
- from typing import Union
- # Add the Mbed TLS Python library directory to the module search path
- import scripts_path # pylint: disable=unused-import
- import config
- class Colors: # pylint: disable=too-few-public-methods
- """Minimalistic support for colored output.
- Each field of an object of this class is either None if colored output
- is not possible or not desired, or a pair of strings (start, stop) such
- that outputting start switches the text color to the desired color and
- stop switches the text color back to the default."""
- red = None
- green = None
- cyan = None
- bold_red = None
- bold_green = None
- def __init__(self, options=None):
- """Initialize color profile according to passed options."""
- if not options or options.color in ['no', 'never']:
- want_color = False
- elif options.color in ['yes', 'always']:
- want_color = True
- else:
- want_color = sys.stderr.isatty()
- if want_color:
- # Assume ANSI compatible terminal
- normal = '\033[0m'
- self.red = ('\033[31m', normal)
- self.green = ('\033[32m', normal)
- self.cyan = ('\033[36m', normal)
- self.bold_red = ('\033[1;31m', normal)
- self.bold_green = ('\033[1;32m', normal)
- NO_COLORS = Colors(None)
- def log_line(text, prefix='depends.py:', suffix='', color=None):
- """Print a status message."""
- if color is not None:
- prefix = color[0] + prefix
- suffix = suffix + color[1]
- sys.stderr.write(prefix + ' ' + text + suffix + '\n')
- sys.stderr.flush()
- def log_command(cmd):
- """Print a trace of the specified command.
- cmd is a list of strings: a command name and its arguments."""
- log_line(' '.join(cmd), prefix='+')
- def backup_config(options):
- """Back up the library configuration file (mbedtls_config.h).
- If the backup file already exists, it is presumed to be the desired backup,
- so don't make another backup."""
- if os.path.exists(options.config_backup):
- options.own_backup = False
- else:
- options.own_backup = True
- shutil.copy(options.config, options.config_backup)
- def restore_config(options):
- """Restore the library configuration file (mbedtls_config.h).
- Remove the backup file if it was saved earlier."""
- if options.own_backup:
- shutil.move(options.config_backup, options.config)
- else:
- shutil.copy(options.config_backup, options.config)
- def option_exists(conf, option):
- return option in conf.settings
- def set_config_option_value(conf, option, colors, value: Union[bool, str]):
- """Set/unset a configuration option, optionally specifying a value.
- value can be either True/False (set/unset config option), or a string,
- which will make a symbol defined with a certain value."""
- if not option_exists(conf, option):
- log_line('Symbol {} was not found in {}'.format(option, conf.filename), color=colors.red)
- return False
- if value is False:
- log_command(['config.py', 'unset', option])
- conf.unset(option)
- elif value is True:
- log_command(['config.py', 'set', option])
- conf.set(option)
- else:
- log_command(['config.py', 'set', option, value])
- conf.set(option, value)
- return True
- def set_reference_config(conf, options, colors):
- """Change the library configuration file (mbedtls_config.h) to the reference state.
- The reference state is the one from which the tested configurations are
- derived."""
- # Turn off options that are not relevant to the tests and slow them down.
- log_command(['config.py', 'full'])
- conf.adapt(config.full_adapter)
- set_config_option_value(conf, 'MBEDTLS_TEST_HOOKS', colors, False)
- if options.unset_use_psa:
- set_config_option_value(conf, 'MBEDTLS_USE_PSA_CRYPTO', colors, False)
- class Job:
- """A job builds the library in a specific configuration and runs some tests."""
- def __init__(self, name, config_settings, commands):
- """Build a job object.
- The job uses the configuration described by config_settings. This is a
- dictionary where the keys are preprocessor symbols and the values are
- booleans or strings. A boolean indicates whether or not to #define the
- symbol. With a string, the symbol is #define'd to that value.
- After setting the configuration, the job runs the programs specified by
- commands. This is a list of lists of strings; each list of string is a
- command name and its arguments and is passed to subprocess.call with
- shell=False."""
- self.name = name
- self.config_settings = config_settings
- self.commands = commands
- def announce(self, colors, what):
- '''Announce the start or completion of a job.
- If what is None, announce the start of the job.
- If what is True, announce that the job has passed.
- If what is False, announce that the job has failed.'''
- if what is True:
- log_line(self.name + ' PASSED', color=colors.green)
- elif what is False:
- log_line(self.name + ' FAILED', color=colors.red)
- else:
- log_line('starting ' + self.name, color=colors.cyan)
- def configure(self, conf, options, colors):
- '''Set library configuration options as required for the job.'''
- set_reference_config(conf, options, colors)
- for key, value in sorted(self.config_settings.items()):
- ret = set_config_option_value(conf, key, colors, value)
- if ret is False:
- return False
- return True
- def test(self, options):
- '''Run the job's build and test commands.
- Return True if all the commands succeed and False otherwise.
- If options.keep_going is false, stop as soon as one command fails. Otherwise
- run all the commands, except that if the first command fails, none of the
- other commands are run (typically, the first command is a build command
- and subsequent commands are tests that cannot run if the build failed).'''
- built = False
- success = True
- for command in self.commands:
- log_command(command)
- ret = subprocess.call(command)
- if ret != 0:
- if command[0] not in ['make', options.make_command]:
- log_line('*** [{}] Error {}'.format(' '.join(command), ret))
- if not options.keep_going or not built:
- return False
- success = False
- built = True
- return success
- # If the configuration option A requires B, make sure that
- # B in REVERSE_DEPENDENCIES[A].
- # All the information here should be contained in check_config.h. This
- # file includes a copy because it changes rarely and it would be a pain
- # to extract automatically.
- REVERSE_DEPENDENCIES = {
- 'MBEDTLS_AES_C': ['MBEDTLS_CTR_DRBG_C',
- 'MBEDTLS_NIST_KW_C'],
- 'MBEDTLS_CHACHA20_C': ['MBEDTLS_CHACHAPOLY_C'],
- 'MBEDTLS_ECDSA_C': ['MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED',
- 'MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED'],
- 'MBEDTLS_ECP_C': ['MBEDTLS_ECDSA_C',
- 'MBEDTLS_ECDH_C',
- 'MBEDTLS_ECJPAKE_C',
- 'MBEDTLS_ECP_RESTARTABLE',
- 'MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED',
- 'MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED',
- 'MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED',
- 'MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED',
- 'MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED',
- 'MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED',
- 'MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_EPHEMERAL_ENABLED',
- 'MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_PSK_EPHEMERAL_ENABLED'],
- 'MBEDTLS_ECP_DP_SECP256R1_ENABLED': ['MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED'],
- 'MBEDTLS_PKCS1_V21': ['MBEDTLS_X509_RSASSA_PSS_SUPPORT'],
- 'MBEDTLS_PKCS1_V15': ['MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED',
- 'MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED',
- 'MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED',
- 'MBEDTLS_KEY_EXCHANGE_RSA_ENABLED'],
- 'MBEDTLS_RSA_C': ['MBEDTLS_X509_RSASSA_PSS_SUPPORT',
- 'MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED',
- 'MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED',
- 'MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED',
- 'MBEDTLS_KEY_EXCHANGE_RSA_ENABLED',
- 'MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED'],
- 'MBEDTLS_SHA256_C': ['MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED',
- 'MBEDTLS_ENTROPY_FORCE_SHA256',
- 'MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT',
- 'MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY',
- 'MBEDTLS_LMS_C',
- 'MBEDTLS_LMS_PRIVATE'],
- 'MBEDTLS_SHA512_C': ['MBEDTLS_SHA512_USE_A64_CRYPTO_IF_PRESENT',
- 'MBEDTLS_SHA512_USE_A64_CRYPTO_ONLY'],
- 'MBEDTLS_SHA224_C': ['MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED',
- 'MBEDTLS_ENTROPY_FORCE_SHA256',
- 'MBEDTLS_SHA256_USE_A64_CRYPTO_IF_PRESENT',
- 'MBEDTLS_SHA256_USE_A64_CRYPTO_ONLY'],
- 'MBEDTLS_X509_RSASSA_PSS_SUPPORT': []
- }
- # If an option is tested in an exclusive test, alter the following defines.
- # These are not necessarily dependencies, but just minimal required changes
- # if a given define is the only one enabled from an exclusive group.
- EXCLUSIVE_GROUPS = {
- 'MBEDTLS_SHA512_C': ['-MBEDTLS_SSL_COOKIE_C',
- '-MBEDTLS_SSL_PROTO_TLS1_3'],
- 'MBEDTLS_ECP_DP_CURVE448_ENABLED': ['-MBEDTLS_ECDSA_C',
- '-MBEDTLS_ECDSA_DETERMINISTIC',
- '-MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED',
- '-MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED',
- '-MBEDTLS_ECJPAKE_C',
- '-MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED'],
- 'MBEDTLS_ECP_DP_CURVE25519_ENABLED': ['-MBEDTLS_ECDSA_C',
- '-MBEDTLS_ECDSA_DETERMINISTIC',
- '-MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED',
- '-MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED',
- '-MBEDTLS_ECJPAKE_C',
- '-MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED'],
- 'MBEDTLS_ARIA_C': ['-MBEDTLS_CMAC_C'],
- 'MBEDTLS_CAMELLIA_C': ['-MBEDTLS_CMAC_C'],
- 'MBEDTLS_CHACHA20_C': ['-MBEDTLS_CMAC_C', '-MBEDTLS_CCM_C', '-MBEDTLS_GCM_C'],
- 'MBEDTLS_DES_C': ['-MBEDTLS_CCM_C',
- '-MBEDTLS_GCM_C',
- '-MBEDTLS_SSL_TICKET_C',
- '-MBEDTLS_SSL_CONTEXT_SERIALIZATION'],
- }
- def handle_exclusive_groups(config_settings, symbol):
- """For every symbol tested in an exclusive group check if there are other
- defines to be altered. """
- for dep in EXCLUSIVE_GROUPS.get(symbol, []):
- unset = dep.startswith('-')
- dep = dep[1:]
- config_settings[dep] = not unset
- def turn_off_dependencies(config_settings):
- """For every option turned off config_settings, also turn off what depends on it.
- An option O is turned off if config_settings[O] is False."""
- for key, value in sorted(config_settings.items()):
- if value is not False:
- continue
- for dep in REVERSE_DEPENDENCIES.get(key, []):
- config_settings[dep] = False
- class BaseDomain: # pylint: disable=too-few-public-methods, unused-argument
- """A base class for all domains."""
- def __init__(self, symbols, commands, exclude):
- """Initialize the jobs container"""
- self.jobs = []
- class ExclusiveDomain(BaseDomain): # pylint: disable=too-few-public-methods
- """A domain consisting of a set of conceptually-equivalent settings.
- Establish a list of configuration symbols. For each symbol, run a test job
- with this symbol set and the others unset."""
- def __init__(self, symbols, commands, exclude=None):
- """Build a domain for the specified list of configuration symbols.
- The domain contains a set of jobs that enable one of the elements
- of symbols and disable the others.
- Each job runs the specified commands.
- If exclude is a regular expression, skip generated jobs whose description
- would match this regular expression."""
- super().__init__(symbols, commands, exclude)
- base_config_settings = {}
- for symbol in symbols:
- base_config_settings[symbol] = False
- for symbol in symbols:
- description = symbol
- if exclude and re.match(exclude, description):
- continue
- config_settings = base_config_settings.copy()
- config_settings[symbol] = True
- handle_exclusive_groups(config_settings, symbol)
- turn_off_dependencies(config_settings)
- job = Job(description, config_settings, commands)
- self.jobs.append(job)
- class ComplementaryDomain(BaseDomain): # pylint: disable=too-few-public-methods
- """A domain consisting of a set of loosely-related settings.
- Establish a list of configuration symbols. For each symbol, run a test job
- with this symbol unset.
- If exclude is a regular expression, skip generated jobs whose description
- would match this regular expression."""
- def __init__(self, symbols, commands, exclude=None):
- """Build a domain for the specified list of configuration symbols.
- Each job in the domain disables one of the specified symbols.
- Each job runs the specified commands."""
- super().__init__(symbols, commands, exclude)
- for symbol in symbols:
- description = '!' + symbol
- if exclude and re.match(exclude, description):
- continue
- config_settings = {symbol: False}
- turn_off_dependencies(config_settings)
- job = Job(description, config_settings, commands)
- self.jobs.append(job)
- class DualDomain(ExclusiveDomain, ComplementaryDomain): # pylint: disable=too-few-public-methods
- """A domain that contains both the ExclusiveDomain and BaseDomain tests.
- Both parent class __init__ calls are performed in any order and
- each call adds respective jobs. The job array initialization is done once in
- BaseDomain, before the parent __init__ calls."""
- class CipherInfo: # pylint: disable=too-few-public-methods
- """Collect data about cipher.h."""
- def __init__(self):
- self.base_symbols = set()
- with open('include/mbedtls/cipher.h', encoding="utf-8") as fh:
- for line in fh:
- m = re.match(r' *MBEDTLS_CIPHER_ID_(\w+),', line)
- if m and m.group(1) not in ['NONE', 'NULL', '3DES']:
- self.base_symbols.add('MBEDTLS_' + m.group(1) + '_C')
- class DomainData:
- """A container for domains and jobs, used to structurize testing."""
- def config_symbols_matching(self, regexp):
- """List the mbedtls_config.h settings matching regexp."""
- return [symbol for symbol in self.all_config_symbols
- if re.match(regexp, symbol)]
- def __init__(self, options, conf):
- """Gather data about the library and establish a list of domains to test."""
- build_command = [options.make_command, 'CFLAGS=-Werror']
- build_and_test = [build_command, [options.make_command, 'test']]
- self.all_config_symbols = set(conf.settings.keys())
- # Find hash modules by name.
- hash_symbols = self.config_symbols_matching(r'MBEDTLS_(MD|RIPEMD|SHA)[0-9]+_C\Z')
- # Find elliptic curve enabling macros by name.
- curve_symbols = self.config_symbols_matching(r'MBEDTLS_ECP_DP_\w+_ENABLED\Z')
- # Find key exchange enabling macros by name.
- key_exchange_symbols = self.config_symbols_matching(r'MBEDTLS_KEY_EXCHANGE_\w+_ENABLED\Z')
- # Find cipher IDs (block permutations and stream ciphers --- chaining
- # and padding modes are exercised separately) information by parsing
- # cipher.h, as the information is not readily available in mbedtls_config.h.
- cipher_info = CipherInfo()
- # Find block cipher chaining and padding mode enabling macros by name.
- cipher_chaining_symbols = self.config_symbols_matching(r'MBEDTLS_CIPHER_MODE_\w+\Z')
- cipher_padding_symbols = self.config_symbols_matching(r'MBEDTLS_CIPHER_PADDING_\w+\Z')
- self.domains = {
- # Cipher IDs, chaining modes and padding modes. Run the test suites.
- 'cipher_id': ExclusiveDomain(cipher_info.base_symbols,
- build_and_test),
- 'cipher_chaining': ExclusiveDomain(cipher_chaining_symbols,
- build_and_test),
- 'cipher_padding': ExclusiveDomain(cipher_padding_symbols,
- build_and_test),
- # Elliptic curves. Run the test suites.
- 'curves': ExclusiveDomain(curve_symbols, build_and_test),
- # Hash algorithms. Excluding exclusive domains of MD, RIPEMD, SHA1,
- # SHA224 and SHA384 because MBEDTLS_ENTROPY_C is extensively used
- # across various modules, but it depends on either SHA256 or SHA512.
- # As a consequence an "exclusive" test of anything other than SHA256
- # or SHA512 with MBEDTLS_ENTROPY_C enabled is not possible.
- 'hashes': DualDomain(hash_symbols, build_and_test,
- exclude=r'MBEDTLS_(MD|RIPEMD|SHA1_)' \
- '|MBEDTLS_SHA224_' \
- '|MBEDTLS_SHA384_'),
- # Key exchange types.
- 'kex': ExclusiveDomain(key_exchange_symbols, build_and_test),
- 'pkalgs': ComplementaryDomain(['MBEDTLS_ECDSA_C',
- 'MBEDTLS_ECP_C',
- 'MBEDTLS_PKCS1_V21',
- 'MBEDTLS_PKCS1_V15',
- 'MBEDTLS_RSA_C',
- 'MBEDTLS_X509_RSASSA_PSS_SUPPORT'],
- build_and_test),
- }
- self.jobs = {}
- for domain in self.domains.values():
- for job in domain.jobs:
- self.jobs[job.name] = job
- def get_jobs(self, name):
- """Return the list of jobs identified by the given name.
- A name can either be the name of a domain or the name of one specific job."""
- if name in self.domains:
- return sorted(self.domains[name].jobs, key=lambda job: job.name)
- else:
- return [self.jobs[name]]
- def run(options, job, conf, colors=NO_COLORS):
- """Run the specified job (a Job instance)."""
- subprocess.check_call([options.make_command, 'clean'])
- job.announce(colors, None)
- if not job.configure(conf, options, colors):
- job.announce(colors, False)
- return False
- conf.write()
- success = job.test(options)
- job.announce(colors, success)
- return success
- def run_tests(options, domain_data, conf):
- """Run the desired jobs.
- domain_data should be a DomainData instance that describes the available
- domains and jobs.
- Run the jobs listed in options.tasks."""
- if not hasattr(options, 'config_backup'):
- options.config_backup = options.config + '.bak'
- colors = Colors(options)
- jobs = []
- failures = []
- successes = []
- for name in options.tasks:
- jobs += domain_data.get_jobs(name)
- backup_config(options)
- try:
- for job in jobs:
- success = run(options, job, conf, colors=colors)
- if not success:
- if options.keep_going:
- failures.append(job.name)
- else:
- return False
- else:
- successes.append(job.name)
- restore_config(options)
- except:
- # Restore the configuration, except in stop-on-error mode if there
- # was an error, where we leave the failing configuration up for
- # developer convenience.
- if options.keep_going:
- restore_config(options)
- raise
- if successes:
- log_line('{} passed'.format(' '.join(successes)), color=colors.bold_green)
- if failures:
- log_line('{} FAILED'.format(' '.join(failures)), color=colors.bold_red)
- return False
- else:
- return True
- def main():
- try:
- parser = argparse.ArgumentParser(
- formatter_class=argparse.RawDescriptionHelpFormatter,
- description=
- "Test Mbed TLS with a subset of algorithms.\n\n"
- "Example usage:\n"
- r"./tests/scripts/depends.py \!MBEDTLS_SHA1_C MBEDTLS_SHA256_C""\n"
- "./tests/scripts/depends.py MBEDTLS_AES_C hashes\n"
- "./tests/scripts/depends.py cipher_id cipher_chaining\n")
- parser.add_argument('--color', metavar='WHEN',
- help='Colorize the output (always/auto/never)',
- choices=['always', 'auto', 'never'], default='auto')
- parser.add_argument('-c', '--config', metavar='FILE',
- help='Configuration file to modify',
- default='include/mbedtls/mbedtls_config.h')
- parser.add_argument('-C', '--directory', metavar='DIR',
- help='Change to this directory before anything else',
- default='.')
- parser.add_argument('-k', '--keep-going',
- help='Try all configurations even if some fail (default)',
- action='store_true', dest='keep_going', default=True)
- parser.add_argument('-e', '--no-keep-going',
- help='Stop as soon as a configuration fails',
- action='store_false', dest='keep_going')
- parser.add_argument('--list-jobs',
- help='List supported jobs and exit',
- action='append_const', dest='list', const='jobs')
- parser.add_argument('--list-domains',
- help='List supported domains and exit',
- action='append_const', dest='list', const='domains')
- parser.add_argument('--make-command', metavar='CMD',
- help='Command to run instead of make (e.g. gmake)',
- action='store', default='make')
- parser.add_argument('--unset-use-psa',
- help='Unset MBEDTLS_USE_PSA_CRYPTO before any test',
- action='store_true', dest='unset_use_psa')
- parser.add_argument('tasks', metavar='TASKS', nargs='*',
- help='The domain(s) or job(s) to test (default: all).',
- default=True)
- options = parser.parse_args()
- os.chdir(options.directory)
- conf = config.ConfigFile(options.config)
- domain_data = DomainData(options, conf)
- if options.tasks is True:
- options.tasks = sorted(domain_data.domains.keys())
- if options.list:
- for arg in options.list:
- for domain_name in sorted(getattr(domain_data, arg).keys()):
- print(domain_name)
- sys.exit(0)
- else:
- sys.exit(0 if run_tests(options, domain_data, conf) else 1)
- except Exception: # pylint: disable=broad-except
- traceback.print_exc()
- sys.exit(3)
- if __name__ == '__main__':
- main()
|