From 088b74119ce32523d54ec2addb53bf8089ba0749 Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Fri, 5 Sep 2025 10:25:18 +0200 Subject: [PATCH 1/6] Make analyzers optional, add cppcheck --- src/code_checker.bzl | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/code_checker.bzl b/src/code_checker.bzl index 2d0c81b4..7503f9d8 100644 --- a/src/code_checker.bzl +++ b/src/code_checker.bzl @@ -41,6 +41,21 @@ cp $DATA_DIR/*_clangsa_*.plist $CLANGSA_PLIST """ +def _get_analyzers(options): + pattern = r"--analyzers" + analyzers_raw_string = "" + for s in options: + if s.startswith(pattern): + analyzers_raw_string = s + break + if analyzers_raw_string == "": + return [] + analyzers = [] + analyzers_raw_string = analyzers_raw_string.removeprefix("--analyzers") + analyzers = analyzers_raw_string.strip("= ").split(" ") + return analyzers + + def _run_code_checker( ctx, src, @@ -53,17 +68,27 @@ def _run_code_checker( # Define Plist and log file names data_dir = ctx.attr.name + "/data" file_name_params = (data_dir, src.path.replace("/", "-")) + analyzers = _get_analyzers(options) clang_tidy_plist_file_name = "{}/{}_clang-tidy.plist".format(*file_name_params) clangsa_plist_file_name = "{}/{}_clangsa.plist".format(*file_name_params) + cppcheck_plist_file_name = "{}/{}_cppcheck.plist".format(*file_name_params) codechecker_log_file_name = "{}/{}_codechecker.log".format(*file_name_params) # Declare output files - clang_tidy_plist = ctx.actions.declare_file(clang_tidy_plist_file_name) - clangsa_plist = ctx.actions.declare_file(clangsa_plist_file_name) codechecker_log = ctx.actions.declare_file(codechecker_log_file_name) inputs = [compile_commands_json] + sources_and_headers - outputs = [clang_tidy_plist, clangsa_plist, codechecker_log] + outputs = [codechecker_log] + + if "clangsa" in analyzers: + clangsa_plist = ctx.actions.declare_file(clangsa_plist_file_name) + outputs.append(clangsa_plist) + if "clang-tidy" in analyzers: + clang_tidy_plist = ctx.actions.declare_file(clang_tidy_plist_file_name) + outputs.append(clang_tidy_plist) + if "cppcheck" in analyzers: + cppcheck_plist = ctx.actions.declare_file(cppcheck_plist_file_name) + outputs.append(cppcheck_plist) # Create CodeChecker wrapper script wrapper = ctx.actions.declare_file(ctx.attr.name + "/code_checker.sh") From a1a20ce5cfaa735033bb0ed6030a97ba2d30c98c Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Mon, 8 Sep 2025 09:24:52 +0200 Subject: [PATCH 2/6] Add code_checker_script.py to replace the inline code_checker bash wrapper --- src/BUILD | 5 +- src/code_checker.bzl | 115 ++++++++++++++++--------------------- src/code_checker_script.py | 113 ++++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 67 deletions(-) create mode 100644 src/code_checker_script.py diff --git a/src/BUILD b/src/BUILD index 8a2e5cdb..3d4f8c9e 100644 --- a/src/BUILD +++ b/src/BUILD @@ -7,7 +7,10 @@ py_binary( # Build & Test script template exports_files( - ["codechecker_script.py"], + [ + "codechecker_script.py", + "code_checker_script.py", + ], ) # The following are flags and default values for clang_tidy_aspect diff --git a/src/code_checker.bzl b/src/code_checker.bzl index 7503f9d8..dd5c42ef 100644 --- a/src/code_checker.bzl +++ b/src/code_checker.bzl @@ -4,43 +4,6 @@ load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") -CODE_CHECKER_WRAPPER_SCRIPT = """#!/usr/bin/env bash -#set -x -DATA_DIR=$1 -shift -CLANG_TIDY_PLIST=$1 -shift -CLANGSA_PLIST=$1 -shift -LOG_FILE=$1 -shift -COMPILE_COMMANDS_JSON=$1 -shift -COMPILE_COMMANDS_ABS=$COMPILE_COMMANDS_JSON.abs -sed 's|"directory":"."|"directory":"'$(pwd)'"|g' $COMPILE_COMMANDS_JSON > $COMPILE_COMMANDS_ABS -echo "CodeChecker command: $@" $COMPILE_COMMANDS_ABS > $LOG_FILE -echo "===-----------------------------------------------------===" >> $LOG_FILE -echo " CodeChecker error log " >> $LOG_FILE -echo "===-----------------------------------------------------===" >> $LOG_FILE -eval "$@" $COMPILE_COMMANDS_ABS >> $LOG_FILE 2>&1 -# ls -la $DATA_DIR -# NOTE: the following we do to get rid of md5 hash in plist file names -ret_code=$? -echo "===-----------------------------------------------------===" >> $LOG_FILE -if [ $ret_code -eq 1 ] || [ $ret_code -ge 128 ]; then - echo "===-----------------------------------------------------===" - echo "[ERROR]: CodeChecker returned with $ret_code!" - cat $LOG_FILE - exit 1 -fi -cp $DATA_DIR/*_clang-tidy_*.plist $CLANG_TIDY_PLIST -cp $DATA_DIR/*_clangsa_*.plist $CLANGSA_PLIST - -# sed -i -e "s|.*execroot/bazel_codechecker/||g" $CLANG_TIDY_PLIST -# sed -i -e "s|.*execroot/bazel_codechecker/||g" $CLANGSA_PLIST - -""" - def _get_analyzers(options): pattern = r"--analyzers" analyzers_raw_string = "" @@ -54,7 +17,6 @@ def _get_analyzers(options): analyzers_raw_string = analyzers_raw_string.removeprefix("--analyzers") analyzers = analyzers_raw_string.strip("= ").split(" ") return analyzers - def _run_code_checker( ctx, @@ -68,10 +30,6 @@ def _run_code_checker( # Define Plist and log file names data_dir = ctx.attr.name + "/data" file_name_params = (data_dir, src.path.replace("/", "-")) - analyzers = _get_analyzers(options) - clang_tidy_plist_file_name = "{}/{}_clang-tidy.plist".format(*file_name_params) - clangsa_plist_file_name = "{}/{}_clangsa.plist".format(*file_name_params) - cppcheck_plist_file_name = "{}/{}_cppcheck.plist".format(*file_name_params) codechecker_log_file_name = "{}/{}_codechecker.log".format(*file_name_params) # Declare output files @@ -80,45 +38,49 @@ def _run_code_checker( inputs = [compile_commands_json] + sources_and_headers outputs = [codechecker_log] + analyzers = _get_analyzers(options) + analyzer_output_paths = [] # List of tuples (analyzer_name, plist_path) if "clangsa" in analyzers: + clangsa_plist_file_name = "{}/{}_clangsa.plist".format(*file_name_params) clangsa_plist = ctx.actions.declare_file(clangsa_plist_file_name) + analyzer_output_paths.append(("clangsa", clangsa_plist.path)) outputs.append(clangsa_plist) if "clang-tidy" in analyzers: + clang_tidy_plist_file_name = "{}/{}_clang-tidy.plist".format(*file_name_params) clang_tidy_plist = ctx.actions.declare_file(clang_tidy_plist_file_name) + analyzer_output_paths.append(("clang-tidy", clang_tidy_plist.path)) outputs.append(clang_tidy_plist) if "cppcheck" in analyzers: + cppcheck_plist_file_name = "{}/{}_cppcheck.plist".format(*file_name_params) cppcheck_plist = ctx.actions.declare_file(cppcheck_plist_file_name) + analyzer_output_paths.append(("cppcheck", cppcheck_plist.path)) outputs.append(cppcheck_plist) - # Create CodeChecker wrapper script - wrapper = ctx.actions.declare_file(ctx.attr.name + "/code_checker.sh") - ctx.actions.write( - output = wrapper, + codechecker_options = "" + for item in options: + codechecker_options += item + " " + codechecker_options += "--output=" + data_dir + " " + codechecker_options += "--file=*/" + src.path + + ctx.actions.expand_template( + template = ctx.file._code_checker_script_template, + output = ctx.outputs.code_checker_script, is_executable = True, - content = CODE_CHECKER_WRAPPER_SCRIPT, + substitutions = { + "{PythonPath}": ctx.attr._python_runtime[PyRuntimeInfo].interpreter_path, + "{data_dir}": data_dir, + "{log_file}": codechecker_log.path, + "{compile_commands_json}": compile_commands_json.path, + "{codechecker_args}": codechecker_options, + "{analyzer_output_list}": str(analyzer_output_paths), + }, ) - # Prepare arguments - args = ctx.actions.args() - - # NOTE: we pass: data dir, PList and log file names as first 4 arguments - args.add(data_dir) - args.add(clang_tidy_plist.path) - args.add(clangsa_plist.path) - args.add(codechecker_log.path) - args.add(compile_commands_json.path) - args.add("CodeChecker") - args.add("analyze") - args.add_all(options) - args.add("--output=" + data_dir) - args.add("--file=*/" + src.path) - # Action to run CodeChecker for a file ctx.actions.run( inputs = inputs, outputs = outputs, - executable = wrapper, - arguments = [args], + executable = ctx.outputs.code_checker_script, mnemonic = "CodeChecker", use_default_shell_env = True, progress_message = "CodeChecker analyze {}".format(src.short_path), @@ -144,7 +106,6 @@ def check_valid_file_type(src): return False def _rule_sources(ctx): - srcs = [] if hasattr(ctx.rule.attr, "srcs"): for src in ctx.rule.attr.srcs: @@ -315,10 +276,24 @@ def _collect_all_sources_and_headers(ctx): sources_and_headers = all_files + headers.to_list() return sources_and_headers +def _merge_options(default, custom): + """ + Merge command line arguments so that default options can be overridden + """ + final = [] + args_set = [] + for item in custom: + args_set.append(item.split(" ")[0].split("=")[0]) + final.append(item) + for option in default: + if option.split(" ")[0].split("=")[0] not in args_set: + final.append(option) + return final + def _code_checker_impl(ctx): compile_commands_json = _compile_commands_impl(ctx) sources_and_headers = _collect_all_sources_and_headers(ctx) - options = ctx.attr.default_options + ctx.attr.options + options = _merge_options(ctx.attr.default_options, ctx.attr.options) all_files = [compile_commands_json] for target in ctx.attr.targets: if not CcInfo in target: @@ -385,9 +360,17 @@ code_checker_test = rule( ], doc = "List of compilable targets which should be checked.", ), + "_code_checker_script_template": attr.label( + default = ":code_checker_script.py", + allow_single_file = True, + ), + "_python_runtime": attr.label( + default = "@default_python_tools//:py3_runtime", + ), }, outputs = { "test_script": "%{name}/test_script.sh", + "code_checker_script": "%{name}/code_checker_script.py", }, test = True, ) diff --git a/src/code_checker_script.py b/src/code_checker_script.py new file mode 100644 index 00000000..bfd5c234 --- /dev/null +++ b/src/code_checker_script.py @@ -0,0 +1,113 @@ +#!{PythonPath} + +# Copyright 2023 Ericsson AB +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import os +import re +import shutil +import subprocess +import sys + +DATA_DIR: str = "{data_dir}" +ANALYZER_PLIST_PATHS: list[tuple[str, str]] = {analyzer_output_list} +LOG_FILE: str = "{log_file}" +COMPILE_COMMANDS_JSON: str = "{compile_commands_json}" +COMPILE_COMMANDS_ABSOLUTE: str = f"{COMPILE_COMMANDS_JSON}.abs" +CODECHECKER_ARGS: str = "{codechecker_args}" + + +def log(msg: str) -> None: + with open(LOG_FILE, "a") as log_file: + log_file.write(msg) + + +with open(COMPILE_COMMANDS_JSON, "r") as original_file, open( + COMPILE_COMMANDS_ABSOLUTE, "w" +) as new_file: + content = original_file.read() + # Replace '"directory":"."' with the absolute path + # of the current working directory + new_content = content.replace( + '"directory":".', f'"directory":"{os.getcwd()}' + ) + new_file.write(new_content) + +with open(LOG_FILE, "w") as log_file: + log_file.write( + f"CodeChecker command: CodeChecker analyze {CODECHECKER_ARGS} \ +{COMPILE_COMMANDS_ABSOLUTE}\n" + ) + log_file.write( + "===-----------------------------------------------------===\n" + ) + log_file.write( + " CodeChecker error log \n" + ) + log_file.write( + "===-----------------------------------------------------===\n" + ) + +result = subprocess.run( + ["echo", "$PATH"], + shell=True, + env=os.environ, + capture_output=True, + text=True, +) +log(result.stdout) + +codechecker_cmd: list[str] = ( + ["CodeChecker", "analyze"] + + CODECHECKER_ARGS.split() + + [COMPILE_COMMANDS_ABSOLUTE] +) + +try: + with open(LOG_FILE, "a") as log_file: + proc = subprocess.run( + codechecker_cmd, + env=os.environ, + stdout=log_file, + stderr=log_file, + check=True, + ) + ret_code = 0 +except subprocess.CalledProcessError as e: + ret_code = e.returncode + with open(LOG_FILE, "a") as log_file: + log_file.write(e.output.decode() if e.output else "") + +# Log and exit on error +if ret_code == 1 or ret_code >= 128: + print("===-----------------------------------------------------===") + print(f"[ERROR]: CodeChecker returned with {ret_code}!") + with open(LOG_FILE, "r") as log_file: + print(log_file.read()) + sys.exit(1) + +# NOTE: the following we do to get rid of md5 hash in plist file names +# Copy the plist files to the specified destinations +for file in os.listdir(DATA_DIR): + for analyzer_info in ANALYZER_PLIST_PATHS: + if re.search( + rf"_{analyzer_info[0]}_.*\.plist$", file + ) and os.path.isfile(os.path.join(DATA_DIR, file)): + shutil.copy(os.path.join(DATA_DIR, file), analyzer_info[1]) + +# I have conserved this comment from the original bash script +# The sed commands are commented out, so we won't implement them +# # sed -i -e "s|.*execroot/bazel_codechecker/||g" $CLANG_TIDY_PLIST +# # sed -i -e "s|.*execroot/bazel_codechecker/||g" $CLANGSA_PLIST From 14278a67113d23f33f1b0c98e3da2daaf3dd7bd2 Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Mon, 8 Sep 2025 15:50:56 +0200 Subject: [PATCH 3/6] Expand template only once, pass variables as argument instead --- src/code_checker.bzl | 50 ++++++++++++++++++++------------------ src/code_checker_script.py | 11 ++++++--- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/code_checker.bzl b/src/code_checker.bzl index dd5c42ef..5c48a98d 100644 --- a/src/code_checker.bzl +++ b/src/code_checker.bzl @@ -39,48 +39,34 @@ def _run_code_checker( outputs = [codechecker_log] analyzers = _get_analyzers(options) - analyzer_output_paths = [] # List of tuples (analyzer_name, plist_path) + analyzer_output_paths = "" # List of tuples (analyzer_name, plist_path) if "clangsa" in analyzers: clangsa_plist_file_name = "{}/{}_clangsa.plist".format(*file_name_params) clangsa_plist = ctx.actions.declare_file(clangsa_plist_file_name) - analyzer_output_paths.append(("clangsa", clangsa_plist.path)) + analyzer_output_paths += "clangsa," + clangsa_plist.path + ";" outputs.append(clangsa_plist) if "clang-tidy" in analyzers: clang_tidy_plist_file_name = "{}/{}_clang-tidy.plist".format(*file_name_params) clang_tidy_plist = ctx.actions.declare_file(clang_tidy_plist_file_name) - analyzer_output_paths.append(("clang-tidy", clang_tidy_plist.path)) + analyzer_output_paths += "clang-tidy," + clang_tidy_plist.path + ";" outputs.append(clang_tidy_plist) if "cppcheck" in analyzers: cppcheck_plist_file_name = "{}/{}_cppcheck.plist".format(*file_name_params) cppcheck_plist = ctx.actions.declare_file(cppcheck_plist_file_name) - analyzer_output_paths.append(("cppcheck", cppcheck_plist.path)) + analyzer_output_paths += "cppcheck," + cppcheck_plist.path + ";" outputs.append(cppcheck_plist) - codechecker_options = "" - for item in options: - codechecker_options += item + " " - codechecker_options += "--output=" + data_dir + " " - codechecker_options += "--file=*/" + src.path - - ctx.actions.expand_template( - template = ctx.file._code_checker_script_template, - output = ctx.outputs.code_checker_script, - is_executable = True, - substitutions = { - "{PythonPath}": ctx.attr._python_runtime[PyRuntimeInfo].interpreter_path, - "{data_dir}": data_dir, - "{log_file}": codechecker_log.path, - "{compile_commands_json}": compile_commands_json.path, - "{codechecker_args}": codechecker_options, - "{analyzer_output_list}": str(analyzer_output_paths), - }, - ) - # Action to run CodeChecker for a file ctx.actions.run( inputs = inputs, outputs = outputs, executable = ctx.outputs.code_checker_script, + arguments = [ + data_dir, + src.path, + codechecker_log.path, + analyzer_output_paths + ], mnemonic = "CodeChecker", use_default_shell_env = True, progress_message = "CodeChecker analyze {}".format(src.short_path), @@ -290,11 +276,27 @@ def _merge_options(default, custom): final.append(option) return final +def _create_wrapper_script(ctx, options, compile_commands_json): + options_str = "" + for item in options: + options_str += item + " " + ctx.actions.expand_template( + template = ctx.file._code_checker_script_template, + output = ctx.outputs.code_checker_script, + is_executable = True, + substitutions = { + "{PythonPath}": ctx.attr._python_runtime[PyRuntimeInfo].interpreter_path, + "{compile_commands_json}": compile_commands_json.path, + "{codechecker_args}": options_str, + }, + ) + def _code_checker_impl(ctx): compile_commands_json = _compile_commands_impl(ctx) sources_and_headers = _collect_all_sources_and_headers(ctx) options = _merge_options(ctx.attr.default_options, ctx.attr.options) all_files = [compile_commands_json] + _create_wrapper_script(ctx, options, compile_commands_json) for target in ctx.attr.targets: if not CcInfo in target: continue diff --git a/src/code_checker_script.py b/src/code_checker_script.py index bfd5c234..02543e88 100644 --- a/src/code_checker_script.py +++ b/src/code_checker_script.py @@ -21,9 +21,12 @@ import subprocess import sys -DATA_DIR: str = "{data_dir}" -ANALYZER_PLIST_PATHS: list[tuple[str, str]] = {analyzer_output_list} -LOG_FILE: str = "{log_file}" +DATA_DIR: str = sys.argv[1] +FILE_PATH: str = sys.argv[2] +ANALYZER_PLIST_PATHS: list[list[str, str]] = [ + item.split(",") for item in sys.argv[4].split(";") +] +LOG_FILE: str = sys.argv[3] COMPILE_COMMANDS_JSON: str = "{compile_commands_json}" COMPILE_COMMANDS_ABSOLUTE: str = f"{COMPILE_COMMANDS_JSON}.abs" CODECHECKER_ARGS: str = "{codechecker_args}" @@ -72,6 +75,8 @@ def log(msg: str) -> None: codechecker_cmd: list[str] = ( ["CodeChecker", "analyze"] + CODECHECKER_ARGS.split() + + ["--output=" + DATA_DIR] + + ["--file=*/" + FILE_PATH] + [COMPILE_COMMANDS_ABSOLUTE] ) From 1f48124fe51cdad217d1d2be51dd05f1497f088b Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Mon, 8 Sep 2025 16:12:57 +0200 Subject: [PATCH 4/6] Beautify --- src/code_checker_script.py | 147 ++++++++++++++++++++++--------------- 1 file changed, 86 insertions(+), 61 deletions(-) diff --git a/src/code_checker_script.py b/src/code_checker_script.py index 02543e88..4fb7a795 100644 --- a/src/code_checker_script.py +++ b/src/code_checker_script.py @@ -33,84 +33,109 @@ def log(msg: str) -> None: + """ + Append message to the log file + """ with open(LOG_FILE, "a") as log_file: log_file.write(msg) -with open(COMPILE_COMMANDS_JSON, "r") as original_file, open( - COMPILE_COMMANDS_ABSOLUTE, "w" -) as new_file: - content = original_file.read() - # Replace '"directory":"."' with the absolute path - # of the current working directory - new_content = content.replace( - '"directory":".', f'"directory":"{os.getcwd()}' - ) - new_file.write(new_content) +def _create_compile_commands_json_with_absolute_paths(): + """ + Modifies the paths in compile_commands.json to contain the absolute path + of the files. + """ + with open(COMPILE_COMMANDS_JSON, "r") as original_file, open( + COMPILE_COMMANDS_ABSOLUTE, "w" + ) as new_file: + content = original_file.read() + # Replace '"directory":"."' with the absolute path + # of the current working directory + new_content = content.replace( + '"directory":".', f'"directory":"{os.getcwd()}' + ) + new_file.write(new_content) -with open(LOG_FILE, "w") as log_file: - log_file.write( + +def _run_codechecker() -> None: + """ + Runs CodeChecker analyze + """ + log( f"CodeChecker command: CodeChecker analyze {CODECHECKER_ARGS} \ -{COMPILE_COMMANDS_ABSOLUTE}\n" - ) - log_file.write( - "===-----------------------------------------------------===\n" +{COMPILE_COMMANDS_ABSOLUTE} --output={DATA_DIR} --file=*/{FILE_PATH}\n" ) - log_file.write( - " CodeChecker error log \n" + log("===-----------------------------------------------------===\n") + log(" CodeChecker error log \n") + log("===-----------------------------------------------------===\n") + + result = subprocess.run( + ["echo", "$PATH"], + shell=True, + env=os.environ, + capture_output=True, + text=True, ) - log_file.write( - "===-----------------------------------------------------===\n" + log(result.stdout) + + codechecker_cmd: list[str] = ( + ["CodeChecker", "analyze"] + + CODECHECKER_ARGS.split() + + ["--output=" + DATA_DIR] + + ["--file=*/" + FILE_PATH] + + [COMPILE_COMMANDS_ABSOLUTE] ) -result = subprocess.run( - ["echo", "$PATH"], - shell=True, - env=os.environ, - capture_output=True, - text=True, -) -log(result.stdout) - -codechecker_cmd: list[str] = ( - ["CodeChecker", "analyze"] - + CODECHECKER_ARGS.split() - + ["--output=" + DATA_DIR] - + ["--file=*/" + FILE_PATH] - + [COMPILE_COMMANDS_ABSOLUTE] -) - -try: - with open(LOG_FILE, "a") as log_file: - proc = subprocess.run( - codechecker_cmd, - env=os.environ, - stdout=log_file, - stderr=log_file, - check=True, - ) - ret_code = 0 -except subprocess.CalledProcessError as e: - ret_code = e.returncode - with open(LOG_FILE, "a") as log_file: - log_file.write(e.output.decode() if e.output else "") + try: + with open(LOG_FILE, "a") as log_file: + subprocess.run( + codechecker_cmd, + env=os.environ, + stdout=log_file, + stderr=log_file, + check=True, + ) + except subprocess.CalledProcessError as e: + log(e.output.decode() if e.output else "") + if e.returncode == 1 or e.returncode >= 128: + _display_error(e.returncode) + -# Log and exit on error -if ret_code == 1 or ret_code >= 128: +def _display_error(ret_code: int) -> None: + """ + Display the log file, and exit with 1 + """ + # Log and exit on error print("===-----------------------------------------------------===") print(f"[ERROR]: CodeChecker returned with {ret_code}!") with open(LOG_FILE, "r") as log_file: print(log_file.read()) sys.exit(1) -# NOTE: the following we do to get rid of md5 hash in plist file names -# Copy the plist files to the specified destinations -for file in os.listdir(DATA_DIR): - for analyzer_info in ANALYZER_PLIST_PATHS: - if re.search( - rf"_{analyzer_info[0]}_.*\.plist$", file - ) and os.path.isfile(os.path.join(DATA_DIR, file)): - shutil.copy(os.path.join(DATA_DIR, file), analyzer_info[1]) + +def _move_plist_files(): + """ + Move the plist files from the temporary directory to their final destination + """ + # NOTE: the following we do to get rid of md5 hash in plist file names + # Copy the plist files to the specified destinations + for file in os.listdir(DATA_DIR): + for analyzer_info in ANALYZER_PLIST_PATHS: + if re.search( + rf"_{analyzer_info[0]}_.*\.plist$", file + ) and os.path.isfile(os.path.join(DATA_DIR, file)): + shutil.copy(os.path.join(DATA_DIR, file), analyzer_info[1]) + + +def main(): + _create_compile_commands_json_with_absolute_paths() + _run_codechecker() + _move_plist_files() + + +if __name__ == "__main__": + main() + # I have conserved this comment from the original bash script # The sed commands are commented out, so we won't implement them From 9ea1cbeee04b5cade2d8d8e75a2d46846964d926 Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Wed, 10 Sep 2025 08:37:33 +0200 Subject: [PATCH 5/6] Fix incorrect type --- src/code_checker_script.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/code_checker_script.py b/src/code_checker_script.py index 4fb7a795..83fa4238 100644 --- a/src/code_checker_script.py +++ b/src/code_checker_script.py @@ -23,7 +23,7 @@ DATA_DIR: str = sys.argv[1] FILE_PATH: str = sys.argv[2] -ANALYZER_PLIST_PATHS: list[list[str, str]] = [ +ANALYZER_PLIST_PATHS: list[list[str]] = [ item.split(",") for item in sys.argv[4].split(";") ] LOG_FILE: str = sys.argv[3] From 304bf402f151e9e1c23e5e41da272a0884b9efde Mon Sep 17 00:00:00 2001 From: "F.Tibor" Date: Fri, 12 Sep 2025 15:43:25 +0200 Subject: [PATCH 6/6] Add gcc and infer as analyzer --- src/code_checker.bzl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/code_checker.bzl b/src/code_checker.bzl index 5c48a98d..bc38cf40 100644 --- a/src/code_checker.bzl +++ b/src/code_checker.bzl @@ -55,6 +55,16 @@ def _run_code_checker( cppcheck_plist = ctx.actions.declare_file(cppcheck_plist_file_name) analyzer_output_paths += "cppcheck," + cppcheck_plist.path + ";" outputs.append(cppcheck_plist) + if "gcc" in analyzers: + gcc_plist_file_name = "{}/{}_gcc.plist".format(*file_name_params) + gcc_plist = ctx.actions.declare_file(gcc_plist_file_name) + analyzer_output_paths += "gcc," + gcc_plist.path + ";" + outputs.append(gcc_plist) + if "infer" in analyzers: + infer_plist_file_name = "{}/{}_infer.plist".format(*file_name_params) + infer_plist = ctx.actions.declare_file(infer_plist_file_name) + analyzer_output_paths += "infer," + infer_plist.path + ";" + outputs.append(infer_plist) # Action to run CodeChecker for a file ctx.actions.run(