Files
mbedtls-framework/scripts/mbedtls_framework/generated_files.py
T
Ronald Cron 042e954d7d make_generated_files.py: Split data from code
Initial work to eventually have the list of
scripts that generate files in the branches
that consume the framework.

Signed-off-by: Ronald Cron <ronald.cron@arm.com>
2026-01-26 15:54:59 +01:00

168 lines
6.5 KiB
Python

"""Generic code to generate, check and list the generated files
"""
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
import argparse
import filecmp
import shutil
import subprocess
import sys
from pathlib import Path
from typing import List, Optional
class GenerationScript:
"""
Representation of a script generating a configuration independent file.
"""
# pylint: disable=too-few-public-methods,too-many-arguments
def __init__(self, script: Path, files: List[Path],
output_dir_option: Optional[str] = None,
output_file_option: Optional[str] = None,
optional: bool = False) -> None:
# Path from the root of Mbed TLS or TF-PSA-Crypto of the generation script
self.script = script
# Executable to run the script, needed for Windows
if script.suffix == ".py":
self.exe = sys.executable
elif script.suffix == ".pl":
self.exe = "perl"
# List of the default paths from the Mbed TLS or TF-PSA-Crypto root of the
# files the script generates.
self.files = files
# Output directory script argument. Can be an empty string in case it is a
# positional argument.
self.output_dir_option = output_dir_option
# Output file script argument. Can be an empty string in case it is a
# positional argument.
self.output_file_option = output_file_option
# Optional files are skipped in --check mode if they don't exist.
# This normally shouldn't happen, but it can happen during transition
# periods where we're adding a new script or a new file, and a
# consuming repository hasn't been updated yet.
self.optional = optional
def get_generation_script_files(generation_script: str) -> List[Path]:
"""
Get the list of the default paths of the files that a given script
generates. It is assumed that the script supports the "--list" option.
"""
files = []
if generation_script.endswith(".py"):
cmd = [sys.executable]
elif generation_script.endswith(".pl"):
cmd = ["perl"]
cmd += [generation_script, "--list"]
output = subprocess.check_output(cmd, universal_newlines=True)
for line in output.splitlines():
files.append(Path(line))
return files
def get_generated_files(generation_scripts: List[GenerationScript]) -> List[Path]:
"""
List the generated files in Mbed TLS or TF-PSA-Crypto. The path from root
is returned for each generated files.
"""
files = []
for generation_script in generation_scripts:
files += generation_script.files
return files
def make_generated_files(generation_scripts: List[GenerationScript]) -> None:
"""
Generate the configuration independent files in their default location in
the Mbed TLS or TF-PSA-Crypto tree.
"""
for generation_script in generation_scripts:
subprocess.run([generation_script.exe, str(generation_script.script)], check=True)
def check_generated_files(generation_scripts: List[GenerationScript],
root: Path) -> bool:
"""
Check that the given root directory contains the generated files as expected/
generated by this script.
"""
ok = True
for generation_script in generation_scripts:
for file in generation_script.files:
file = root / file
if not file.exists():
# If the script is just being added, allow its files not
# to exist. This can happen, at least, when adding a new
# generation script in crypto: until mbedtls is updated,
# the files from that script won't be present when
# the updated crypto is built from mbedtls development.
if generation_script.optional:
continue
raise Exception(f"Expected generated file does not exist: {file}")
bak_file = file.with_name(file.name + ".bak")
if bak_file.exists():
bak_file.unlink()
file.rename(bak_file)
command = [generation_script.exe, str(generation_script.script)]
if generation_script.output_dir_option is not None:
command += [generation_script.output_dir_option,
str(root / Path(generation_script.files[0].parent))]
elif generation_script.output_file_option is not None:
command += generation_script.output_file_option.split()
command += [str(root / Path(generation_script.files[0]))]
subprocess.run([item for item in command if item.strip()], check=True)
for file in generation_script.files:
file = root / file
bak_file = file.with_name(file.name + ".bak")
if generation_script.optional and not bak_file.exists():
# This file is optional and didn't exist before, so
# there's nothing to compare to, or clean up.
continue
if not filecmp.cmp(file, bak_file):
ok = False
ref_file = file.with_name(file.name + ".ref")
ref_file = root / ref_file
if ref_file.exists():
ref_file.unlink()
shutil.copy(file, ref_file)
print(f"Generated file {file} not identical to the reference one {ref_file}.")
file.unlink()
bak_file.rename(file)
return ok
def main(generation_scripts: List[GenerationScript]) -> int:
"""
Main function of this program
"""
parser = argparse.ArgumentParser()
parser.add_argument('--list', action='store_true',
default=False, help='List generated files.')
parser.add_argument('--root', metavar='DIR',
help='Root of the tree containing the generated files \
to check (default: Mbed TLS or TF-PSA-Cryto root.)')
parser.add_argument('--check', action='store_true',
default=False, help='Check the generated files in root')
args = parser.parse_args()
if args.list:
files = get_generated_files(generation_scripts)
for file in files:
print(str(file))
return 0
elif args.check:
ok = check_generated_files(generation_scripts, Path(args.root or "."))
return 0 if ok else 1
else:
make_generated_files(generation_scripts)
return 0 # Any error causes an exception