diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 2690c6bb8..927417f98 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,17 +9,15 @@ on: jobs: clang-format: - runs-on: ubuntu-20.04 # latest + runs-on: ubuntu-24.04 # latest steps: - name: Checkout Sources - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: clang-format lint - uses: DoozyX/clang-format-lint-action@v0.3.1 - with: - # List of extensions to check - extensions: c,h + run: | + ./format-check.py autopep8: runs-on: ubuntu-20.04 # latest diff --git a/format-check.py b/format-check.py new file mode 100755 index 000000000..f9c17bdbe --- /dev/null +++ b/format-check.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +import argparse +import os +from pathlib import Path +import re +from subprocess import list2cmdline, run +from tempfile import NamedTemporaryFile + +CLANG_FORMAT_VERSION = '18.1.6' + +INCLUDE_REGEX = re.compile(r'^source/.*\.(c|h)$') +EXCLUDE_REGEX = re.compile(r'^$') + +arg_parser = argparse.ArgumentParser(description="Check with clang-format") +arg_parser.add_argument('-i', '--inplace-edit', action='store_true', + help="Edit files inplace") +args = arg_parser.parse_args() + +os.chdir(Path(__file__).parent) + +# create file containing list of all files to format +filepaths_file = NamedTemporaryFile(delete=False) +for dirpath, dirnames, filenames in os.walk('.'): + for filename in filenames: + # our regexes expect filepath to use forward slash + filepath = Path(dirpath, filename).as_posix() + if not INCLUDE_REGEX.match(filepath): + continue + if EXCLUDE_REGEX.match(filepath): + continue + + filepaths_file.write(f"{filepath}\n".encode()) +filepaths_file.close() + +# use pipx to run clang-format from PyPI +# this is a simple way to run the same clang-format version regardless of OS +cmd = ['pipx', 'run', f'clang-format=={CLANG_FORMAT_VERSION}', + f'--files={filepaths_file.name}'] +if args.inplace_edit: + cmd += ['-i'] +else: + cmd += ['--Werror', '--dry-run'] + +print(f"{Path.cwd()}$ {list2cmdline(cmd)}") +if run(cmd).returncode: + exit(1) diff --git a/format-check.sh b/format-check.sh deleted file mode 100755 index fce95eabc..000000000 --- a/format-check.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash - -if [[ -z $CLANG_FORMAT ]] ; then - CLANG_FORMAT=clang-format -fi - -if NOT type $CLANG_FORMAT 2> /dev/null ; then - echo "No appropriate clang-format found." - exit 1 -fi - -FAIL=0 -SOURCE_FILES=`find source -type f \( -name '*.h' -o -name '*.c' \)` -for i in $SOURCE_FILES -do - $CLANG_FORMAT -output-replacements-xml $i | grep -c " /dev/null - if [ $? -ne 1 ] - then - echo "$i failed clang-format check." - FAIL=1 - fi -done - -exit $FAIL diff --git a/guides/dev/README.md b/guides/dev/README.md index 9fda4c7c0..39dc0189e 100644 --- a/guides/dev/README.md +++ b/guides/dev/README.md @@ -179,10 +179,11 @@ the code is formatted correctly. `autopep8` is used for python code. You installed this earlier via `requirements-dev.txt`. -For C code `clang-format` is used (specifically version 9). -To install this on Mac using homebrew, run: +For C code `clang-format` is used. You need to install an exact version (see `CLANG_FORMAT_VERSION=...` line at the top of [format-check.py](../../format-check.py)) via [pipx](https://github.com/pypa/pipx). Doing this on MacOS looks like: ```sh -(.venv) $ brew install llvm@9 +(.venv) $ brew install pipx +(.venv) $ pipx ensurepath +(.venv) $ pipx install clang-format== ``` Use helper scripts to automatically format your code (or configure your IDE to do it): @@ -194,7 +195,7 @@ Use helper scripts to automatically format your code (or configure your IDE to d (.venv) $ python3 scripts/format-python.py # just format C files -(.venv) $ python3 scripts/format-c.py +(.venv) $ python3 format-check.py -i ``` ## Using an IDE diff --git a/scripts/format-all.py b/scripts/format-all.py index a185d3669..ec816f028 100755 --- a/scripts/format-all.py +++ b/scripts/format-all.py @@ -3,5 +3,5 @@ utils.chdir_project_root() -utils.run('python3 scripts/format-c.py') +utils.run('python3 format-check.py -i') utils.run('python3 scripts/format-python.py') diff --git a/scripts/format-c.py b/scripts/format-c.py deleted file mode 100755 index d52a1c8e6..000000000 --- a/scripts/format-c.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python3 -import utils -import glob - -FILE_PATTERNS = [ - 'source/**/*.h', - 'source/**/*.c', -] - -utils.chdir_project_root() - -files = [] -for pattern in FILE_PATTERNS: - files.extend(glob.glob(pattern, recursive=True)) - -utils.run(['clang-format', '-i', *files]) diff --git a/source/module.c b/source/module.c index 0648957e5..983054e79 100644 --- a/source/module.c +++ b/source/module.c @@ -364,7 +364,8 @@ PyObject *PyErr_AwsLastError(void) { } #define AWS_DEFINE_ERROR_INFO_CRT(CODE, STR) \ - [(CODE)-AWS_ERROR_ENUM_BEGIN_RANGE(AWS_CRT_PYTHON_PACKAGE_ID)] = AWS_DEFINE_ERROR_INFO(CODE, STR, "aws-crt-python") + [(CODE) - AWS_ERROR_ENUM_BEGIN_RANGE(AWS_CRT_PYTHON_PACKAGE_ID)] = \ + AWS_DEFINE_ERROR_INFO(CODE, STR, "aws-crt-python") /* clang-format off */ static struct aws_error_info s_errors[] = { @@ -655,8 +656,7 @@ static void s_install_crash_handler(void) { * Definitions ******************************************************************************/ -#define AWS_PY_METHOD_DEF(NAME, FLAGS) \ - { #NAME, aws_py_##NAME, (FLAGS), NULL } +#define AWS_PY_METHOD_DEF(NAME, FLAGS) {#NAME, aws_py_##NAME, (FLAGS), NULL} static PyMethodDef s_module_methods[] = { /* Common */ diff --git a/source/mqtt5_client.c b/source/mqtt5_client.c index bcedffaf4..243af6a0e 100644 --- a/source/mqtt5_client.c +++ b/source/mqtt5_client.c @@ -272,7 +272,9 @@ static void s_on_publish_received(const struct aws_mqtt5_packet_publish_view *pu /* i */ (int)(publish_packet->payload_format ? *publish_packet->payload_format : 0), /* O */ publish_packet->message_expiry_interval_seconds ? Py_True : Py_False, /* I */ - (unsigned int)(publish_packet->message_expiry_interval_seconds ? *publish_packet->message_expiry_interval_seconds : 0), + (unsigned int)(publish_packet->message_expiry_interval_seconds + ? *publish_packet->message_expiry_interval_seconds + : 0), /* O */ publish_packet->topic_alias ? Py_True : Py_False, /* H */ (unsigned short)(publish_packet->topic_alias ? *publish_packet->topic_alias : 0), /* s */ publish_packet->response_topic ? publish_packet->response_topic->ptr : NULL, @@ -544,7 +546,9 @@ static void s_lifecycle_event_disconnection( /* i */ (int)(disconnect ? disconnect->reason_code : 0), /* O */ (disconnect && disconnect->session_expiry_interval_seconds) ? Py_True : Py_False, /* I */ - (unsigned int)((disconnect && disconnect->session_expiry_interval_seconds) ? *disconnect->session_expiry_interval_seconds : 0), + (unsigned int)((disconnect && disconnect->session_expiry_interval_seconds) + ? *disconnect->session_expiry_interval_seconds + : 0), /* s */ (disconnect && disconnect->reason_string) ? disconnect->reason_string->ptr : NULL, /* # */ (disconnect && disconnect->reason_string) ? disconnect->reason_string->len : 0, /* O */ user_property_count > 0 ? user_properties_list : Py_None,