• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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