import argparse
import json
import os
import re
import glob
import os.path
import stat
class Analyzer:
@classmethod
def get_components_from_inherit_attr(cls, components, inherit, project):
for json_name in inherit:
with open(project + os.sep + json_name, 'r', encoding='utf-8') as r:
inherit_file = json.load(r)
for subsystem in inherit_file['subsystems']:
for component in subsystem['components']:
component['subsystem'] = subsystem['subsystem']
components.append(component)
@classmethod
def check(cls, include):
if include is not None and './' in include.group():
return True
return False
@classmethod
def scan_files(cls, components, proj_path):
results = []
for component in components:
if not component.__contains__('scan_path') or component['scan_path'].strip() == '':
continue
files = glob.glob(os.path.join(component['scan_path'], '**', '*.c'), recursive=True)
files.extend(glob.glob(os.path.join(component['scan_path'], '**', '*.cpp'), recursive=True))
files.extend(glob.glob(os.path.join(component['scan_path'], '**', '*.cc'), recursive=True))
files.extend(glob.glob(os.path.join(component['scan_path'], '**', '*.h'), recursive=True))
for file in files:
try:
cls.scan_each_file(component, file, proj_path, results)
except UnicodeDecodeError as e:
print("scan file {} with unicode decode error: {}".format(file, e))
return results
@classmethod
def scan_each_file(cls, component, file, project_path, results):
with open(file, 'r', encoding='ISO-8859-1') as f:
line_list = f.readlines()
line_num = 0
for line in line_list:
include = re.match(r'#include\s+"([^">]+)"', line)
line_num = line_num + 1
if cls.check(include):
result = {'line_num': line_num, 'file_path': file.replace(project_path, "/"),
'include_cmd': include.group(), 'component': component['component'],
'subsystem': component['subsystem']}
results.append(result)
@classmethod
def analysis(cls, config: str, project_path: str, components_info: str, output_path: str):
if not os.path.exists(config):
print("error: {} is inaccessible or not found".format(config))
return
if not os.path.exists(project_path):
print("error: {} is inaccessible or not found".format(project_path))
return
if not os.path.exists(components_info):
print("error: {} is inaccessible or not found".format(components_info))
return
components = cls.__get_components(config, project_path)
cls.__get_need_scan_path(components, project_path, components_info)
print("scan:")
print([item['scan_path'] for item in components], project_path)
result = cls.scan_files(components, project_path)
flags = os.O_WRONLY | os.O_CREAT
modes = stat.S_IWUSR | stat.S_IRUSR
with os.fdopen(os.open(output_path, flags, modes), 'w') as f:
for ele in result:
items = ele['subsystem'], ele['component'], ele['file_path'], str(ele['line_num']), ele['include_cmd']
f.write('{}\n'.format(" ".join(items)))
@classmethod
def __get_need_scan_path(cls, components, project, components_info_path):
path_info = dict()
with open(components_info_path, 'r', encoding='utf-8') as r:
xml_info = r.readlines()
for line in xml_info:
if "path=" in line:
path = re.findall('path="(.*?)"', line)[0]
component = path.split('/')[-1]
path_info[component] = path
item_list = list(path_info.keys())
for component in components:
if component['component'] in path_info.keys():
component['scan_path'] = project + '/' + path_info[component['component']]
if (component['component'] in item_list):
item_list.remove(component['component'])
else:
component['scan_path'] = ''
print("no scan component :" + " ".join(item_list))
@classmethod
def __get_components(cls, config: str, project: str):
components = list()
with open(config, 'r', encoding='utf-8') as r:
config_json = json.load(r)
if "inherit" in config_json.keys():
inherit = config_json['inherit']
cls.get_components_from_inherit_attr(components, inherit, project)
for subsystem in config_json['subsystems']:
for component in subsystem['components']:
if component not in components:
component['subsystem'] = subsystem['subsystem']
components.append(component)
return components
def get_args():
parser = argparse.ArgumentParser(
description=f"common_template.\n")
parser.add_argument("-c", "--config_path", required=True, type=str,
help="path of config_file", default="")
parser.add_argument("-p", "--project_path", type=str, required=False,
help="root path of openharmony. eg: -p ~/openharmony", default="./")
parser.add_argument("-x", "--xml_path", type=str, required=True,
help="path of ohos.xml", default="")
parser.add_argument("-o", "--output_path", required=False, type=str,
default="include_relative_path.list", help="name of output_json")
return parser.parse_args()
if __name__ == '__main__':
args = get_args()
local_config_path = args.config_path
local_project_path = args.project_path
local_xml_path = args.xml_path
local_output_path = args.output_path
Analyzer.analysis(local_config_path, local_project_path, local_xml_path, local_output_path)