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