From 88b1c5b91706643e889a19f1fb225730b1e43153 Mon Sep 17 00:00:00 2001 From: PabstMirror Date: Tue, 20 Apr 2021 05:39:05 -0500 Subject: [PATCH] Tools - Add script to check sqf/config with sqfvm (#8137) --- .gitignore | 1 + addons/artillerytables/dev/checkConfigs.sqf | 1 + addons/artillerytables/dev/showShotInfo.sqf | 1 + addons/common/config.cpp | 6 +- addons/medical_ai/stateMachine.sqf | 2 + addons/nametags/config.cpp | 2 +- addons/yardage450/initKeybinds.sqf | 1 - tools/sqfvmChecker.py | 89 +++++++++++++++++++++ 8 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 tools/sqfvmChecker.py diff --git a/.gitignore b/.gitignore index a8f6a13221..52645712a7 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ texHeaders.bin *.biprivatekey Thumbs.db CHANGELOG.md +sqfvm.exe diff --git a/addons/artillerytables/dev/checkConfigs.sqf b/addons/artillerytables/dev/checkConfigs.sqf index 533aecf656..1dfcea7f9f 100644 --- a/addons/artillerytables/dev/checkConfigs.sqf +++ b/addons/artillerytables/dev/checkConfigs.sqf @@ -1,3 +1,4 @@ +//pragma SKIP_COMPILE diag_log text "-------------------------------------------"; INFO("Showing entries with custom configs"); diag_log text "-------------------------------------------"; diff --git a/addons/artillerytables/dev/showShotInfo.sqf b/addons/artillerytables/dev/showShotInfo.sqf index 81a29dca22..aab2f0ef5f 100644 --- a/addons/artillerytables/dev/showShotInfo.sqf +++ b/addons/artillerytables/dev/showShotInfo.sqf @@ -1,3 +1,4 @@ +//pragma SKIP_COMPILE // #include "\z\ace\addons\artillerytables\script_component.hpp" INFO("showing shot info"); diff --git a/addons/common/config.cpp b/addons/common/config.cpp index 557b45b732..6416f244b8 100644 --- a/addons/common/config.cpp +++ b/addons/common/config.cpp @@ -61,9 +61,9 @@ class ACE_Rsc_Control_Base { #include "ACE_Settings.hpp" #include "define.hpp" -#include -#include -#include +#include "ProgressScreen.hpp" +#include "HintConfig.hpp" +#include "RscInfoType.hpp" #include "CompassControl.hpp" #include "CfgUIGrids.hpp" diff --git a/addons/medical_ai/stateMachine.sqf b/addons/medical_ai/stateMachine.sqf index 48d5a6ef8e..03483f4981 100644 --- a/addons/medical_ai/stateMachine.sqf +++ b/addons/medical_ai/stateMachine.sqf @@ -1,3 +1,5 @@ +//pragma SKIP_COMPILE - Inline file + GVAR(stateMachine) = [{call EFUNC(common,getLocalUnits)}, true] call CBA_statemachine_fnc_create; // Add states [statemachine, onState, onStateEntered, onStateLeaving, name] diff --git a/addons/nametags/config.cpp b/addons/nametags/config.cpp index 2db10c7eeb..30b8415787 100644 --- a/addons/nametags/config.cpp +++ b/addons/nametags/config.cpp @@ -19,4 +19,4 @@ class CfgPatches { #include "CfgFactionClasses.hpp" #include "CfgVehicles.hpp" -#include +#include "RscTitles.hpp" diff --git a/addons/yardage450/initKeybinds.sqf b/addons/yardage450/initKeybinds.sqf index fa4f52b6c5..210141a681 100644 --- a/addons/yardage450/initKeybinds.sqf +++ b/addons/yardage450/initKeybinds.sqf @@ -1,4 +1,3 @@ - ["ACE3 Equipment", QGVAR(DistanceKey), LLSTRING(PowerButtonKey), { // Conditions: canInteract diff --git a/tools/sqfvmChecker.py b/tools/sqfvmChecker.py new file mode 100644 index 0000000000..98216563f0 --- /dev/null +++ b/tools/sqfvmChecker.py @@ -0,0 +1,89 @@ +import os +import sys +import subprocess +import concurrent.futures + +addon_base_path = os.path.dirname(os.getcwd()) + +files_to_ignore_lower = [ + x.lower() for x in ["initSettings.sqf", "initKeybinds.sqf", "XEH_PREP.sqf"] +] +sqfvm_exe = os.path.join(addon_base_path, "sqfvm.exe") +virtual_paths = [ + # would need to add more even more to /include to use it + "P:/a3|/a3", # "{}|/a3".format(os.path.join(addon_base_path, "include", "a3")), + "P:/a3|/A3", + "P:/x/cba|/x/cba", + "{}|/z/ace".format(addon_base_path), +] + + +def get_files_to_process(basePath): + arma_files = [] + for root, _dirs, files in os.walk(os.path.join(addon_base_path, "addons")): + for file in files: + if file.endswith(".sqf") or file == "config.cpp": + if file.lower() in files_to_ignore_lower: + continue + filePath = os.path.join(root, file) + arma_files.append(filePath) + return arma_files + + +def process_file(filePath, skipA3Warnings=True): + with open(filePath, "r", encoding="utf-8", errors="ignore") as file: + content = file.read() + if content.startswith("//pragma SKIP_COMPILE"): + return False + cmd = [sqfvm_exe, "--input", filePath, "--parse-only", "--automated"] + for v in virtual_paths: + cmd.append("-v") + cmd.append(v) + # cmd.append("-V") + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, universal_newlines=True) + try: + ret = proc.wait(7) # max wait - seconds + except Exception as _e: + print("sqfvm timed out: {}".format(filePath)) + return True + # print("{} = {}".format(filePath, ret)) + + fileHasError = False + keepReadingLines = True + while keepReadingLines: + line = proc.stdout.readline() + if not line: + keepReadingLines = False + else: + line = line.rstrip() + if line.startswith("[ERR]"): + fileHasError = True + if not ( + skipA3Warnings + and line.startswith("[WRN]") + and ("a3/" in line) + and (("Unexpected IFDEF" in line) or ("defined twice" in line)) + ): + print(" {}".format(line)) + return fileHasError + + +def main(): + if not os.path.isfile(sqfvm_exe): + print("Error: sqfvm.exe not found in base folder [{}]".format(sqfvm_exe)) + return 1 + + error_count = 0 + arma_files = get_files_to_process(addon_base_path) + print("Checking {} files".format(len(arma_files))) + with concurrent.futures.ThreadPoolExecutor(max_workers=12) as executor: + for fileError in executor.map(process_file, arma_files): + if fileError: + error_count += 1 + + print("Errors: {}".format(error_count)) + return error_count + + +if __name__ == "__main__": + sys.exit(main())