CAPI-diff工具新增参数位置变化场景、addtogroup和file标签新增和删除,增加按kit划分的.md表格结果

Signed-off-by: zhangwuf <zhangwu47@huawei.com>
This commit is contained in:
zhangwuf 2024-05-17 14:49:34 +08:00
parent bbe35eb861
commit 5fc2948d5a
8 changed files with 304 additions and 43 deletions

View File

@ -24,6 +24,7 @@ class ToolNameType(enum.Enum):
DIFF = 'diff'
CHECK = 'check'
COLLECT_H = 'collect_h'
COLLECT_FILE = 'collect_file'
tool_name_type_set = [
@ -51,9 +52,11 @@ def run_tools(options):
elif tool_name == ToolNameType["DIFF"].value:
diff.process_dir(options.diff_path_old, options.diff_path_new)
elif tool_name == ToolNameType["CHECK"].value:
check.curr_entry(options.path, options.checker, options.output)
check.curr_entry(options.path, options.root_path, options.checker, options.output)
elif tool_name == ToolNameType['COLLECT_H'].value:
parser.parser_direct(options.parser_path)
elif tool_name == ToolNameType['COLLECT_FILE'].value:
parser.parser_file_level(options.output_path)
else:
print("工具名称错误")
@ -79,6 +82,13 @@ class Config(object):
"type": str,
"help": "解析路径"
},
{
"name": "--output-path",
"abbr": "-O",
"required": False,
"type": str,
"help": "collect_file工具输出文件路径"
},
{
"name": "--codecheck--path",
"abbr": "--path",
@ -86,6 +96,13 @@ class Config(object):
"type": str,
"help": "codecheck解析文件路径"
},
{
"name": "--root-path",
"abbr": "--root_path",
"required": False,
"type": str,
"help": "根目录路径"
},
{
"name": "--check-command",
"abbr": "--checker",

View File

@ -0,0 +1,143 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2024 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import stat
import pandas as pd
def sort_by_kit(result_info_list: list):
"""
Description:列表按kit排序
"""
sort_by_kit_list = []
if 1 == len(result_info_list):
sort_by_kit_list.extend(result_info_list)
write_data_in_md(result_info_list[0].kit_name, result_info_list)
return sort_by_kit_list
if result_info_list:
kit_list = sorted(result_info_list, key=lambda obj: obj.kit_name)
first_kit_name = kit_list[0].kit_name
same_element = []
for obj_element in kit_list:
if obj_element.kit_name == first_kit_name:
same_element.append(obj_element)
else:
sorted_data = sort_by_file_path(same_element)
write_data_in_md(first_kit_name, sorted_data)
sort_by_kit_list.extend(sorted_data)
first_kit_name = obj_element.kit_name
same_element = []
if same_element:
sorted_data = sort_by_file_path(same_element)
write_data_in_md(first_kit_name, sorted_data)
sort_by_kit_list.extend(sorted_data)
return sort_by_kit_list
def sort_by_file_path(result_info_list_kit: list):
"""
Description:列表按文件路径排序
"""
sorted_by_file_list = []
if 1 == len(result_info_list_kit):
sorted_by_file_list.extend(result_info_list_kit)
return sorted_by_file_list
if result_info_list_kit:
file_list = sorted(result_info_list_kit, key=lambda obj: obj.api_file_path)
first_file_name = file_list[0].api_file_path
same_element = []
for obj_element in file_list:
if obj_element.api_file_path == first_file_name:
same_element.append(obj_element)
else:
sorted_data = sort_by_type(same_element)
sorted_by_file_list.extend(sorted_data)
first_file_name = obj_element.api_file_path
same_element = []
if same_element:
sorted_data = sort_by_type(same_element)
sorted_by_file_list.extend(sorted_data)
return sorted_by_file_list
def sort_by_type(result_info_list_file: list):
"""
Description:列表按操作类型排序
"""
sorted_by_type_list = []
if result_info_list_file:
sorted_by_type_list = sorted(result_info_list_file, key=lambda obj: obj.diff_type.name)
return sorted_by_type_list
def create_md_table_with_pandas(data):
"""
Description:将列表中字典元素数据转为md支持的数据
"""
df = pd.DataFrame(data)
markdown_table = df.to_markdown(index=False)
if markdown_table:
markdown_table.encode(encoding='utf-8')
return markdown_table
def change_list_obj_to_dict(list_of_obj: list):
"""
Description:将列表中对象元素数据转为字典元素数据
"""
data_list = []
if list_of_obj:
for obj_element in list_of_obj:
obj_dict = {
'操作': obj_element.diff_type.name,
'旧版本': obj_element.old_api_full_text.replace('\n', '<br />'),
'新版本': obj_element.new_api_full_text.replace('\n', '<br />'),
'.h文件': obj_element.api_file_path
}
data_list.append(obj_dict)
return data_list
def write_data_in_md(kit_name: str, write_data: list):
"""
Description:生成.md表格
"""
if not kit_name:
kit_name = r'nullOfKit'
file_name = '{}{}'.format(kit_name, '.md')
list_element_dict = change_list_obj_to_dict(write_data)
md_data = create_md_table_with_pandas(list_element_dict)
if md_data:
path_str = r'diff合集'
if not os.path.exists(path_str):
os.mkdir(path_str)
md_name = os.path.abspath(os.path.join(path_str, file_name))
modes = stat.S_IRWXO | stat.S_IRWXG | stat.S_IRWXU
fd = os.open(md_name, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, mode=modes)
os.write(fd, md_data.encode())
os.close(fd)
def write_md_entrance(result_info_list):
"""
Description:将数据生成.md表格入口
"""
sorted_data = sort_by_kit(result_info_list)
return sorted_data

View File

@ -22,6 +22,7 @@ import openpyxl as op
from coreImpl.parser.parser import parser_include_ast
from coreImpl.diff.diff_processor_node import judgment_entrance
from typedef.diff.diff import OutputJson
from bin.write_md import write_md_entrance
global_old_dir = ''
global_new_dir = ''
@ -31,6 +32,7 @@ diff_info_list = []
def start_diff_file(old_dir, new_dir):
result_info_list = global_assignment(old_dir, new_dir)
generate_excel(result_info_list)
write_md_entrance(result_info_list)
result_json = result_to_json(result_info_list)
write_in_txt(result_json, r'./ndk_diff.txt')
print(result_json)
@ -90,7 +92,7 @@ def result_to_json(result_info_list):
def write_in_txt(check_result, output_path):
modes = stat.S_IRWXO | stat.S_IRWXG | stat.S_IRWXU
fd = os.open(output_path, os.O_WRONLY | os.O_CREAT, mode=modes)
fd = os.open(output_path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, mode=modes)
os.write(fd, check_result.encode())
os.close(fd)

View File

@ -19,7 +19,7 @@ import os
from collections import OrderedDict
from clang.cindex import CursorKind
from coreImpl.diff.diff_processor_permission import compare_permission, RangeChange
from typedef.diff.diff import TAGS, DiffType, DiffInfo, Scene, ApiInfo
from typedef.diff.diff import TAGS, DiffType, DiffInfo, Scene
current_file = os.path.dirname(__file__)
@ -29,7 +29,7 @@ def wrap_diff_info(old_info, new_info, diff_info: DiffInfo):
if 'temporary_name' in old_info['name']:
old_info['name'] = ''
if (not diff_info.is_api_change) and 'kind' in old_info \
and 'MACRO_DEFINITION' != old_info['kind']:
and 'MACRO_DEFINITION' != old_info['kind'] and 'TRANSLATION_UNIT' != old_info['kind']:
diff_info.set_is_api_change(True)
diff_info.set_api_name(old_info['name'])
diff_info.set_api_type(old_info['kind'])
@ -51,7 +51,7 @@ def wrap_diff_info(old_info, new_info, diff_info: DiffInfo):
if 'temporary_name' in new_info['name']:
new_info['name'] = ''
if (not diff_info.is_api_change) and 'kind' in new_info \
and 'MACRO_DEFINITION' != new_info['kind']:
and 'MACRO_DEFINITION' != new_info['kind'] and 'TRANSLATION_UNIT' != new_info['kind']:
diff_info.set_is_api_change(True)
diff_info.set_api_name(new_info['name'])
diff_info.set_api_type(new_info['kind'])
@ -114,25 +114,58 @@ def process_func_return(old, new, diff_info_list):
diff_info_list.append(diff_info)
def process_func_param_location(old_param_list, new_param_list):
result_list = []
old_param_str_list = get_param_name_and_type(old_param_list)
new_param_str_list = get_param_name_and_type(new_param_list)
old_len = len(old_param_list)
for i, element in enumerate(old_param_str_list):
if element not in new_param_str_list:
return result_list
if i != new_param_str_list.index(element) and i + 1 <= old_len:
result_obj = wrap_diff_info(old_param_list[i], new_param_list[i],
DiffInfo(DiffType.FUNCTION_PARAM_POS_CHANGE))
result_list.append(result_obj)
return result_list
def get_param_name_and_type(param_list):
param_str_list = []
for param in param_list:
if 'name' in param and 'type' in param:
param_str = '{} {}'.format(param.get('type'), param.get('name'))
param_str_list.append(param_str)
return param_str_list
def process_each_param(old, new, old_len, new_len, diff_info_list):
for i in range(max(old_len, new_len)):
if (i + 1) > new_len: # 减少参数
result_message_obj = get_initial_result_obj(DiffType.FUNCTION_PARAM_REDUCE, new, old)
new_none = None
diff_info = wrap_diff_info(old['parm'][i], new_none, result_message_obj)
diff_info_list.append(diff_info)
elif (i + 1) > old_len: # 增加参数
result_message_obj = get_initial_result_obj(DiffType.FUNCTION_PARAM_ADD, new, old)
old_none = None
diff_info = wrap_diff_info(old_none, new['parm'][i], result_message_obj)
diff_info_list.append(diff_info)
else:
process_param_scene(old['parm'], new['parm'], diff_info_list, i, new)
def process_func_param(old, new, diff_info_list):
if 'parm' in old and 'parm' in new:
old_len = len(old['parm'])
new_len = len(new['parm'])
for i in range(max(old_len, new_len)):
if (i + 1) > new_len: # 减少参数
result_message_obj = get_initial_result_obj(DiffType.FUNCTION_PARAM_REDUCE, new, old)
new_none = None
diff_info = wrap_diff_info(old['parm'][i], new_none, result_message_obj)
diff_info_list.append(diff_info)
elif (i + 1) > old_len: # 增加参数
result_message_obj = get_initial_result_obj(DiffType.FUNCTION_PARAM_ADD, new, old)
old_none = None
diff_info = wrap_diff_info(old_none, new['parm'][i], result_message_obj)
diff_info_list.append(diff_info)
else:
process_param_scene(old['parm'], new['parm'], diff_info_list, i, new)
result_obj_list = []
if old_len == new_len:
result_obj_list = process_func_param_location(old['parm'], new['parm'])
diff_info_list.extend(result_obj_list)
if not result_obj_list:
process_each_param(old, new, old_len, new_len, diff_info_list)
elif 'parm' not in old and 'parm' in new: # 旧无新有
result_message_obj = get_initial_result_obj(DiffType.FUNCTION_PARAM_ADD, new, old)
@ -388,24 +421,36 @@ def process_variable_const(old, new):
diff_var_or_con = []
if 'is_const' in old:
if old['is_const']: # 处理常量
process_constant_to_variable(old, new, diff_var_or_con) # 常量改变量
if 'is_const' in new and new['is_const']:
process_constant_type(old, new, diff_var_or_con) # 处理常量类型
elif 'is_const' in new and (not new['is_const']): # 处理常量变变量
process_const_change_variable(old, new, diff_var_or_con)
process_constant_name(old, new, diff_var_or_con) # 处理常量名
process_constant_type(old, new, diff_var_or_con) # 处理常量类型
process_constant_value(old, new, diff_var_or_con) # 处理常量值
else: # 处理变量
process_variable_to_constant(old, new, diff_var_or_con) # 变量改常量
if 'is_const' in new and new['is_const']:
process_variable_change_const(old, new, diff_var_or_con) # 处理变量变常量
elif 'is_const' in new and (not new['is_const']):
process_variable_type(old, new, diff_var_or_con) # 处理变量类型
process_variable_name(old, new, diff_var_or_con) # 处理变量名
process_variable_type(old, new, diff_var_or_con) # 处理变量类型
process_variable_value(old, new, diff_var_or_con) # 处理变量值
return diff_var_or_con
def process_variable_to_constant(old, new, diff_variable_list):
if new['is_const']:
def process_const_change_variable(old, new, diff_variable_list):
if 'is_const' in new and (not new['is_const']):
diff_info = wrap_diff_info(old, new, DiffInfo(DiffType.CONSTANT_CHANGE_TO_VARIABLE))
diff_variable_list.append(diff_info)
def process_variable_change_const(old, new, diff_variable_list):
if 'is_const' in new and new['is_const']:
diff_info = wrap_diff_info(old, new, DiffInfo(DiffType.VARIABLE_CHANGE_TO_CONSTANT))
diff_variable_list.append(diff_info)
def process_variable_name(old, new, diff_variable_list):
if old['name'] != new['name']:
diff_info = wrap_diff_info(old, new, DiffInfo(DiffType.VARIABLE_NAME_CHANGE))
@ -796,6 +841,54 @@ def process_doc_list(old_doc_list: list, new_doc_list: list, old_info, new_info)
return diff_info_list
def get_eligible_labels_doc(doc_element):
addtogroup_doc_list_right = []
file_doc_list_right = []
if 'tags' in doc_element:
for element in doc_element['tags']:
if element.get('tag') and 'addtogroup' == element.get('tag'):
addtogroup_doc_list_right.append(doc_element)
break
elif element.get('tag') and 'file' == element.get('tag'):
file_doc_list_right.append(doc_element)
break
return addtogroup_doc_list_right, file_doc_list_right
def get_addtogroup_and_file_doc(doc_list: list):
addtogroup_doc_list = []
file_doc_list = []
for doc_element in doc_list:
result_of_addtogroup_list, result_of_file_list = get_eligible_labels_doc(doc_element)
addtogroup_doc_list.extend(result_of_addtogroup_list)
file_doc_list.extend(result_of_file_list)
return addtogroup_doc_list, file_doc_list
def process_addtogroup_and_file_list(old_list, new_list, old_info, new_info, num_key):
old_len = len(old_list)
new_len = len(new_list)
result_list = []
# addtogroup tag
if 1 == num_key:
if old_len > new_len:
result_list.append(wrap_diff_info(old_info, new_info, DiffInfo(DiffType.DOC_TAG_ADDTOGROUP_DECREASE)))
elif old_len < new_len:
result_list.append(wrap_diff_info(old_info, new_info, DiffInfo(DiffType.DOC_TAG_ADDTOGROUP_INCREASE)))
else:
result_list.extend(process_doc_list(old_list, new_list, old_info, new_info))
# file tag
elif 0 == num_key:
if old_len > new_len:
result_list.append(wrap_diff_info(old_info, new_info, DiffInfo(DiffType.DOC_TAG_FILE_DECREASE)))
elif old_len < new_len:
result_list.append(wrap_diff_info(old_info, new_info, DiffInfo(DiffType.DOC_TAG_FILE_INCREASE)))
else:
result_list.extend(process_doc_list(old_list, new_list, old_info, new_info))
return result_list
def process_comment_str(old_info, new_info):
diff_info_list = []
if old_info['comment'] == new_info['comment']:
@ -809,7 +902,12 @@ def process_comment_str(old_info, new_info):
old_doc_list = process_comment(old_info['comment'])
new_doc_list = process_comment(new_info['comment'])
if new_info['kind'] == CursorKind.TRANSLATION_UNIT.name:
diff_info_list.extend(process_doc_list(old_doc_list, new_doc_list, old_info, new_info))
old_addtogroup_doc_list, old_file_doc_list = get_addtogroup_and_file_doc(old_doc_list)
new_addtogroup_doc_list, new_file_doc_list = get_addtogroup_and_file_doc(new_doc_list)
diff_info_list.extend(process_addtogroup_and_file_list(old_addtogroup_doc_list, new_addtogroup_doc_list,
old_info, new_info, 1))
diff_info_list.extend(process_addtogroup_and_file_list(old_file_doc_list, new_file_doc_list,
old_info, new_info, 0))
else:
if len(old_doc_list) > len(new_doc_list):
diff_info_list.append(wrap_diff_info(old_info, new_info, DiffInfo(DiffType.REDUCE_DOC)))

View File

@ -516,7 +516,6 @@ def api_entrance(share_lib, include_path, gn_path=None, link_path=None): # 统
print("lib.dll: install path")
# 创建AST索引
index = Index.create()
print('=' * 50)
# options赋值为如下代表宏定义解析数据也要
args = ['-I{}'.format(path) for path in link_path]
args.append('-std=c99')
@ -525,14 +524,10 @@ def api_entrance(share_lib, include_path, gn_path=None, link_path=None): # 统
data_total = [] # 列表对象-用于统计
for item in include_path: # 对每个头文件做处理
tu = index.parse(item, args=args, options=options)
print(tu)
print('=' * 50)
ast_root_node = tu.cursor # 获取根节点
print(ast_root_node)
matches = get_start_comments(item) # 接收文件最开始的注释
# 前序遍历AST
preorder_travers_ast(ast_root_node, data_total, matches, item, gn_path) # 调用处理函数
print('=' * 50)
return data_total

View File

@ -141,7 +141,6 @@ def change_abs(include_files, dire_path): # 获取.h绝对路径
else:
relative_path = os.path.abspath(os.path.join(dire_path, os.path.normpath(j_item))) # ../ .解决
abs_path.append(relative_path)
print("=" * 50)
return abs_path
@ -173,9 +172,6 @@ def create_dir(sources_dir, gn_file, function_name, link_include_file):
new_dire = os.path.normpath(new_dire)
if not os.path.exists(new_dire):
os.makedirs(new_dire)
else:
print("目录已存在")
if new_dire in link_include_file:
pass
else:
@ -213,12 +209,8 @@ def main_entrance(directory_path, function_names, link_path): # 主入口
for item in gn_file_total: # 处理每个gn文件
match_files, json_files, include_files = dire_func(item, function_names)
dire_path = os.path.dirname(item) # 获取gn文件路径
print("目录路径: {}".format(dire_path))
print("同级json文件\n", json_files)
print("头文件:\n", include_files)
if include_files: # 符合条件的gn文件
abs_path = change_abs(include_files, dire_path) # 接收.h绝对路径
print("头文件绝对路径:\n", abs_path)
# 接收对比结果信息
data_result = get_result_table(json_files, abs_path, link_path, directory_path)
data_total.append(data_result.data)

View File

@ -84,13 +84,11 @@ class DiffType(enum.Enum):
VARIABLE_NAME_CHANGE = 'change variable name'
VARIABLE_TYPE_CHANGE = 'change variable type'
VARIABLE_VALUE_CHANGE = 'change variable value'
VARIABLE_CHANGE_CONST = 'Change variable to constant'
VARIABLE_CHANGE_TO_CONSTANT = 'change variable to constant'
CONSTANT_NAME_CHANGE = 'change constant name'
CONSTANT_TYPE_CHANGE = 'change constant type'
CONSTANT_VALUE_CHANGE = 'change constant value'
CONST_CHANGE_VARIABLE = 'Change constant to variable'
CONSTANT_CHANGE_TO_VARIABLE = 'change constant to variable'
TYPEDEF_NAME_TYPE_CHANGE = 'change typedef name type'
@ -129,6 +127,10 @@ class DiffType(enum.Enum):
DOC_TAG_LEFT_BRACE_HAVE_TO_NA = 'delete { tag'
DOC_TAG_RIGHT_BRACE_NA_TO_HAVE = 'add } tag'
DOC_TAG_RIGHT_BRACE_HAVE_TO_NA = 'delete } tag'
DOC_TAG_ADDTOGROUP_INCREASE = 'The file has addtogroup tag, add the addtogroup tag'
DOC_TAG_ADDTOGROUP_DECREASE = 'The file has multiple addtogroup tags. Delete the addtogroup tag'
DOC_TAG_FILE_INCREASE = 'The file has file tag, add the file tag'
DOC_TAG_FILE_DECREASE = 'The file has multiple file tags. Delete the file tag'
compatible_list = [
@ -157,6 +159,10 @@ compatible_list = [
DiffType.DOC_TAG_LEFT_BRACE_HAVE_TO_NA,
DiffType.DOC_TAG_RIGHT_BRACE_NA_TO_HAVE,
DiffType.DOC_TAG_RIGHT_BRACE_HAVE_TO_NA,
DiffType.DOC_TAG_ADDTOGROUP_DECREASE,
DiffType.DOC_TAG_ADDTOGROUP_INCREASE,
DiffType.DOC_TAG_FILE_DECREASE,
DiffType.DOC_TAG_FILE_INCREASE
]
api_new_list = [DiffType.ADD_API]
@ -198,9 +204,11 @@ api_prototype_change_list = [
DiffType.VARIABLE_NAME_CHANGE,
DiffType.VARIABLE_TYPE_CHANGE,
DiffType.VARIABLE_VALUE_CHANGE,
DiffType.VARIABLE_CHANGE_TO_CONSTANT,
DiffType.CONSTANT_NAME_CHANGE,
DiffType.CONSTANT_TYPE_CHANGE,
DiffType.CONSTANT_VALUE_CHANGE,
DiffType.CONSTANT_CHANGE_TO_VARIABLE,
DiffType.TYPEDEF_NAME_TYPE_CHANGE
]
@ -238,6 +246,10 @@ api_constraint_change_list = [
DiffType.DOC_TAG_LEFT_BRACE_HAVE_TO_NA,
DiffType.DOC_TAG_RIGHT_BRACE_NA_TO_HAVE,
DiffType.DOC_TAG_RIGHT_BRACE_HAVE_TO_NA,
DiffType.DOC_TAG_ADDTOGROUP_DECREASE,
DiffType.DOC_TAG_ADDTOGROUP_INCREASE,
DiffType.DOC_TAG_FILE_DECREASE,
DiffType.DOC_TAG_FILE_INCREASE
]
api_modification_type_dict = {

View File

@ -19,7 +19,7 @@ import enum
class StringConstant(enum.Enum):
LIB_CLG_PATH = r'C:\Program Files\LLVM\bin\libclang.dll' # 共享库
LIB_CLG_PATH = r'./prebuilts/clang/ohos/linux-x86_64/llvm/lib/libclang.so' # 共享库
FUNK_NAME = "ohos_ndk_headers"
REPLACE_WAREHOUSE = '\\interface_sdk_c\\interface_sdk_c' # 拉到本地仓路径(去掉磁盘)
# 拉到本地仓的三方库绝对路径
@ -31,6 +31,8 @@ class StringConstant(enum.Enum):
SELF_INCLUDE_NEW = r'.\sysroot\self_include_files_new'
SYSROOT = r'.\sysroot'
RESULT_HEAD_NAME = "result_total.xlsx"
PARSER_DIRECT_EXCEL_NAME = 'parser_direct_data.xlsx'
FILE_LEVEL_API_DATA = r'.\file_api_json.json'
class RegularExpressions(enum.Enum):