mirror of
https://github.com/Mbed-TLS/mbedtls-framework.git
synced 2026-09-08 03:09:54 +00:00
test_driver.py: Add support for the list-vars-for-cmake option
Signed-off-by: Ronald Cron <[email protected]>
This commit is contained in:
@@ -12,7 +12,7 @@ import subprocess
|
||||
|
||||
from fnmatch import fnmatch
|
||||
from pathlib import Path
|
||||
from typing import Iterable, Match, Optional, Set
|
||||
from typing import Iterable, List, Match, Optional, Set
|
||||
|
||||
def get_parsearg_base() -> argparse.ArgumentParser:
|
||||
""" Get base arguments for scripts building a TF-PSA-Crypto test driver """
|
||||
@@ -26,6 +26,11 @@ def get_parsearg_base() -> argparse.ArgumentParser:
|
||||
" - If relative, interpreted relative to the repository root.\n")
|
||||
parser.add_argument("--driver", default="libtestdriver1", metavar="DRIVER",
|
||||
help="Test driver name (default: %(default)s).")
|
||||
parser.add_argument('--list-vars-for-cmake', nargs="?", const="__AUTO__", metavar="FILE",
|
||||
help="Generate a file to be included from a CMakeLists.txt.\n"
|
||||
"The file defines CMake list variables with the script's\n"
|
||||
"inputs/outputs files. If FILE is omitted, the output \n"
|
||||
"name defaults to '<DRIVER>-list-vars.cmake'.")
|
||||
return parser
|
||||
|
||||
def iter_code_files(root: Path) -> Iterable[Path]:
|
||||
@@ -38,6 +43,40 @@ def iter_code_files(root: Path) -> Iterable[Path]:
|
||||
for ext in (".c", ".h"):
|
||||
yield from directory_path.rglob(f"*{ext}")
|
||||
|
||||
def get_src_relpaths(builtin: Path, exclude_files: Set[str]) -> List[Path]:
|
||||
"""
|
||||
Return the relative paths of all *.c and *.h files under `builtin`,
|
||||
excluding those whose names match any of the patterns in `exclude_files`.
|
||||
|
||||
The returned paths are relative to `builtin`.
|
||||
"""
|
||||
|
||||
out = []
|
||||
for file in iter_code_files(builtin):
|
||||
if not any(fnmatch(file.name, pattern) for pattern in exclude_files):
|
||||
out.append(file.relative_to(builtin))
|
||||
out.sort()
|
||||
return out
|
||||
|
||||
def get_dst_relpaths(src_relpaths: List[Path], driver: str) -> List[Path]:
|
||||
"""
|
||||
Return the relative paths of the *.c and *.h files generated by the script.
|
||||
|
||||
These paths are the same as in `src_relpaths`, except that occurrences of
|
||||
`mbedtls` in `include/mbedtls/...` paths are replaced with `driver`.
|
||||
|
||||
The returned paths are relative to `dst_dir`.
|
||||
"""
|
||||
|
||||
out = []
|
||||
for path in src_relpaths:
|
||||
parts = list(path.parts)
|
||||
if parts[0] == "include" and parts[1] == "mbedtls":
|
||||
parts[1] = driver
|
||||
out.append(Path(*parts))
|
||||
|
||||
return out
|
||||
|
||||
def run_ctags(file: Path) -> Set[str]:
|
||||
"""
|
||||
Extract the C identifiers in `file` using ctags.
|
||||
@@ -71,20 +110,65 @@ def run_ctags(file: Path) -> Set[str]:
|
||||
|
||||
class TestDriverGenerator:
|
||||
"""A TF-PSA-Crypto test driver generator"""
|
||||
def __init__(self, dst_dir: Path, driver: str):
|
||||
def __init__(self, src_dir: Path, dst_dir: Path, driver: str, \
|
||||
exclude_files: Optional[Set[str]] = None) -> None:
|
||||
"""
|
||||
Initialize a test driver generator.
|
||||
|
||||
Args:
|
||||
src_dir (Path):
|
||||
Path to the source directory that contains the built-in driver.
|
||||
If this path is relative, it should be relative to the repository
|
||||
root so that the source paths returned by `write_list_vars_for_cmake`
|
||||
are correct.
|
||||
|
||||
The source directory is expected to contain:
|
||||
- an `include` directory
|
||||
- an `src` directory
|
||||
- the `include/` directory contains exactly one subdirectory
|
||||
|
||||
dst_dir (Path):
|
||||
Path to the destination directory where the rewritten tree will
|
||||
be created.
|
||||
|
||||
driver (str):
|
||||
Name of the driver. This is used as a prefix when rewritting
|
||||
the tree.
|
||||
|
||||
exclude_files (Optional[Set[str]]):
|
||||
Glob patterns for the basename of the files to be excluded from
|
||||
the source directory.
|
||||
"""
|
||||
self.src_dir = src_dir
|
||||
self.dst_dir = dst_dir
|
||||
self.driver = driver
|
||||
self.exclude_files = set()
|
||||
if exclude_files is not None:
|
||||
self.exclude_files = exclude_files
|
||||
# Path of 'dst_dir'/include/'driver'
|
||||
self.test_driver_include_dir = None #type: Path | None
|
||||
|
||||
def build_tree(self, src_dir: Path, exclude_files: Optional[Set[str]] = None) -> None:
|
||||
"""
|
||||
Build a test driver tree from `src_dir`.
|
||||
if not (src_dir / "include").is_dir():
|
||||
raise RuntimeError(f'"include" directory in {src_dir} not found')
|
||||
|
||||
The source directory `src_dir` is expected to have the following structure:
|
||||
- an `include` directory
|
||||
- an `src` directory
|
||||
- the `include` directory contains exactly one subdirectory
|
||||
if not (src_dir / "src").is_dir():
|
||||
raise RuntimeError(f'"src" directory in {src_dir} not found')
|
||||
|
||||
def write_list_vars_for_cmake(self, fname: str) -> None:
|
||||
src_relpaths = get_src_relpaths(self.src_dir, self.exclude_files)
|
||||
with open(self.dst_dir / fname, "w") as f:
|
||||
f.write(f"set({self.driver}_input_files " + \
|
||||
" ".join(str(path) for path in src_relpaths) + ")\n\n")
|
||||
f.write(f"set({self.driver}_files " + \
|
||||
" ".join(str(path) \
|
||||
for path in get_dst_relpaths(src_relpaths, self.driver)) + ")\n\n")
|
||||
f.write(f"set({self.driver}_src_files " + \
|
||||
" ".join(str(path) \
|
||||
for path in src_relpaths if path.suffix == ".c") + ")")
|
||||
|
||||
def build_tree(self) -> None:
|
||||
"""
|
||||
Build a test driver tree from `self.src_dir`.
|
||||
|
||||
Only the `include` and `src` directories from `src_dir` are used to build
|
||||
the test driver tree, and their directory structure is preserved.
|
||||
@@ -95,14 +179,9 @@ class TestDriverGenerator:
|
||||
The subdirectory inside `include` is renamed to `driver` in the test driver
|
||||
tree, and header inclusions are adjusted accordingly.
|
||||
"""
|
||||
include = src_dir / "include"
|
||||
if not include.is_dir():
|
||||
raise RuntimeError(f'Do not find "include" directory in {src_dir}')
|
||||
|
||||
src = src_dir / "src"
|
||||
if not src.is_dir():
|
||||
raise RuntimeError(f'Do not find "src" directory in {src_dir}')
|
||||
|
||||
include = self.src_dir / "include"
|
||||
entries = list(include.iterdir())
|
||||
if len(entries) != 1 or not entries[0].is_dir():
|
||||
raise RuntimeError(f"Found more than one directory in {include}")
|
||||
@@ -115,13 +194,10 @@ class TestDriverGenerator:
|
||||
if (self.dst_dir / "src").exists():
|
||||
shutil.rmtree(self.dst_dir / "src")
|
||||
|
||||
if exclude_files is None:
|
||||
exclude_files = set()
|
||||
|
||||
for file in iter_code_files(src_dir):
|
||||
if any(fnmatch(file.name, pattern) for pattern in exclude_files):
|
||||
for file in iter_code_files(self.src_dir):
|
||||
if any(fnmatch(file.name, pattern) for pattern in self.exclude_files):
|
||||
continue
|
||||
dst = self.dst_dir / file.relative_to(src_dir)
|
||||
dst = self.dst_dir / file.relative_to(self.src_dir)
|
||||
dst.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.copy2(file, dst)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user