Skip to content
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

Move scripts/code_style.py to the framework #100

Merged
merged 73 commits into from
Dec 18, 2024
Merged
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
0abc1ce
Specify register clobbers in mbedtls_aesni_crypt_ecb()
solardiz Nov 30, 2024
7b51437
Move files out of Mbed TLS
eleuzi01 Nov 19, 2024
d92e24e
Adapt paths for output_env.sh
eleuzi01 Nov 19, 2024
9f54874
Adapt paths for scripts/quiet
eleuzi01 Nov 19, 2024
827e2a9
Update submodule
eleuzi01 Nov 20, 2024
c5f5183
PSA sign/verify: more uniform error on an unsupported hash
gilles-peskine-arm Apr 10, 2024
8a4ff2f
import_not_supported: edge case of unsupported curves
gilles-peskine-arm Apr 10, 2024
070fbca
Add some missing test case dependencies
gilles-peskine-arm Apr 19, 2024
eafc275
Fix edge case with half-supported ECDSA (manual test cases)
gilles-peskine-arm Apr 19, 2024
27c604a
Add missing resource cleanup on test failure
gilles-peskine-arm Nov 20, 2024
de7aae1
PSA interruptible sign/verify: detect unsupported mechanism in start
gilles-peskine-arm Nov 20, 2024
e7e704a
p256-m: allow deterministic ECDSA verification
gilles-peskine-arm Nov 20, 2024
c3e0e8f
Fix copypasta
gilles-peskine-arm Dec 2, 2024
c1fc136
Add Header for mbedtls_psa_ecp_export_public_key_iop_complete()
waleed-elmelegy-arm Dec 3, 2024
af2595b
Add implementation for mbedtls_psa_ecp_export_public_key_iop_complete()
waleed-elmelegy-arm Dec 3, 2024
2cfce63
Fix status variable type in mbedtls_psa_ecp_export_public_key_iop_set…
waleed-elmelegy-arm Dec 3, 2024
4cffd5d
Add implementaion for psa_export_public_key_iop_complete()
waleed-elmelegy-arm Dec 3, 2024
f466a28
Fix checks for key type in psa_export_public_key_iop_setup()
waleed-elmelegy-arm Dec 3, 2024
54ba963
Add interuptible export public-key testing to invalid key tests
waleed-elmelegy-arm Dec 3, 2024
81a5258
Add interuptible export public-key to current export public-key tests
waleed-elmelegy-arm Dec 3, 2024
a04e88a
Fix export public-key opaque key test paramters
waleed-elmelegy-arm Dec 3, 2024
e283ed9
Add testing of complete API of interruptible export public-key
waleed-elmelegy-arm Dec 3, 2024
3c46535
Rename mbedtls_psa_export_public_key_iop_operation_t
waleed-elmelegy-arm Dec 3, 2024
1daabc1
Refactor and improve iop export public-key setup and abort APIs
waleed-elmelegy-arm Dec 9, 2024
c66147d
Refactor & improve internal iop export public-key setup and complete …
waleed-elmelegy-arm Dec 9, 2024
0843214
Remove Invalid import/export key test
waleed-elmelegy-arm Dec 9, 2024
f37cbf8
Update submodule with the merge
eleuzi01 Dec 10, 2024
e330e58
Improve iop export public-key testing
waleed-elmelegy-arm Dec 9, 2024
e9d036a
Merge pull request #9788 from eleuzi01/issue-74-fw
mpg Dec 10, 2024
8392f18
Move build of PSA programs to tf-psa-crypto
ronald-cron-arm Dec 9, 2024
ce3bcf0
Restore 3.6 PSA constants generation check
ronald-cron-arm Dec 9, 2024
cec78c3
libtesdriver1: Copy only scripts from framework
ronald-cron-arm Dec 5, 2024
04baacb
cmake: Try and simplify test_keys/certs.h generation
ronald-cron-arm Dec 6, 2024
f6eee5a
Move test_keys.h to include/test
ronald-cron-arm Dec 9, 2024
5096b4c
Revert "Remove mbedtls_test"
ronald-cron-arm Dec 6, 2024
2654081
Adapt TF-M configurations to config split
ronald-cron-arm Dec 5, 2024
9d262d7
Fix test_ccm_aes_sha256
ronald-cron-arm Dec 6, 2024
b7adf7b
Fix tls13_only
ronald-cron-arm Dec 4, 2024
bfa03a2
Fix build_zeroize_checks
ronald-cron-arm Dec 4, 2024
42ba65d
Fix test_malloc_0_null
ronald-cron-arm Dec 5, 2024
3dd1d3d
Fix test_sha3_variations
ronald-cron-arm Dec 5, 2024
faadfc2
cmake: Remove unnecessary file generation disablement
ronald-cron-arm Dec 7, 2024
9fb40d7
Move PSA documentation to tf-psa-crypto
ronald-cron-arm Dec 9, 2024
bced0c7
Fix check that psa_test_wrappers.[hc] are up to date
ronald-cron-arm Dec 9, 2024
a747fa6
make: Fix psa_constant_names_generated.c generation
ronald-cron-arm Dec 10, 2024
8a09a41
make: Add missing dependency
ronald-cron-arm Dec 10, 2024
54f19e5
Merge pull request #9783 from gilles-peskine-arm/psa-storage-test-cas…
yanesca Dec 10, 2024
4393dff
Specify previously missed XMM register clobbers in AES-NI asm blocks
solardiz Dec 8, 2024
6b2ca18
Add change log entry on AES-NI asm block fixes
solardiz Dec 11, 2024
2d40a24
Update framework to the merge of #99
ronald-cron-arm Dec 11, 2024
f3720c7
Merge pull request #9828 from ronald-cron-arm/finalize-split-preparat…
ronald-cron-arm Dec 11, 2024
99ed26e
Merge pull request #9808 from waleed-elmelegy-arm/add-iop-export-pub-…
paul-elliott-arm Dec 11, 2024
3955d8b
tf-psa-crypto: cmake: Use TF-PSA-Crypto config.py
ronald-cron-arm Nov 22, 2024
f6d17ca
Switch to tf-psa-crypto/build_info.h
ronald-cron-arm Nov 6, 2024
e11ae17
Split check_config.h
ronald-cron-arm Nov 12, 2024
51f228c
Switch to actual TF-PSA-Crypto build_info.h
ronald-cron-arm Nov 6, 2024
45eec22
Remove include as header path
ronald-cron-arm Nov 8, 2024
524f75b
Remove library as header path
ronald-cron-arm Nov 8, 2024
14ace27
tf-psa-crypto: Add cmake_package_install test program
ronald-cron-arm Dec 6, 2024
d98477d
tf-psa-crypto: config.py: Adjust EXCLUDE_FROM_FULL
ronald-cron-arm Dec 11, 2024
fd71abe
cmake: tf-psa-crypto: Add seedfile for testing
ronald-cron-arm Dec 11, 2024
a41d52a
Merge pull request #9831 from ronald-cron-arm/finalize-split-preparat…
ronald-cron-arm Dec 12, 2024
8ef9323
Merge pull request #9809 from solardiz/development
paul-elliott-arm Dec 13, 2024
08d8cc5
Remove tf-psa-crypto directory
ronald-cron-arm Dec 13, 2024
674bd8f
Add tf-psa-crypto module
ronald-cron-arm Dec 11, 2024
27a1ac7
make: Generate test_keys.h in tf-psa-crypto/framework as well
ronald-cron-arm Dec 12, 2024
f25121c
make_generated_files.bat: Generate test_keys.h in tf-psa-crypto/frame…
ronald-cron-arm Dec 12, 2024
4491418
Include all submodules for readthedocs
ronald-cron-arm Dec 16, 2024
8064c02
Add change log
ronald-cron-arm Dec 16, 2024
08909c9
Merge pull request #9852 from ronald-cron-arm/tf-psa-crypto-as-submodule
ronald-cron-arm Dec 16, 2024
e4675f1
Move files into the framework
eleuzi01 Dec 18, 2024
3cb213b
Merge branch 'tmp-branch-move-files-to-framework' into issue-70
eleuzi01 Dec 18, 2024
7b91d1e
Make script work in both branches
eleuzi01 Dec 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
286 changes: 286 additions & 0 deletions scripts/code_style.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
#!/usr/bin/env python3
"""Check or fix the code style by running Uncrustify.

This script must be run from the root of a Git work tree containing Mbed TLS.
"""
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
import argparse
import os
import re
import subprocess
import sys
from typing import FrozenSet, List, Optional
from mbedtls_framework import build_tree

UNCRUSTIFY_SUPPORTED_VERSION = "0.75.1"
CONFIG_FILE = ".uncrustify.cfg"
UNCRUSTIFY_EXE = "uncrustify"
UNCRUSTIFY_ARGS = ["-c", CONFIG_FILE]
CHECK_GENERATED_FILES = "tests/scripts/check-generated-files.sh"

def print_err(*args):
print("Error: ", *args, file=sys.stderr)

# Print the file names that will be skipped and the help message
def print_skip(files_to_skip):
print()
print(*files_to_skip, sep=", SKIP\n", end=", SKIP\n")
print("Warning: The listed files will be skipped because\n"
"they are not known to git.")
print()

# Match FILENAME(s) in "check SCRIPT (FILENAME...)"
CHECK_CALL_RE = re.compile(r"\n\s*check\s+[^\s#$&*?;|]+([^\n#$&*?;|]+)",
re.ASCII)
def list_generated_files() -> FrozenSet[str]:
"""Return the names of generated files.

We don't reformat generated files, since the result might be different
from the output of the generator. Ideally the result of the generator
would conform to the code style, but this would be difficult, especially
with respect to the placement of line breaks in long logical lines.
"""
# Parse check-generated-files.sh to get an up-to-date list of
# generated files. Read the file rather than calling it so that
# this script only depends on Git, Python and uncrustify, and not other
# tools such as sh or grep which might not be available on Windows.
# This introduces a limitation: check-generated-files.sh must have
# the expected format and must list the files explicitly, not through
# wildcards or command substitution.
content = open(CHECK_GENERATED_FILES, encoding="utf-8").read()
checks = re.findall(CHECK_CALL_RE, content)
return frozenset(word for s in checks for word in s.split())

# Check for comment string indicating an auto-generated file
AUTOGEN_RE = re.compile(r"Warning[ :-]+This file is (now )?auto[ -]?generated",
re.ASCII | re.IGNORECASE)
def is_file_autogenerated(filename):
content = open(filename, encoding="utf-8").read()
return AUTOGEN_RE.search(content) is not None

def get_src_files(since: Optional[str]) -> List[str]:
"""
Use git to get a list of the source files.

The optional argument since is a commit, indicating to only list files
that have changed since that commit. Without this argument, list all
files known to git.

Only C files are included, and certain files (generated, or third party)
are excluded.
"""
file_patterns = ["*.[hc]",
"tests/suites/*.function",
"tf-psa-crypto/tests/suites/*.function",
"scripts/data_files/*.fmt"]
output = subprocess.check_output(["git", "ls-files"] + file_patterns,
universal_newlines=True)
src_files = output.split()

# When this script is called from a git hook, some environment variables
# are set by default which force all git commands to use the main repository
# (i.e. prevent us from performing commands on the framework repo).
# Create an environment without these variables for running commands on the
# framework repo.
framework_env = os.environ.copy()
# Get a list of environment vars that git sets
git_env_vars = subprocess.check_output(["git", "rev-parse", "--local-env-vars"],
universal_newlines=True)
# Remove the vars from the environment
for var in git_env_vars.split():
framework_env.pop(var, None)

output = subprocess.check_output(["git", "-C", "framework", "ls-files"]
+ file_patterns,
universal_newlines=True,
env=framework_env)
framework_src_files = output.split()

if since:
# get all files changed in commits since the starting point in ...
# ... the main repository
cmd = ["git", "log", since + "..HEAD", "--ignore-submodules",
"--name-only", "--pretty=", "--"] + src_files
output = subprocess.check_output(cmd, universal_newlines=True)
committed_changed_files = output.split()

# ... the framework submodule
framework_since = get_submodule_hash(since, "framework")
cmd = ["git", "-C", "framework", "log", framework_since + "..HEAD",
"--name-only", "--pretty=", "--"] + framework_src_files
output = subprocess.check_output(cmd, universal_newlines=True,
env=framework_env)
committed_changed_files += ["framework/" + s for s in output.split()]

# and also get all files with uncommitted changes in ...
# ... the main repository
cmd = ["git", "diff", "--name-only", "--"] + src_files
output = subprocess.check_output(cmd, universal_newlines=True)
uncommitted_changed_files = output.split()
# ... the framework submodule
cmd = ["git", "-C", "framework", "diff", "--name-only", "--"] + \
framework_src_files
output = subprocess.check_output(cmd, universal_newlines=True,
env=framework_env)
uncommitted_changed_files += ["framework/" + s for s in output.split()]

src_files = committed_changed_files + uncommitted_changed_files
else:
src_files += ["framework/" + s for s in framework_src_files]

generated_files = list_generated_files()
# Don't correct style for third-party files (and, for simplicity,
# companion files in the same subtree), or for automatically
# generated files (we're correcting the templates instead).
if build_tree.is_mbedtls_3_6():
src_files = [filename for filename in src_files
if not (filename.startswith("3rdparty/") or
filename in generated_files or
is_file_autogenerated(filename))]
else:
src_files = [filename for filename in src_files
if not (filename.startswith("tf-psa-crypto/drivers/everest/") or
filename.startswith("tf-psa-crypto/drivers/p256-m/") or
filename in generated_files or
is_file_autogenerated(filename))]
return src_files

def get_submodule_hash(commit: str, submodule: str) -> str:
"""Get the commit hash of a submodule at a given commit in the Git repository."""
cmd = ["git", "ls-tree", commit, submodule]
output = subprocess.check_output(cmd, universal_newlines=True)
return output.split()[2]

def get_uncrustify_version() -> str:
"""
Get the version string from Uncrustify
"""
result = subprocess.run([UNCRUSTIFY_EXE, "--version"],
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
check=False)
if result.returncode != 0:
print_err("Could not get Uncrustify version:", str(result.stderr, "utf-8"))
return ""
else:
return str(result.stdout, "utf-8")

def check_style_is_correct(src_file_list: List[str]) -> bool:
"""
Check the code style and output a diff for each file whose style is
incorrect.
"""
style_correct = True
for src_file in src_file_list:
uncrustify_cmd = [UNCRUSTIFY_EXE] + UNCRUSTIFY_ARGS + [src_file]
result = subprocess.run(uncrustify_cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, check=False)
if result.returncode != 0:
print_err("Uncrustify returned " + str(result.returncode) +
" correcting file " + src_file)
return False

# Uncrustify makes changes to the code and places the result in a new
# file with the extension ".uncrustify". To get the changes (if any)
# simply diff the 2 files.
diff_cmd = ["diff", "-u", src_file, src_file + ".uncrustify"]
cp = subprocess.run(diff_cmd, check=False)

if cp.returncode == 1:
print(src_file + " changed - code style is incorrect.")
style_correct = False
elif cp.returncode != 0:
raise subprocess.CalledProcessError(cp.returncode, cp.args,
cp.stdout, cp.stderr)

# Tidy up artifact
os.remove(src_file + ".uncrustify")

return style_correct

def fix_style_single_pass(src_file_list: List[str]) -> bool:
"""
Run Uncrustify once over the source files.
"""
code_change_args = UNCRUSTIFY_ARGS + ["--no-backup"]
for src_file in src_file_list:
uncrustify_cmd = [UNCRUSTIFY_EXE] + code_change_args + [src_file]
result = subprocess.run(uncrustify_cmd, check=False)
if result.returncode != 0:
print_err("Uncrustify with file returned: " +
str(result.returncode) + " correcting file " +
src_file)
return False
return True

def fix_style(src_file_list: List[str]) -> int:
"""
Fix the code style. This takes 2 passes of Uncrustify.
"""
if not fix_style_single_pass(src_file_list):
return 1
if not fix_style_single_pass(src_file_list):
return 1

# Guard against future changes that cause the codebase to require
# more passes.
if not check_style_is_correct(src_file_list):
print_err("Code style still incorrect after second run of Uncrustify.")
return 1
else:
return 0

def main() -> int:
"""
Main with command line arguments.
"""
uncrustify_version = get_uncrustify_version().strip()
if UNCRUSTIFY_SUPPORTED_VERSION not in uncrustify_version:
print("Warning: Using unsupported Uncrustify version '" +
uncrustify_version + "'")
print("Note: The only supported version is " +
UNCRUSTIFY_SUPPORTED_VERSION)

parser = argparse.ArgumentParser()
parser.add_argument('-f', '--fix', action='store_true',
help=('modify source files to fix the code style '
'(default: print diff, do not modify files)'))
parser.add_argument('-s', '--since', metavar='COMMIT', const='development', nargs='?',
help=('only check files modified since the specified commit'
' (e.g. --since=HEAD~3 or --since=development). If no'
' commit is specified, default to development.'))
# --subset is almost useless: it only matters if there are no files
# ('code_style.py' without arguments checks all files known to Git,
# 'code_style.py --subset' does nothing). In particular,
# 'code_style.py --fix --subset ...' is intended as a stable ("porcelain")
# way to restyle a possibly empty set of files.
parser.add_argument('--subset', action='store_true',
help='only check the specified files (default with non-option arguments)')
parser.add_argument('operands', nargs='*', metavar='FILE',
help='files to check (files MUST be known to git, if none: check all)')

args = parser.parse_args()

covered = frozenset(get_src_files(args.since))
# We only check files that are known to git
if args.subset or args.operands:
src_files = [f for f in args.operands if f in covered]
skip_src_files = [f for f in args.operands if f not in covered]
if skip_src_files:
print_skip(skip_src_files)
else:
src_files = list(covered)

if args.fix:
# Fix mode
return fix_style(src_files)
else:
# Check mode
if check_style_is_correct(src_files):
print("Checked {} files, style ok.".format(len(src_files)))
return 0
else:
return 1

if __name__ == '__main__':
sys.exit(main())