summaryrefslogtreecommitdiffstats
path: root/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/ci/coding_guidelines_check.py
diff options
context:
space:
mode:
Diffstat (limited to 'fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/ci/coding_guidelines_check.py')
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/ci/coding_guidelines_check.py308
1 files changed, 308 insertions, 0 deletions
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/ci/coding_guidelines_check.py b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/ci/coding_guidelines_check.py
new file mode 100644
index 000000000..062614597
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/ci/coding_guidelines_check.py
@@ -0,0 +1,308 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2019 Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+#
+import argparse
+import re
+import pathlib
+import re
+import shlex
+import shutil
+import subprocess
+import sys
+import unittest
+
+CLANG_FORMAT_CMD = "clang-format-12"
+GIT_CLANG_FORMAT_CMD = "git-clang-format-12"
+
+# glob style patterns
+EXCLUDE_PATHS = [
+ "**/.git/*",
+ "**/.github/*",
+ "**/.vscode/*",
+ "**/assembly-script/*",
+ "**/build/*",
+ "**/build-scripts/*",
+ "**/ci/*",
+ "**/core/deps/*",
+ "**/doc/*",
+ "**/samples/wasm-c-api/src/*.*",
+ "**/samples/workload/*",
+ "**/test-tools/wasi-sdk/*",
+ "**/test-tools/IoT-APP-Store-Demo/*",
+ "**/tests/wamr-test-suites/workspace/*",
+ "**/wamr-sdk/*",
+]
+
+C_SUFFIXES = [".c", ".cpp", ".h"]
+INVALID_DIR_NAME_SEGMENT = r"([a-zA-Z0-9]+\_[a-zA-Z0-9]+)"
+INVALID_FILE_NAME_SEGMENT = r"([a-zA-Z0-9]+\-[a-zA-Z0-9]+)"
+
+
+def locate_command(command: str) -> bool:
+ if not shutil.which(command):
+ print(f"Command '{command}'' not found")
+ return False
+
+ return True
+
+
+def is_excluded(path: str) -> bool:
+ path = pathlib.Path(path).resolve()
+ for exclude_path in EXCLUDE_PATHS:
+ if path.match(exclude_path):
+ return True
+ return False
+
+
+def pre_flight_check(root: pathlib) -> bool:
+ def check_aspell(root):
+ return True
+
+ def check_clang_foramt(root: pathlib) -> bool:
+ if not locate_command(CLANG_FORMAT_CMD):
+ return False
+
+ # Quick syntax check for .clang-format
+ try:
+ subprocess.check_output(
+ shlex.split(f"{CLANG_FORMAT_CMD} --dump-config"), cwd=root
+ )
+ except subprocess.CalledProcessError:
+ print(f"Might have a typo in .clang-format")
+ return False
+ return True
+
+ def check_git_clang_format() -> bool:
+ return locate_command(GIT_CLANG_FORMAT_CMD)
+
+ return check_aspell(root) and check_clang_foramt(root) and check_git_clang_format()
+
+
+def run_clang_format(file_path: pathlib, root: pathlib) -> bool:
+ try:
+ subprocess.check_call(
+ shlex.split(
+ f"{CLANG_FORMAT_CMD} --style=file --Werror --dry-run {file_path}"
+ ),
+ cwd=root,
+ )
+ return True
+ except subprocess.CalledProcessError:
+ print(f"{file_path} failed the check of {CLANG_FORMAT_CMD}")
+ return False
+
+
+def run_clang_format_diff(root: pathlib, commits: str) -> bool:
+ """
+ Use `clang-format-12` or `git-clang-format-12` to check code format of
+ the PR, with a commit range specified. It is required to format the
+ code before committing the PR, or it might fail to pass the CI check:
+
+ 1. Install clang-format-12.0.0
+ Normally we can install it by `sudo apt-get install clang-format-12`,
+ or download the `clang+llvm-12.0.0-xxx-tar.xz` package from
+ https://github.com/llvm/llvm-project/releases/tag/llvmorg-12.0.0
+ and install it
+
+ 2. Format the C/C++ source file
+ ``` shell
+ cd path/to/wamr/root
+ clang-format-12 --style file -i path/to/file
+ ```
+
+ The code wrapped by `/* clang-format off */` and `/* clang-format on */`
+ will not be formatted, you shall use them when the formatted code is not
+ readable or friendly:
+
+ ``` cc
+ /* clang-format off */
+ code snippets
+ /* clang-format on */
+ ```
+
+ """
+ try:
+ before, after = commits.split("..")
+ after = after if after else "HEAD"
+ COMMAND = (
+ f"{GIT_CLANG_FORMAT_CMD} -v --binary "
+ f"{shutil.which(CLANG_FORMAT_CMD)} --style file "
+ f"--extensions c,cpp,h --diff {before} {after}"
+ )
+
+ p = subprocess.Popen(
+ shlex.split(COMMAND),
+ stdout=subprocess.PIPE,
+ stderr=None,
+ stdin=None,
+ universal_newlines=True,
+ )
+
+ stdout, _ = p.communicate()
+ if not stdout.startswith("diff --git"):
+ return True
+
+ diff_content = stdout.split("\n")
+ found = False
+ for summary in [x for x in diff_content if x.startswith("diff --git")]:
+ # b/path/to/file -> path/to/file
+ with_invalid_format = re.split("\s+", summary)[-1][2:]
+ if not is_excluded(with_invalid_format):
+ print(f"--- {with_invalid_format} failed on code style checking.")
+ found = True
+ else:
+ return not found
+ except subprocess.subprocess.CalledProcessError:
+ return False
+
+
+def run_aspell(file_path: pathlib, root: pathlib) -> bool:
+ return True
+
+
+def check_dir_name(path: pathlib, root: pathlib) -> bool:
+ m = re.search(INVALID_DIR_NAME_SEGMENT, str(path.relative_to(root).parent))
+ if m:
+ print(f"--- found a character '_' in {m.groups()} in {path}")
+
+ return not m
+
+
+def check_file_name(path: pathlib) -> bool:
+ m = re.search(INVALID_FILE_NAME_SEGMENT, path.stem)
+ if m:
+ print(f"--- found a character '-' in {m.groups()} in {path}")
+
+ return not m
+
+
+def parse_commits_range(root: pathlib, commits: str) -> list:
+ GIT_LOG_CMD = f"git log --pretty='%H' {commits}"
+ try:
+ ret = subprocess.check_output(
+ shlex.split(GIT_LOG_CMD), cwd=root, universal_newlines=True
+ )
+ return [x for x in ret.split("\n") if x]
+ except subprocess.CalledProcessError:
+ print(f"can not parse any commit from the range {commits}")
+ return []
+
+
+def analysis_new_item_name(root: pathlib, commit: str) -> bool:
+ """
+ For any file name in the repo, it is required to use '_' to replace '-'.
+
+ For any directory name in the repo, it is required to use '-' to replace '_'.
+ """
+ GIT_SHOW_CMD = f"git show --oneline --name-status --diff-filter A {commit}"
+ try:
+ invalid_items = True
+ output = subprocess.check_output(
+ shlex.split(GIT_SHOW_CMD), cwd=root, universal_newlines=True
+ )
+ if not output:
+ return True
+
+ NEW_FILE_PATTERN = "^A\s+(\S+)"
+ for line_no, line in enumerate(output.split("\n")):
+ # bypass the first line, usually it is the commit description
+ if line_no == 0:
+ continue
+
+ if not line:
+ continue
+
+ match = re.match(NEW_FILE_PATTERN, line)
+ if not match:
+ continue
+
+ new_item = match.group(1)
+ new_item = pathlib.Path(new_item).resolve()
+
+ if new_item.is_file():
+ if not check_file_name(new_item):
+ invalid_items = False
+ continue
+
+ new_item = new_item.parent
+
+ if not check_dir_name(new_item, root):
+ invalid_items = False
+ continue
+ else:
+ return invalid_items
+
+ except subprocess.CalledProcessError:
+ return False
+
+
+def process_entire_pr(root: pathlib, commits: str) -> bool:
+ if not commits:
+ print("Please provide a commits range")
+ return False
+
+ commit_list = parse_commits_range(root, commits)
+ if not commit_list:
+ print(f"Quit since there is no commit to check with")
+ return True
+
+ print(f"there are {len(commit_list)} commits in the PR")
+
+ found = False
+ if not analysis_new_item_name(root, commits):
+ print(f"{analysis_new_item_name.__doc__}")
+ found = True
+
+ if not run_clang_format_diff(root, commits):
+ print(f"{run_clang_format_diff.__doc__}")
+ found = True
+
+ return not found
+
+
+def main() -> int:
+ parser = argparse.ArgumentParser(
+ description="Check if change meets all coding guideline requirements"
+ )
+ parser.add_argument(
+ "-c", "--commits", default=None, help="Commit range in the form: a..b"
+ )
+ options = parser.parse_args()
+
+ wamr_root = pathlib.Path(__file__).parent.joinpath("..").resolve()
+
+ if not pre_flight_check(wamr_root):
+ return False
+
+ return process_entire_pr(wamr_root, options.commits)
+
+
+# run with python3 -m unitest ci/coding_guidelines_check.py
+class TestCheck(unittest.TestCase):
+ def test_check_dir_name_failed(self):
+ root = pathlib.Path("/root/Workspace/")
+ new_file_path = root.joinpath("core/shared/platform/esp_idf/espid_memmap.c")
+ self.assertFalse(check_dir_name(new_file_path, root))
+
+ def test_check_dir_name_pass(self):
+ root = pathlib.Path("/root/Workspace/")
+ new_file_path = root.joinpath("core/shared/platform/esp-idf/espid_memmap.c")
+ self.assertTrue(check_dir_name(new_file_path, root))
+
+ def test_check_file_name_failed(self):
+ new_file_path = pathlib.Path(
+ "/root/Workspace/core/shared/platform/esp-idf/espid-memmap.c"
+ )
+ self.assertFalse(check_file_name(new_file_path))
+
+ def test_check_file_name_pass(self):
+ new_file_path = pathlib.Path(
+ "/root/Workspace/core/shared/platform/esp-idf/espid_memmap.c"
+ )
+ self.assertTrue(check_file_name(new_file_path))
+
+
+if __name__ == "__main__":
+ sys.exit(0 if main() else 1)