1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# Copyright (c) 2023 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 16import filecmp 17import json 18import os 19import stat 20from collections import OrderedDict 21import openpyxl as op 22from coreImpl.parser.parser import parser_include_ast 23from coreImpl.diff.diff_processor_node import judgment_entrance, change_data_total 24from typedef.diff.diff import OutputJson, ApiChangeData 25from bin.write_md import write_md_entrance 26 27global_old_dir = '' 28global_new_dir = '' 29diff_info_list = [] 30 31 32def get_modification_type_dict(): 33 modification_type_dict = { 34 'API新增': 0, 35 'API删除': 0, 36 'API废弃': 0, 37 'API修改': 0, 38 'API修改(原型修改)': 0, 39 'API修改(约束变化)': 0 40 } 41 return modification_type_dict 42 43 44def get_compatible_dict(): 45 compatible_dict = { 46 '兼容性': 0, 47 '非兼容性': 0 48 } 49 return compatible_dict 50 51 52def change_to_json(data): 53 data_of_json = json.dumps(data, ensure_ascii=False, indent=4) 54 return data_of_json 55 56 57def get_api_change_obj(api_data): 58 modification_type_dict = get_modification_type_dict() 59 compatible_dict = get_compatible_dict() 60 change_data_obj = ApiChangeData() 61 key = 0 62 api_unique_id = '' 63 for element in api_data: 64 api_unique_id = element.current_api_unique_id 65 if 0 == key: 66 change_data_obj.set_api_name(element.api_node_name) 67 change_data_obj.set_kit_name(element.kit_name) 68 change_data_obj.set_sub_system(element.sub_system) 69 change_data_obj.set_is_api_change(element.is_api_change) 70 change_data_obj.set_class_name(element.class_name) 71 change_data_obj.set_diff_type(element.operation_diff_type) 72 change_data_obj.set_change_type(element.api_modification_type) 73 change_data_obj.set_old_all_text(element.old_api_full_text) 74 change_data_obj.set_new_all_text(element.new_api_full_text) 75 change_data_obj.set_compatible_total(element.is_compatible) 76 change_data_obj.set_is_system_api(element.is_system_api) 77 key = 1 78 else: 79 old_all_text = '{}#&#{}'.format(change_data_obj.old_all_text, element.old_api_full_text) 80 new_all_text = '{}#&#{}'.format(change_data_obj.new_all_text, element.new_api_full_text) 81 diff_type_all = '{}#&#{}'.format(change_data_obj.get_diff_type(), element.operation_diff_type) 82 change_type_all = '{}#&#{}'.format(change_data_obj.get_change_type(), element.api_modification_type) 83 compatible_data_all = '{}#&#{}'.format(change_data_obj.get_compatible_total(), element.is_compatible) 84 change_data_obj.set_old_all_text(old_all_text) 85 change_data_obj.set_new_all_text(new_all_text) 86 change_data_obj.set_diff_type(diff_type_all) 87 change_data_obj.set_change_type(change_type_all) 88 change_data_obj.set_compatible_total(compatible_data_all) 89 if element.is_compatible and (0 == compatible_dict.get('兼容性')): 90 compatible_dict['兼容性'] = 1 91 elif not element.is_compatible and (0 == compatible_dict.get('非兼容性')): 92 compatible_dict['非兼容性'] = 1 93 if element.api_modification_type in modification_type_dict: 94 modification_type_dict[element.api_modification_type] = 1 95 if 1 == modification_type_dict.get('API修改(原型修改)') and 1 == modification_type_dict.get('API修改(约束变化)'): 96 modification_type_dict['API修改'] = 1 97 compatible_str = change_to_json(compatible_dict) 98 modification_type_str = change_to_json(modification_type_dict) 99 change_data_obj.set_compatible(compatible_str) 100 change_data_obj.set_change_num(modification_type_str) 101 change_data_obj.set_unique_id(api_unique_id) 102 103 return change_data_obj 104 105 106def collect_api_change(change_data: list): 107 api_change_data = [] 108 for list_element in change_data: 109 change_obj = get_api_change_obj(list_element) 110 api_change_data.append(change_obj) 111 112 return api_change_data 113 114 115def collect_node_api_change(api_change_info_list): 116 change_data = [] 117 for api_change_info in api_change_info_list: 118 info_data = [ 119 api_change_info.api_name, 120 api_change_info.kit_name, 121 api_change_info.sub_system, 122 api_change_info.is_api_change, 123 api_change_info.class_name, 124 api_change_info.diff_type, 125 api_change_info.change_type, 126 api_change_info.compatible, 127 api_change_info.change_num, 128 api_change_info.old_all_text, 129 api_change_info.new_all_text, 130 api_change_info.compatible_total, 131 api_change_info.unique_id, 132 api_change_info.is_system_api 133 ] 134 change_data.append(info_data) 135 136 return change_data 137 138 139def start_diff_file(old_dir, new_dir, output_path): 140 result_info_list = global_assignment(old_dir, new_dir) 141 total = change_data_total 142 collect_api_change_data = collect_api_change(total) 143 generate_excel(result_info_list, collect_api_change_data, output_path) 144 write_md_entrance(result_info_list, output_path) 145 result_json = result_to_json(result_info_list) 146 diff_result_path = r'./diff_result.txt' 147 output_path_txt = os.path.abspath(os.path.join(output_path, diff_result_path)) 148 write_in_txt(result_json, output_path_txt) 149 150 151def disposal_result_data(result_info_list): 152 data = [] 153 for diff_info in result_info_list: 154 info_data = [ 155 diff_info.operation_diff_type, 156 diff_info.old_api_full_text, 157 diff_info.new_api_full_text, 158 diff_info.api_file_path, 159 diff_info.sub_system, 160 diff_info.kit_name, 161 diff_info.is_system_api 162 ] 163 data.append(info_data) 164 165 return data 166 167 168def generate_excel(result_info_list, api_change_data, output_path): 169 data = disposal_result_data(result_info_list) 170 wb = op.Workbook() 171 ws = wb['Sheet'] 172 ws.title = 'api差异' 173 ws.append(['操作标记', '差异项-旧版本', '差异项-新版本', '.h文件', '归属子系统', 'kit', '是否为系统API']) 174 for title in data: 175 d = title[0], title[1], title[2], title[3], title[4], title[5], title[6] 176 ws.append(d) 177 178 change_data_list = collect_node_api_change(api_change_data) 179 ws_of_change = wb.create_sheet('api变更次数统计') 180 ws_of_change.append(['api名称', 'kit名称', '归属子系统', '是否是api', 'api类型', '操作标记', '变更类型', 181 '兼容性', '变更次数', '差异项-旧版本', '差异项-新版本', '兼容性列表', '接口全路径', 182 '是否为系统API']) 183 for element in change_data_list: 184 change_data = element[0], element[1], element[2], element[3], element[4], element[5],\ 185 element[6], element[7], element[8], element[9], element[10], element[11],\ 186 element[12], element[13] 187 ws_of_change.append(change_data) 188 output_path_xlsx = os.path.abspath(os.path.join(output_path, 'diff.xlsx')) 189 wb.save(output_path_xlsx) 190 191 192def global_assignment(old_dir, new_dir): 193 global diff_info_list 194 diff_info_list = [] 195 global global_old_dir 196 global_old_dir = old_dir 197 global global_new_dir 198 global_new_dir = new_dir 199 do_diff(old_dir, new_dir) 200 return diff_info_list 201 202 203def result_to_json(result_info_list): 204 result_json = [] 205 for diff_info in result_info_list: 206 result_json.append(OutputJson(diff_info)) 207 return json.dumps(result_json, default=lambda obj: obj.__dict__, indent=4, ensure_ascii=False) 208 209 210def write_in_txt(check_result, output_path): 211 modes = stat.S_IRWXO | stat.S_IRWXG | stat.S_IRWXU 212 fd = os.open(output_path, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, mode=modes) 213 os.write(fd, check_result.encode()) 214 os.close(fd) 215 216 217def do_diff(old_dir, new_dir): 218 old_file_list = os.listdir(old_dir) 219 new_file_list = os.listdir(new_dir) 220 diff_list(old_file_list, new_file_list, old_dir, new_dir) 221 222 223def get_file_ext(file_name): 224 return os.path.splitext(file_name)[1] 225 226 227def diff_list(old_file_list, new_file_list, old_dir, new_dir): 228 all_list = set(old_file_list + new_file_list) 229 if len(all_list) == 0: 230 return 231 for target_file in all_list: 232 if (get_file_ext(target_file) != '.h' 233 and get_file_ext(target_file) != ''): 234 continue 235 if (target_file in old_file_list 236 and target_file not in new_file_list): 237 diff_file_path = os.path.join(old_dir, target_file) 238 del_old_file(diff_file_path) 239 if (target_file in new_file_list 240 and target_file not in old_file_list): 241 diff_file_path = os.path.join(new_dir, target_file) 242 add_new_file(diff_file_path) 243 get_same_file_diff(target_file, old_file_list, new_file_list, old_dir, new_dir) 244 245 246def add_new_file(diff_file_path): 247 if os.path.isdir(diff_file_path): 248 add_file(diff_file_path) 249 else: 250 result_map = parse_file_result(parser_include_ast(global_new_dir, [diff_file_path], flag=1)) 251 for new_info in result_map.values(): 252 diff_info_list.extend(judgment_entrance(None, new_info)) 253 254 255def del_old_file(diff_file_path): 256 if os.path.isdir(diff_file_path): 257 del_file(diff_file_path) 258 else: 259 result_map = parse_file_result(parser_include_ast(global_old_dir, [diff_file_path], flag=0)) 260 for old_info in result_map.values(): 261 diff_info_list.extend(judgment_entrance(old_info, None)) 262 263 264def get_same_file_diff(target_file, old_file_list, new_file_list, old_dir, new_dir): 265 if (target_file in old_file_list 266 and target_file in new_file_list): 267 if (os.path.isdir(os.path.join(old_dir, target_file)) 268 and os.path.isdir(os.path.join(new_dir, target_file))): 269 old_child_dir = os.path.join(old_dir, target_file) 270 new_child_dir = os.path.join(new_dir, target_file) 271 do_diff(old_child_dir, new_child_dir) 272 if (os.path.isfile(os.path.join(old_dir, target_file)) 273 and os.path.isfile(os.path.join(new_dir, target_file))): 274 old_target_file = os.path.join(old_dir, target_file) 275 new_target_file = os.path.join(new_dir, target_file) 276 if not filecmp.cmp(old_target_file, new_target_file): 277 get_file_result_diff(old_target_file, new_target_file) 278 279 280def get_file_result_diff(old_target_file, new_target_file): 281 old_file_result_map = parse_file_result(parser_include_ast(global_old_dir, [old_target_file], flag=0)) 282 new_file_result_map = parse_file_result(parser_include_ast(global_new_dir, [new_target_file], flag=1)) 283 merged_dict = OrderedDict(list(old_file_result_map.items()) + list(new_file_result_map.items())) 284 all_key_list = merged_dict.keys() 285 for key in all_key_list: 286 diff_info_list.extend(judgment_entrance(old_file_result_map.get(key), new_file_result_map.get(key))) 287 288 289def del_file(dir_path): 290 file_list = os.listdir(dir_path) 291 for i in file_list: 292 if get_file_ext(i) != '.h' and get_file_ext(i) != '': 293 continue 294 file_path = os.path.join(dir_path, i) 295 if os.path.isdir(file_path): 296 del_file(file_path) 297 if get_file_ext(i) == '.h': 298 result_map = parse_file_result(parser_include_ast(global_old_dir, [file_path], flag=0)) 299 for old_info in result_map.values(): 300 diff_info_list.extend(judgment_entrance(old_info, None)) 301 302 303def add_file(dir_path): 304 file_list = os.listdir(dir_path) 305 for i in file_list: 306 if get_file_ext(i) != '.h' and get_file_ext(i) != '': 307 continue 308 file_path = os.path.join(dir_path, i) 309 if os.path.isdir(file_path): 310 add_file(file_path) 311 if get_file_ext(i) == '.h': 312 result_map = parse_file_result(parser_include_ast(global_new_dir, [file_path], flag=1)) 313 for new_info in result_map.values(): 314 diff_info_list.extend(judgment_entrance(None, new_info)) 315 316 317def parse_file_result(result, data_type=0): 318 """ 319 Args: 320 result: *** 321 data_type(int): 数据处理类型。1-文件新增或删除;0-其他 322 """ 323 result_map = {} 324 for root_node in result: 325 if data_type != 1: 326 parse_file_result_by_child(result_map, root_node) 327 result_map.setdefault(f'{root_node["name"]}-{root_node["kind"]}', root_node) 328 return result_map 329 330 331def parse_file_result_by_child(result_map, root_node): 332 children_list = root_node['children'] 333 for children in children_list: 334 if children["name"] == '': 335 continue 336 result_map.setdefault(f'{children["name"]}-{children["kind"]}', children) 337 del root_node['children'] 338