15f9996aaSopenharmony_ci#!/usr/bin/env python3 25f9996aaSopenharmony_ci# -*- coding: utf-8 -*- 35f9996aaSopenharmony_ci# Copyright (c) 2024 Huawei Device Co., Ltd. 45f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License"); 55f9996aaSopenharmony_ci# you may not use this file except in compliance with the License. 65f9996aaSopenharmony_ci# You may obtain a copy of the License at 75f9996aaSopenharmony_ci# 85f9996aaSopenharmony_ci# http://www.apache.org/licenses/LICENSE-2.0 95f9996aaSopenharmony_ci# 105f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software 115f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS, 125f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135f9996aaSopenharmony_ci# See the License for the specific language governing permissions and 145f9996aaSopenharmony_ci# limitations under the License. 155f9996aaSopenharmony_ci 165f9996aaSopenharmony_ciimport argparse 175f9996aaSopenharmony_ciimport json 185f9996aaSopenharmony_ciimport os 195f9996aaSopenharmony_ciimport re 205f9996aaSopenharmony_ciimport glob 215f9996aaSopenharmony_ciimport os.path 225f9996aaSopenharmony_ciimport stat 235f9996aaSopenharmony_ci 245f9996aaSopenharmony_ci 255f9996aaSopenharmony_ciclass Analyzer: 265f9996aaSopenharmony_ci @classmethod 275f9996aaSopenharmony_ci def get_components_from_inherit_attr(cls, components, inherit, project): 285f9996aaSopenharmony_ci for json_name in inherit: 295f9996aaSopenharmony_ci with open(project + os.sep + json_name, 'r', encoding='utf-8') as r: 305f9996aaSopenharmony_ci inherit_file = json.load(r) 315f9996aaSopenharmony_ci for subsystem in inherit_file['subsystems']: 325f9996aaSopenharmony_ci for component in subsystem['components']: 335f9996aaSopenharmony_ci component['subsystem'] = subsystem['subsystem'] 345f9996aaSopenharmony_ci components.append(component) 355f9996aaSopenharmony_ci 365f9996aaSopenharmony_ci @classmethod 375f9996aaSopenharmony_ci def check(cls, include): 385f9996aaSopenharmony_ci if include is not None and './' in include.group(): 395f9996aaSopenharmony_ci return True 405f9996aaSopenharmony_ci return False 415f9996aaSopenharmony_ci 425f9996aaSopenharmony_ci @classmethod 435f9996aaSopenharmony_ci def scan_files(cls, components, proj_path): 445f9996aaSopenharmony_ci results = [] 455f9996aaSopenharmony_ci for component in components: 465f9996aaSopenharmony_ci if not component.__contains__('scan_path') or component['scan_path'].strip() == '': 475f9996aaSopenharmony_ci continue 485f9996aaSopenharmony_ci files = glob.glob(os.path.join(component['scan_path'], '**', '*.c'), recursive=True) 495f9996aaSopenharmony_ci files.extend(glob.glob(os.path.join(component['scan_path'], '**', '*.cpp'), recursive=True)) 505f9996aaSopenharmony_ci files.extend(glob.glob(os.path.join(component['scan_path'], '**', '*.cc'), recursive=True)) 515f9996aaSopenharmony_ci files.extend(glob.glob(os.path.join(component['scan_path'], '**', '*.h'), recursive=True)) 525f9996aaSopenharmony_ci for file in files: 535f9996aaSopenharmony_ci try: 545f9996aaSopenharmony_ci cls.scan_each_file(component, file, proj_path, results) 555f9996aaSopenharmony_ci except UnicodeDecodeError as e: 565f9996aaSopenharmony_ci print("scan file {} with unicode decode error: {}".format(file, e)) 575f9996aaSopenharmony_ci return results 585f9996aaSopenharmony_ci 595f9996aaSopenharmony_ci @classmethod 605f9996aaSopenharmony_ci def scan_each_file(cls, component, file, project_path, results): 615f9996aaSopenharmony_ci with open(file, 'r', encoding='ISO-8859-1') as f: 625f9996aaSopenharmony_ci line_list = f.readlines() 635f9996aaSopenharmony_ci line_num = 0 645f9996aaSopenharmony_ci for line in line_list: 655f9996aaSopenharmony_ci include = re.match(r'#include\s+"([^">]+)"', line) 665f9996aaSopenharmony_ci line_num = line_num + 1 675f9996aaSopenharmony_ci if cls.check(include): 685f9996aaSopenharmony_ci result = {'line_num': line_num, 'file_path': file.replace(project_path, "/"), 695f9996aaSopenharmony_ci 'include_cmd': include.group(), 'component': component['component'], 705f9996aaSopenharmony_ci 'subsystem': component['subsystem']} 715f9996aaSopenharmony_ci results.append(result) 725f9996aaSopenharmony_ci 735f9996aaSopenharmony_ci @classmethod 745f9996aaSopenharmony_ci def analysis(cls, config: str, project_path: str, components_info: str, output_path: str): 755f9996aaSopenharmony_ci if not os.path.exists(config): 765f9996aaSopenharmony_ci print("error: {} is inaccessible or not found".format(config)) 775f9996aaSopenharmony_ci return 785f9996aaSopenharmony_ci if not os.path.exists(project_path): 795f9996aaSopenharmony_ci print("error: {} is inaccessible or not found".format(project_path)) 805f9996aaSopenharmony_ci return 815f9996aaSopenharmony_ci if not os.path.exists(components_info): 825f9996aaSopenharmony_ci print("error: {} is inaccessible or not found".format(components_info)) 835f9996aaSopenharmony_ci return 845f9996aaSopenharmony_ci components = cls.__get_components(config, project_path) 855f9996aaSopenharmony_ci cls.__get_need_scan_path(components, project_path, components_info) 865f9996aaSopenharmony_ci print("scan:") 875f9996aaSopenharmony_ci print([item['scan_path'] for item in components], project_path) 885f9996aaSopenharmony_ci result = cls.scan_files(components, project_path) 895f9996aaSopenharmony_ci flags = os.O_WRONLY | os.O_CREAT 905f9996aaSopenharmony_ci modes = stat.S_IWUSR | stat.S_IRUSR 915f9996aaSopenharmony_ci with os.fdopen(os.open(output_path, flags, modes), 'w') as f: 925f9996aaSopenharmony_ci for ele in result: 935f9996aaSopenharmony_ci items = ele['subsystem'], ele['component'], ele['file_path'], str(ele['line_num']), ele['include_cmd'] 945f9996aaSopenharmony_ci f.write(f'{" ".join(items)}\n') 955f9996aaSopenharmony_ci 965f9996aaSopenharmony_ci @classmethod 975f9996aaSopenharmony_ci def __get_need_scan_path(cls, components, project, components_info_path): 985f9996aaSopenharmony_ci path_info = dict() 995f9996aaSopenharmony_ci with open(components_info_path, 'r', encoding='utf-8') as r: 1005f9996aaSopenharmony_ci xml_info = r.readlines() 1015f9996aaSopenharmony_ci for line in xml_info: 1025f9996aaSopenharmony_ci if "path=" in line: 1035f9996aaSopenharmony_ci path = re.findall('path="(.*?)"', line)[0] 1045f9996aaSopenharmony_ci component = path.split('/')[-1] 1055f9996aaSopenharmony_ci path_info[component] = path 1065f9996aaSopenharmony_ci item_list = list(path_info.keys()) 1075f9996aaSopenharmony_ci for component in components: 1085f9996aaSopenharmony_ci if component['component'] in path_info.keys(): 1095f9996aaSopenharmony_ci component['scan_path'] = project + '/' + path_info[component['component']] 1105f9996aaSopenharmony_ci if (component['component'] in item_list): 1115f9996aaSopenharmony_ci item_list.remove(component['component']) 1125f9996aaSopenharmony_ci else: 1135f9996aaSopenharmony_ci component['scan_path'] = '' 1145f9996aaSopenharmony_ci print("no scan component :" + " ".join(item_list)) 1155f9996aaSopenharmony_ci 1165f9996aaSopenharmony_ci @classmethod 1175f9996aaSopenharmony_ci def __get_components(cls, config: str, project: str): 1185f9996aaSopenharmony_ci components = list() 1195f9996aaSopenharmony_ci with open(config, 'r', encoding='utf-8') as r: 1205f9996aaSopenharmony_ci config_json = json.load(r) 1215f9996aaSopenharmony_ci if "inherit" in config_json.keys(): 1225f9996aaSopenharmony_ci inherit = config_json['inherit'] 1235f9996aaSopenharmony_ci cls.get_components_from_inherit_attr(components, inherit, project) 1245f9996aaSopenharmony_ci for subsystem in config_json['subsystems']: 1255f9996aaSopenharmony_ci for component in subsystem['components']: 1265f9996aaSopenharmony_ci if component not in components: 1275f9996aaSopenharmony_ci component['subsystem'] = subsystem['subsystem'] 1285f9996aaSopenharmony_ci components.append(component) 1295f9996aaSopenharmony_ci return components 1305f9996aaSopenharmony_ci 1315f9996aaSopenharmony_ci 1325f9996aaSopenharmony_ci 1335f9996aaSopenharmony_cidef get_args(): 1345f9996aaSopenharmony_ci parser = argparse.ArgumentParser( 1355f9996aaSopenharmony_ci description=f"common_template.\n") 1365f9996aaSopenharmony_ci parser.add_argument("-c", "--config_path", required=True, type=str, 1375f9996aaSopenharmony_ci help="path of config_file", default="") 1385f9996aaSopenharmony_ci parser.add_argument("-p", "--project_path", type=str, required=False, 1395f9996aaSopenharmony_ci help="root path of openharmony. eg: -p ~/openharmony", default="./") 1405f9996aaSopenharmony_ci parser.add_argument("-x", "--xml_path", type=str, required=True, 1415f9996aaSopenharmony_ci help="path of ohos.xml", default="") 1425f9996aaSopenharmony_ci parser.add_argument("-o", "--output_path", required=False, type=str, 1435f9996aaSopenharmony_ci default="include_relative_path.list", help="name of output_json") 1445f9996aaSopenharmony_ci return parser.parse_args() 1455f9996aaSopenharmony_ci 1465f9996aaSopenharmony_ciif __name__ == '__main__': 1475f9996aaSopenharmony_ci args = get_args() 1485f9996aaSopenharmony_ci local_config_path = args.config_path 1495f9996aaSopenharmony_ci local_project_path = args.project_path 1505f9996aaSopenharmony_ci local_xml_path = args.xml_path 1515f9996aaSopenharmony_ci local_output_path = args.output_path 1525f9996aaSopenharmony_ci Analyzer.analysis(local_config_path, local_project_path, local_xml_path, local_output_path) 153