-
Notifications
You must be signed in to change notification settings - Fork 36
Introduce config_checks_generator.py #196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Introduce config_checks_generator.py #196
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty good to me, just a few minor points/thoughts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have some minor comments at the design. I won't specifically request changes, but I would like to discuss them.
Otherwise the code is sensibe and does functioanlly what is expected to do
Use the given prefix for auxiliary macro names. | ||
""" | ||
methods = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure if declaring a dictionary just to use it as an enum map is neccessary. Since we are matching the names we could get away with something like
method = getattr(self, position.name.lower())
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's shorter but I don't think it's clearer. And it's not type-safe. So I don't see it as better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general I would rather we refrain from using enums in python until we upgrade to 3.10 and have match, unless:
- It is clearly an object that is meant to allign with an enum already in C
- We save time and complexity
- We need to refer to them using their name, or number, or iterate on their items in sequence.
Otherwise we are just adding complexity without much benefit. My proposal was geared towards implemeting 2.
Either way I won't block this Pr for the choice of tooling.
|
||
def __init__(self, name: str, version: str, suggestion: str = '') -> None: | ||
super().__init__(name, suggestion) | ||
self.version = version |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would include the version in the Checker class, as an optional parameter and forgo the inheritance completely and put the subclass as an attribute which defines how the affected method change.
e.g
class Checker:
"""Description of checks for one option.
By default, this class triggers an error if the option is set after
def __init__(self, name: str, suggestion: str = '') -> None:
self.name = name
self.suggestion = suggestion
self.version = version
self.checker_type = self.determine_type(name, suggestion, version)
Of-course this seems to be the first of many so you have better scope of what this should do in its final form. I just suggest that if we could reduce complexity it would be worth it.
For clarity what I propose when invoked would look like:
from mbedtls_framework.config_checks_generator import * \
#pylint: disable=wildcard-import,unused-wildcard-import
MBEDTLS_CHECKS = BranchData(
header_directory='library',
header_prefix='mbedtls_',
project_cpp_prefix='MBEDTLS',
checkers=[
checker('MBEDTLS_KEY_EXCHANGE_RSA_ENABLED', 'Mbed TLS 4.0', check_for="Removed")
],
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of-course this seems to be the first of many so you have better scope of what this should do in its final form. I just suggest that if we could reduce complexity it would be worth it.
I'm not sure but I suspect that it only looks like it could be simpler because the classes here aren't the full story. Can you please take a look at #164 with the added classes (not ready for review yet, but I'm not planning any more changes to that part before 1.0), and see if your comment is still applicable there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see your point. Using inheritance may be the simplest and easier to maintain approach.
code, flags=re.M) | ||
|
||
|
||
class BranchData(typing.NamedTuple): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an immutable object, that is used as the source of thruth for the whole logic. I would consider using a dataclass
@dataclass(frozen=True)
class BranchData:
p.s in that case we can also use the post_init to do input sanitatisation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would be the benefits of a dataclass over a NamedTuple?
I only foresee a single place in each repository where we'll create an instance of that class, so I don't think we need to do any input sanitization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not much in that case, and depends on how we wish to use that.
If that a small immutable, input object, named.tuple is the best choice. If in the future there are plans to do things like conditional immutability, or input checking, then dataclass allows you to attach those extra functionalities.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a small immutable, input object
Right, here this is exactly what it is.
for position in Position: | ||
generator = HeaderGenerator(branch_data, position) | ||
if list_only: | ||
print(os.path.join(directory, generator.output_file_name())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the companion pr
COMMAND
${TF_PSA_CRYPTO_PYTHON_EXECUTABLE}
${TF_PSA_CRYPTO_DIR}/scripts/generate_config_checks.py
--list ""
WORKING_DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}/..
OUTPUT_VARIABLE
TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS)
# Turn newline-terminated non-empty list into semicolon-separated list.
string(REPLACE "\n" ";"
TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS "${TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS}")
string(REGEX REPLACE ";\$" ""
TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS "${TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS}")
# Prepend the binary dir to all element of TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS,
# using features that exist in CMake 3.5.1.
string(REPLACE ";" ";${CMAKE_CURRENT_BINARY_DIR}/"
TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS
"${TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS}")
set(TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS
"${CMAKE_CURRENT_BINARY_DIR}/${TF_PSA_CRYPTO_GENERATED_CONFIG_CHECKS_HEADERS}")
It could make sense to do this formatting in Pyhton rather than cmake?
maybe rename list_only to list_human, and add a new list_cmake for the properly formatted output?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, good point. Especially since the old CMake version on the CI lacks a lot of string manipulation features. We already have scripts with a --list-for-cmake
option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for adding this. I was thinking about it. and it would be nice ( not now, when we have bandwith ) to standardize it across the libraries and our scripting.
The need:
To differentiate between a user calling a python script, and the build system calling it.
Proposal:
- We agree on a common data format, and an api that cmake can consume by default.
- We add a boolean optional, disabled by default option to all scripts
--cmake
- We implement the changes, and remove complexity from the cmake side, only leaving behind a minimal set of common parsing utility methods.
If you agree it would be usefull I could make an issue.
But that is way beyond the scope the 1.0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good, but also, sounds like the kind of grand refactoring that we'll never find the time to do 😢
Infrastructure to generate config check headers, to be included in `${PROJECT}_config.c`. This commit creates a module with the core logic, and support for three generated files, to be included before the user config, just after the user config, and after finalizing the user config. This commit provides a basic `Checker` class. Future commits will add derived classes for common cases such as options set in the wrong project. This module is meant to be used in an executable script in each project, containing the project-specific names to use and the list of options. Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
For the time being, only do this if the generation script `scripts/generate_config_checks.py` exists in the consuming repository. This way we can use this framework revision before the scripts are added to the consuming repositories. Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
Similar to `generate_*_tests.py`, let Python rather than Cmake worry about constructing a CMake list. Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
9bcb4d0
to
7ca97be
Compare
This branch was too old to pass the CI, so I rebased in on top of the head of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks!
Infrastructure to generate config check headers, to be included in
${PROJECT}_config.c
. This is just some basic logic, there will be a follow-up with more sophisticated check.Contributes to Mbed-TLS/mbedtls#10147. See #164 for a the next step.
PR checklist
Please add the numbers (or links) of the associated pull requests for consuming branches. You can omit branches where this pull request is not needed.