1#!/usr/bin/env python3 2# coding: utf-8 3# Copyright (c) 2024 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16 17""" 18Usage: python3 main.py <path_to_ets2panda> <path_to_gen_dir> <path_to_header_or_dir> [<path_to_header_or_dir> ...] 19Description: Parse c++ headers to yaml files. 20""" 21 22import os.path 23import sys 24import traceback 25from typing import List 26 27# pylint: disable=W0401,W0614 28from cpp_parser import CppParser 29from log_tools import init_log, console_log, parsing_log, error_log, info_log 30from prepare_header import remove_comments, extract_and_remove_includes 31from file_tools import print_to_yaml 32from runtime_collections import ( 33 init_collections, 34 add_to_statistics, 35 add_to_custom_yamls, 36 save_custom_yamls, 37 save_statistics, 38) 39 40 41def parse_file(src_path: str, dest_path: str) -> None: 42 """ 43 Parse one file. 44 """ 45 console_log("------------------------------------------------------------------------------") 46 parsing_log("Parsing file: " + src_path) 47 48 with open(src_path, "r", encoding="utf-8") as file: 49 data = file.read() 50 data = remove_comments(data) 51 data, includes = extract_and_remove_includes(data) 52 53 try: 54 res = CppParser(data).parse() 55 56 if len(includes) != 0: 57 res["include"] = includes 58 59 if not os.path.exists(os.path.dirname(dest_path)): 60 os.makedirs(os.path.dirname(dest_path)) 61 62 print_to_yaml(dest_path, res) 63 console_log("\n++++++++++++++++++++++++\n+ Successfully parsed! +\n++++++++++++++++++++++++") 64 65 # Collect statistics 66 add_to_statistics("generated_yamls", dest_path) 67 # Collect custom yamls 68 add_to_custom_yamls("pathsToHeaders", "paths", src_path) 69 70 except Exception: # pylint: disable=W0718 71 os.fdopen(os.open(dest_path, os.O_CREAT, mode=511), "w", encoding="utf-8").close() 72 73 error_log("Error while parsing '" + src_path + "'\n") 74 error_log(traceback.format_exc() + "\n") 75 info_log("Error! Can't parse '" + src_path + "'") 76 77 78def parse_files_in_list(paths_list: List[str], result_folder: str) -> None: 79 """ 80 Parse all headers from paths_list. Elements of list can be file's or dir's paths. 81 """ 82 os.makedirs(result_folder, exist_ok=True) 83 84 for path in paths_list: 85 if os.path.isdir(path): 86 87 if path.rstrip("/") == result_folder.rstrip("/"): 88 continue 89 90 nested_paths = [os.path.join(path, dir_file) for dir_file in os.listdir(path)] 91 parse_files_in_list(nested_paths, result_folder) 92 93 elif os.path.isfile(path) and os.path.splitext(path)[1] == ".h": 94 dst = os.path.join(result_folder, f"{os.path.splitext(os.path.relpath(path, sys.argv[1]))[0]}.yaml") 95 parse_file(path, dst) 96 97 else: 98 info_log(f"Error! File does not fit for parsing or does not exist: '{path}'") 99 100 101if __name__ == "__main__": 102 if len(sys.argv) < 4: 103 raise RuntimeError("Wrong arguments!") 104 105 lib_gen_dir = sys.argv[2] 106 if not os.path.exists(lib_gen_dir) or not os.path.isdir(lib_gen_dir): 107 raise RuntimeError(f"Please change lib_gen_dir to correct path.\n'{lib_gen_dir}'") 108 init_collections(lib_gen_dir) 109 init_log(lib_gen_dir) 110 111 files_list = list(sys.argv[3:]) 112 parse_files_in_list(files_list, os.path.join(lib_gen_dir, "gen/headers")) 113 save_custom_yamls() 114 save_statistics() 115