########################################################################### # # Copyright (c) 2019-2020 Diality Inc. - All Rights Reserved. # # THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN # WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. # # @file build_common_defs.py # # @author (last) Peter Lucia # @date (last) 05-Apr-2021 # @author (original) Peter Lucia # @date (original) 05-Apr-2021 # ############################################################################ import os import subprocess from datetime import datetime def create_enum_file(in_path: str, out_path:str, author: str, code_imports: str, code_class_def: str, as_int=True, custom_defs: dict = {}): """ Generates an enum source code file @param in_path: (str) input txt file @param out_path: (str) output .py file @param author: (str) name of author for header @param code_imports: (str) raw source code as string imports needed for this header file @param code_class_def: (str) raw source code class definition for this enum @param as_int: (bool) if True, output enums as int, if False output as hex @param custom_defs: (dict) custom enums (if mapped to None they are ignored) @return: True upon success, False upon failure """ if os.path.exists(in_path): enums = [] try: with open(in_path, 'r') as f: for line in f: split_str = line.split('=') num = split_str[1].split(",")[0] num = num.replace(",", "").strip() var = split_str[0].strip() if var in custom_defs: if custom_defs[var] is None: print("Ignoring {0}.".format(var)) continue num = custom_defs[var] print("Applied custom mapping {0} = {1}.".format(var, num)) base = 10 if "x" in num.lower(): base = 16 try: if as_int: num = int(num, base) else: num = hex(int(num, base)).upper() enums.append((num, var)) except ValueError as e: print("Skipping {0}: {1}".format(var, e)) except FileNotFoundError as e: print("Error reading in txt file: {0}".format(e)) return False current_time = datetime.now() code_header = \ """########################################################################### # # Copyright (c) 2019-{0} Diality Inc. - All Rights Reserved. # # THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN # WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. # # @file {4} # # @author (last) {3} # @date (last) {2}-{1}-{0} # @author (original) {3} # @date (original) {2}-{1}-{0} # ############################################################################""" \ .format(current_time.strftime("%Y"), current_time.strftime("%b"), current_time.strftime("%d"), author, out_path.split("/")[-1]) # build the resultant source code code_result = code_header code_result += code_imports code_result += code_class_def # pop the enums from the min heap until its empty code = "" for enum in enums: code += " {0} = {1}\n".format(enum[1], enum[0]) code_result += code try: # write the generated file to disk with open(out_path, 'w') as f: f.write(code_result) return True except FileNotFoundError as e: print("Error writing source code: {0}".format(e)) return False else: print("Error: Input file {0} does not exist!".format(in_path)) return False def build_common_defs(dst_alarms_txt: str, dst_common: str, common_branch: str, dst_python: str, author: str, prefix_match: str, cpp_header: str, code_prepend: str, code_class_def: str, as_int: bool, custom_defs: dict = {}, ): """ Driver function to build a common defs .py source file @param dst_alarms_txt: (str) the intermediary txt file to create @param dst_common: (str) where to temporarily clone common @param common_branch: (str) the common branch to clone @param dst_python: (str) the python source file to generate @param author: (str) the author's name to put in the header of the source file @param prefix_match: (str) the prefix token to search for (e.g. ALARM_ID_) @param cpp_header: (str) the cpp header in common to read @param code_prepend: (str) raw source code as string imports needed for this header file @param code_class_def: (str) raw source code class definition for this enum @param as_int: (bool) if True, output enums as int, if False output as hex @param custom_defs: (dict) custom enums (if mapped to None they are ignored) @return: None """ if subprocess.call("bash gen_common_defs.sh {0} {1} {2} {3} {4}" .format(dst_alarms_txt, dst_common, common_branch, prefix_match, cpp_header), shell=True) != 0: print("Failure: Could not generate alarm ids.") return if create_enum_file(dst_alarms_txt, dst_python, author, code_prepend, code_class_def, as_int, custom_defs): print("Created enum file: {0}".format(dst_python)) print("Done.") else: print("Failure: Could not create enum file.") if __name__ == '__main__': common_branch="staging" build_common_defs(dst_alarms_txt="/tmp/AlarmIds.txt", dst_common="/tmp/common", common_branch=common_branch, dst_python=os.path.join(os.path.abspath("../"), "dialin/common/alarm_defs.py"), author="Peter Lucia", prefix_match="ALARM_ID_", cpp_header="AlarmDefs.h", code_prepend= ("\n" "from enum import unique\n" "from ..utils.base import AlarmEnum\n"), code_class_def=("\n\n" "# Branch: {0}\n" "@unique\n" "class AlarmList(AlarmEnum):\n").format(common_branch), as_int=True, ) custom_defs = { "MSG_ID_FIRST_TESTER_MESSAGE": None, "MSG_ID_FIRST_DG_TESTER_MESSAGE": None, "MSG_ID_TESTER_LOGIN_REQUEST": "0x8000", "MSG_ID_DG_TESTER_LOGIN_REQUEST": "0xA000", } build_common_defs(dst_alarms_txt="/tmp/MsgDefs.txt", dst_common="/tmp/common", common_branch=common_branch, dst_python=os.path.join(os.path.abspath("../"), "dialin/common/msg_ids.py"), author="Peter Lucia", prefix_match="MSG_ID_", cpp_header="MsgDefs.h", code_prepend= ("\n" "from enum import unique\n" "from ..utils.base import DialinEnum\n"), code_class_def=("\n\n" "# Branch: {0}\n" "@unique\n" "class MsgIds(DialinEnum):\n").format(common_branch), as_int=False, custom_defs=custom_defs, )