1bae44755Sopenharmony_ci#!/usr/bin/env python3
2bae44755Sopenharmony_ci# -*- coding: utf-8 -*-
3bae44755Sopenharmony_ci# Copyright (c) 2023 Huawei Device Co., Ltd.
4bae44755Sopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
5bae44755Sopenharmony_ci# you may not use this file except in compliance with the License.
6bae44755Sopenharmony_ci# You may obtain a copy of the License at
7bae44755Sopenharmony_ci#
8bae44755Sopenharmony_ci#     http://www.apache.org/licenses/LICENSE-2.0
9bae44755Sopenharmony_ci#
10bae44755Sopenharmony_ci# Unless required by applicable law or agreed to in writing, software
11bae44755Sopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
12bae44755Sopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bae44755Sopenharmony_ci# See the License for the specific language governing permissions and
14bae44755Sopenharmony_ci# limitations under the License.
15bae44755Sopenharmony_ciimport logging
16bae44755Sopenharmony_ciimport os
17bae44755Sopenharmony_ciimport json
18bae44755Sopenharmony_ciimport argparse
19bae44755Sopenharmony_ciimport stat
20bae44755Sopenharmony_cifrom collections import Counter
21bae44755Sopenharmony_ci
22bae44755Sopenharmony_ci
23bae44755Sopenharmony_cidef get_args():
24bae44755Sopenharmony_ci    parser = argparse.ArgumentParser(add_help=True)
25bae44755Sopenharmony_ci    parser.add_argument(
26bae44755Sopenharmony_ci        "-p",
27bae44755Sopenharmony_ci        "--project_path",
28bae44755Sopenharmony_ci        default=r"",
29bae44755Sopenharmony_ci        type=str,
30bae44755Sopenharmony_ci        help="root path of project. default: ./",
31bae44755Sopenharmony_ci    )
32bae44755Sopenharmony_ci    args = parser.parse_args()
33bae44755Sopenharmony_ci    return args
34bae44755Sopenharmony_ci
35bae44755Sopenharmony_ci
36bae44755Sopenharmony_cidef dict_to_json(output_path: str, syscaps_dict: dict):
37bae44755Sopenharmony_ci    """
38bae44755Sopenharmony_ci    output diff product syscaps json to output path
39bae44755Sopenharmony_ci    :param output_path:
40bae44755Sopenharmony_ci    :param syscaps_dict:
41bae44755Sopenharmony_ci    :return:
42bae44755Sopenharmony_ci    """
43bae44755Sopenharmony_ci    print("start generate syscap json...")
44bae44755Sopenharmony_ci    flags = os.O_WRONLY | os.O_CREAT
45bae44755Sopenharmony_ci    modes = stat.S_IWUSR | stat.S_IRUSR
46bae44755Sopenharmony_ci    for product_name, syscaps_list in syscaps_dict.items():
47bae44755Sopenharmony_ci        counts = Counter(syscaps_list)
48bae44755Sopenharmony_ci        duplicates = [elem for elem, count in counts.items() if count > 1]
49bae44755Sopenharmony_ci        if len(duplicates) > 0:
50bae44755Sopenharmony_ci            print("[Warning] repeated syscap: {}".format(",".join(duplicates)))
51bae44755Sopenharmony_ci            syscaps_list = list(set(syscaps_list))
52bae44755Sopenharmony_ci        filename = os.path.join(output_path, f'{product_name}.json')
53bae44755Sopenharmony_ci        with os.fdopen(os.open(filename, flags, modes), 'w') as f:
54bae44755Sopenharmony_ci            json.dump({'SysCaps': syscaps_list}, f, indent=4)
55bae44755Sopenharmony_ci    print("end...")
56bae44755Sopenharmony_ci
57bae44755Sopenharmony_ci
58bae44755Sopenharmony_cidef check_syscap(syscap_str: str):
59bae44755Sopenharmony_ci    syscap = syscap_str.split(' = ')
60bae44755Sopenharmony_ci    if syscap[-1].lower() == 'false':
61bae44755Sopenharmony_ci        return False
62bae44755Sopenharmony_ci    else:
63bae44755Sopenharmony_ci        return syscap[0]
64bae44755Sopenharmony_ci
65bae44755Sopenharmony_ci
66bae44755Sopenharmony_cidef bundle_syscap_list_handler(bundle_syscap_list: list, component_syscaps_list: list):
67bae44755Sopenharmony_ci    """
68bae44755Sopenharmony_ci    check syscap
69bae44755Sopenharmony_ci    :param bundle_syscap_list:
70bae44755Sopenharmony_ci    :param component_syscaps_list:
71bae44755Sopenharmony_ci    :return:
72bae44755Sopenharmony_ci    """
73bae44755Sopenharmony_ci    for component_syscap in component_syscaps_list:
74bae44755Sopenharmony_ci        component_syscap = check_syscap(component_syscap)
75bae44755Sopenharmony_ci        if component_syscap:
76bae44755Sopenharmony_ci            bundle_syscap_list.append(component_syscap)
77bae44755Sopenharmony_ci    return bundle_syscap_list
78bae44755Sopenharmony_ci
79bae44755Sopenharmony_ci
80bae44755Sopenharmony_cidef read_json_file(bundle_json_path: str):
81bae44755Sopenharmony_ci    bundle_syscap_list = list()
82bae44755Sopenharmony_ci    error_list = dict()
83bae44755Sopenharmony_ci    try:
84bae44755Sopenharmony_ci        with open(bundle_json_path, 'r', encoding='utf-8') as f:
85bae44755Sopenharmony_ci            bundle_data = json.load(f)
86bae44755Sopenharmony_ci            component_data = bundle_data.get("component")
87bae44755Sopenharmony_ci            component_syscaps_list = component_data.get("syscap")
88bae44755Sopenharmony_ci            if component_syscaps_list:
89bae44755Sopenharmony_ci                bundle_syscap_list = bundle_syscap_list_handler(bundle_syscap_list, component_syscaps_list)
90bae44755Sopenharmony_ci    except FileNotFoundError as e:
91bae44755Sopenharmony_ci        error_list[bundle_json_path] = str(e)
92bae44755Sopenharmony_ci    except Exception as e:
93bae44755Sopenharmony_ci        error_list[bundle_json_path] = str(e)
94bae44755Sopenharmony_ci    return bundle_syscap_list, error_list
95bae44755Sopenharmony_ci
96bae44755Sopenharmony_ci
97bae44755Sopenharmony_cidef get_all_components_path(components_file_path: str):
98bae44755Sopenharmony_ci    try:
99bae44755Sopenharmony_ci        with open(components_file_path, 'r', encoding='utf-8') as f:
100bae44755Sopenharmony_ci            path_dict = json.load(f)
101bae44755Sopenharmony_ci        return path_dict
102bae44755Sopenharmony_ci    except FileNotFoundError:
103bae44755Sopenharmony_ci        logging.error(r"PATH ERROR")
104bae44755Sopenharmony_ci        return {}
105bae44755Sopenharmony_ci
106bae44755Sopenharmony_ci
107bae44755Sopenharmony_cidef path_component_to_bundle(path: str) -> str:
108bae44755Sopenharmony_ci    bundle_json_path = os.path.join(path, 'bundle.json')
109bae44755Sopenharmony_ci    return bundle_json_path
110bae44755Sopenharmony_ci
111bae44755Sopenharmony_ci
112bae44755Sopenharmony_cidef find_false_syscap(syscap_l: list):
113bae44755Sopenharmony_ci    res = []
114bae44755Sopenharmony_ci    for syscap in syscap_l:
115bae44755Sopenharmony_ci        if not check_syscap(syscap):
116bae44755Sopenharmony_ci            res.append(syscap.split('=')[0].strip())
117bae44755Sopenharmony_ci    return res
118bae44755Sopenharmony_ci
119bae44755Sopenharmony_ci
120bae44755Sopenharmony_cidef handle_bundle_json_file(component_path_dict: dict, product_define_dict: dict):
121bae44755Sopenharmony_ci    """
122bae44755Sopenharmony_ci    from product required part bundle.json to all products parts list
123bae44755Sopenharmony_ci    :param component_path_dict:
124bae44755Sopenharmony_ci    :return: all products parts list
125bae44755Sopenharmony_ci    """
126bae44755Sopenharmony_ci    print("start collect syscap path...")
127bae44755Sopenharmony_ci    syscap_dict = dict()
128bae44755Sopenharmony_ci    errors_list = list()
129bae44755Sopenharmony_ci    for product_name, path_dict in component_path_dict.items():
130bae44755Sopenharmony_ci        bundles_list = list()
131bae44755Sopenharmony_ci        for component in path_dict.keys():
132bae44755Sopenharmony_ci            path = path_dict.get(component)
133bae44755Sopenharmony_ci            bundle_json_path = path_component_to_bundle(path)
134bae44755Sopenharmony_ci            bundle_syscap_list, error_list = read_json_file(bundle_json_path)
135bae44755Sopenharmony_ci            if product_define_dict.get(product_name).get(component):
136bae44755Sopenharmony_ci                false_syscap = find_false_syscap(product_define_dict.get(product_name).get(component))
137bae44755Sopenharmony_ci                bundle_syscap_l = [sc for sc in bundle_syscap_list if sc not in false_syscap]
138bae44755Sopenharmony_ci                bundles_list.extend(bundle_syscap_l)
139bae44755Sopenharmony_ci            else:
140bae44755Sopenharmony_ci                bundles_list.extend(bundle_syscap_list)
141bae44755Sopenharmony_ci            errors_list.extend(error_list)
142bae44755Sopenharmony_ci        syscap_dict.update({product_name: bundles_list})
143bae44755Sopenharmony_ci    return syscap_dict, errors_list
144bae44755Sopenharmony_ci
145bae44755Sopenharmony_ci
146bae44755Sopenharmony_cidef format_component_path(component_path: str):
147bae44755Sopenharmony_ci    sep_list = ['\\', '/']
148bae44755Sopenharmony_ci    sep_list.remove(os.sep)
149bae44755Sopenharmony_ci    component_path = component_path.replace(sep_list[0], os.sep)
150bae44755Sopenharmony_ci    return component_path
151bae44755Sopenharmony_ci
152bae44755Sopenharmony_ci
153bae44755Sopenharmony_cidef traversal_path(parts_path_info: dict, project_path: str, product_define_dict):
154bae44755Sopenharmony_ci    component_path_dict = dict()
155bae44755Sopenharmony_ci    for product_name, component_name_list in product_define_dict.items():
156bae44755Sopenharmony_ci        component_paths = dict()
157bae44755Sopenharmony_ci        for component_name in component_name_list.keys():
158bae44755Sopenharmony_ci            component_relpath = parts_path_info.get(component_name)
159bae44755Sopenharmony_ci            if component_relpath:
160bae44755Sopenharmony_ci                component_path = os.path.join(project_path, component_relpath)
161bae44755Sopenharmony_ci                component_path = format_component_path(component_path)
162bae44755Sopenharmony_ci                component_paths[component_name] = component_path
163bae44755Sopenharmony_ci            else:
164bae44755Sopenharmony_ci                logging.error(f'can\'t find component_name : {component_name}')
165bae44755Sopenharmony_ci        component_path_dict.update({product_name: component_paths})
166bae44755Sopenharmony_ci    return component_path_dict
167bae44755Sopenharmony_ci
168bae44755Sopenharmony_ci
169bae44755Sopenharmony_cidef collect_all_product_component_syscap_dict(parts_path_info: dict, project_path: str, product_define_dict):
170bae44755Sopenharmony_ci    """
171bae44755Sopenharmony_ci    get all syscap to dict
172bae44755Sopenharmony_ci    :param parts_path_info:
173bae44755Sopenharmony_ci    :param project_path:
174bae44755Sopenharmony_ci    :param product_define_dict:
175bae44755Sopenharmony_ci    :return:
176bae44755Sopenharmony_ci    """
177bae44755Sopenharmony_ci    if parts_path_info:
178bae44755Sopenharmony_ci        print("start collect component path...")
179bae44755Sopenharmony_ci        component_path_dict = traversal_path(parts_path_info, project_path, product_define_dict)
180bae44755Sopenharmony_ci        syscap_dict, errors_list = handle_bundle_json_file(component_path_dict, product_define_dict)
181bae44755Sopenharmony_ci        return syscap_dict, errors_list
182bae44755Sopenharmony_ci    else:
183bae44755Sopenharmony_ci        return 0, 0
184bae44755Sopenharmony_ci
185bae44755Sopenharmony_ci
186bae44755Sopenharmony_cidef get_subsystem_info(subsystem_config_file, source_root_dir):
187bae44755Sopenharmony_ci    """
188bae44755Sopenharmony_ci    get subsystem name and subsystem path from oh/build/subsystem_config.json
189bae44755Sopenharmony_ci    :param subsystem_config_file: subsystem_config_file path
190bae44755Sopenharmony_ci    :param source_root_dir: oh project path
191bae44755Sopenharmony_ci    :return: subsystem name and subsystem path
192bae44755Sopenharmony_ci    """
193bae44755Sopenharmony_ci    subsystem_configs = scan(subsystem_config_file, source_root_dir)
194bae44755Sopenharmony_ci    _all_components_path = []
195bae44755Sopenharmony_ci    for _, value in subsystem_configs.get('subsystem').items():
196bae44755Sopenharmony_ci        for i in value.get('build_files'):
197bae44755Sopenharmony_ci            _all_components_path.append(i)
198bae44755Sopenharmony_ci    return subsystem_configs.get('subsystem')
199bae44755Sopenharmony_ci
200bae44755Sopenharmony_ci
201bae44755Sopenharmony_cidef _check_path_prefix(paths):
202bae44755Sopenharmony_ci    allow_path_prefix = ['vendor', 'device']
203bae44755Sopenharmony_ci    result = list(
204bae44755Sopenharmony_ci        filter(lambda x: x is False,
205bae44755Sopenharmony_ci               map(lambda p: p.split('/')[0] in allow_path_prefix, paths)))
206bae44755Sopenharmony_ci    return len(result) <= 1
207bae44755Sopenharmony_ci
208bae44755Sopenharmony_ci
209bae44755Sopenharmony_cidef traversal_files(subsystem_path, _files):
210bae44755Sopenharmony_ci    for item in os.scandir(subsystem_path):
211bae44755Sopenharmony_ci        if is_symlink(item.path):
212bae44755Sopenharmony_ci            continue
213bae44755Sopenharmony_ci        elif item.is_file() and item.name == 'ohos.build':
214bae44755Sopenharmony_ci            _files.append(item.path)
215bae44755Sopenharmony_ci        elif item.is_file() and item.name == 'bundle.json':
216bae44755Sopenharmony_ci            _files.append(item.path)
217bae44755Sopenharmony_ci        elif item.is_dir():
218bae44755Sopenharmony_ci            traversal_files(item, _files)
219bae44755Sopenharmony_ci    return _files
220bae44755Sopenharmony_ci
221bae44755Sopenharmony_ci
222bae44755Sopenharmony_cidef get_file_type(file_path):
223bae44755Sopenharmony_ci    if os.path.islink(file_path):
224bae44755Sopenharmony_ci        return 'symlink'
225bae44755Sopenharmony_ci    elif os.path.isfile(file_path):
226bae44755Sopenharmony_ci        return 'file'
227bae44755Sopenharmony_ci    elif os.path.isdir(file_path):
228bae44755Sopenharmony_ci        return 'directory'
229bae44755Sopenharmony_ci    else:
230bae44755Sopenharmony_ci        return 'unknown'
231bae44755Sopenharmony_ci
232bae44755Sopenharmony_ci
233bae44755Sopenharmony_cidef is_symlink(file_path):
234bae44755Sopenharmony_ci    file_type = get_file_type(file_path)
235bae44755Sopenharmony_ci    if file_type == 'symlink':
236bae44755Sopenharmony_ci        link_target = os.readlink(file_path)
237bae44755Sopenharmony_ci        return link_target != file_type
238bae44755Sopenharmony_ci    return False
239bae44755Sopenharmony_ci
240bae44755Sopenharmony_ci
241bae44755Sopenharmony_cidef _scan_build_file(subsystem_path):
242bae44755Sopenharmony_ci    _files = []
243bae44755Sopenharmony_ci    _bundle_files = []
244bae44755Sopenharmony_ci    try:
245bae44755Sopenharmony_ci        _files = traversal_files(subsystem_path, _files)
246bae44755Sopenharmony_ci    except FileNotFoundError:
247bae44755Sopenharmony_ci        print(f"read file {subsystem_path} failed.")
248bae44755Sopenharmony_ci    return _files
249bae44755Sopenharmony_ci
250bae44755Sopenharmony_ci
251bae44755Sopenharmony_cidef scan(subsystem_config_file, source_root_dir):
252bae44755Sopenharmony_ci    subsystem_infos = _read_config(subsystem_config_file)
253bae44755Sopenharmony_ci    _default_subsystem = {"build": "build"}
254bae44755Sopenharmony_ci    subsystem_infos.update(_default_subsystem)
255bae44755Sopenharmony_ci    no_src_subsystem = {}
256bae44755Sopenharmony_ci    _build_configs = {}
257bae44755Sopenharmony_ci    for key, val in subsystem_infos.items():
258bae44755Sopenharmony_ci        _all_build_config_files = []
259bae44755Sopenharmony_ci        if not isinstance(val, list):
260bae44755Sopenharmony_ci            val = [val]
261bae44755Sopenharmony_ci        else:
262bae44755Sopenharmony_ci            if not _check_path_prefix(val):
263bae44755Sopenharmony_ci                raise Exception("subsystem '{}' path configuration is incorrect.".format(key), "2013")
264bae44755Sopenharmony_ci        _info = {'path': val}
265bae44755Sopenharmony_ci        for _path in val:
266bae44755Sopenharmony_ci            _subsystem_path = os.path.join(source_root_dir, _path)
267bae44755Sopenharmony_ci            _build_config_files = _scan_build_file(_subsystem_path)
268bae44755Sopenharmony_ci            _all_build_config_files.extend(_build_config_files)
269bae44755Sopenharmony_ci        if _all_build_config_files:
270bae44755Sopenharmony_ci            _info['build_files'] = _all_build_config_files
271bae44755Sopenharmony_ci            _build_configs[key] = _info
272bae44755Sopenharmony_ci        else:
273bae44755Sopenharmony_ci            no_src_subsystem[key] = val
274bae44755Sopenharmony_ci
275bae44755Sopenharmony_ci    scan_result = {
276bae44755Sopenharmony_ci        'source_path': source_root_dir,
277bae44755Sopenharmony_ci        'subsystem': _build_configs,
278bae44755Sopenharmony_ci    }
279bae44755Sopenharmony_ci    print('subsystem config scan completed')
280bae44755Sopenharmony_ci    return scan_result
281bae44755Sopenharmony_ci
282bae44755Sopenharmony_ci
283bae44755Sopenharmony_cidef _read_config(subsystem_config_file):
284bae44755Sopenharmony_ci    if not os.path.exists(subsystem_config_file):
285bae44755Sopenharmony_ci        raise Exception("config file '{}' doesn't exist.".format(subsystem_config_file), "2013")
286bae44755Sopenharmony_ci    subsystem_config = _read_json_file(subsystem_config_file)
287bae44755Sopenharmony_ci    if subsystem_config is None:
288bae44755Sopenharmony_ci        raise Exception("read file '{}' failed.".format(subsystem_config_file), "2013")
289bae44755Sopenharmony_ci
290bae44755Sopenharmony_ci    subsystem_info = {}
291bae44755Sopenharmony_ci    for key, val in subsystem_config.items():
292bae44755Sopenharmony_ci        if 'path' not in val:
293bae44755Sopenharmony_ci            raise Exception("subsystem '{}' not config path.".format(key), "2013")
294bae44755Sopenharmony_ci        subsystem_info[key] = val.get('path')
295bae44755Sopenharmony_ci    return subsystem_info
296bae44755Sopenharmony_ci
297bae44755Sopenharmony_ci
298bae44755Sopenharmony_cidef read_build_file(ohos_build_file):
299bae44755Sopenharmony_ci    if not os.path.exists(ohos_build_file):
300bae44755Sopenharmony_ci        raise Exception("config file '{}' doesn't exist.".format(ohos_build_file), "2014")
301bae44755Sopenharmony_ci    subsystem_config = _read_json_file(ohos_build_file)
302bae44755Sopenharmony_ci    if not subsystem_config:
303bae44755Sopenharmony_ci        raise Exception("read file '{}' failed.".format(ohos_build_file), "2014")
304bae44755Sopenharmony_ci    return subsystem_config
305bae44755Sopenharmony_ci
306bae44755Sopenharmony_ci
307bae44755Sopenharmony_ciclass BundlePartObj(object):
308bae44755Sopenharmony_ci    def __init__(self, bundle_config_file):
309bae44755Sopenharmony_ci        self._build_config_file = bundle_config_file
310bae44755Sopenharmony_ci        self._loading_config()
311bae44755Sopenharmony_ci
312bae44755Sopenharmony_ci    def to_ohos_build(self):
313bae44755Sopenharmony_ci        _component_info = self.bundle_info.get('component')
314bae44755Sopenharmony_ci        _subsystem_name = _component_info.get('subsystem')
315bae44755Sopenharmony_ci        _part_name = _component_info.get('name')
316bae44755Sopenharmony_ci        _bundle_build = _component_info.get('build')
317bae44755Sopenharmony_ci        _ohos_build_info = dict()
318bae44755Sopenharmony_ci        _ohos_build_info['subsystem'] = _subsystem_name
319bae44755Sopenharmony_ci        _part_info = {}
320bae44755Sopenharmony_ci        module_list = []
321bae44755Sopenharmony_ci        if _component_info.get('build').__contains__('sub_component'):
322bae44755Sopenharmony_ci            _part_info['module_list'] = _component_info.get('build').get(
323bae44755Sopenharmony_ci                'sub_component')
324bae44755Sopenharmony_ci        elif _component_info.get('build').__contains__('modules'):
325bae44755Sopenharmony_ci            _part_info['module_list'] = _component_info.get(
326bae44755Sopenharmony_ci                'build').get('modules')
327bae44755Sopenharmony_ci        elif _component_info.get('build').__contains__('group_type'):
328bae44755Sopenharmony_ci            _module_groups = _component_info.get('build').get('group_type')
329bae44755Sopenharmony_ci            for _group_type, _module_list in _module_groups.items():
330bae44755Sopenharmony_ci                _key = '{}:{}'.format(_subsystem_name, _part_name)
331bae44755Sopenharmony_ci            _part_info['module_list'] = module_list
332bae44755Sopenharmony_ci        if 'inner_kits' in _bundle_build:
333bae44755Sopenharmony_ci            _part_info['inner_kits'] = _bundle_build.get('inner_kits')
334bae44755Sopenharmony_ci        elif 'inner_api' in _bundle_build:
335bae44755Sopenharmony_ci            _part_info['inner_kits'] = _bundle_build.get('inner_api')
336bae44755Sopenharmony_ci        if 'features' in _component_info:
337bae44755Sopenharmony_ci            _part_info['feature_list'] = _component_info.get('features')
338bae44755Sopenharmony_ci        if 'syscap' in _component_info:
339bae44755Sopenharmony_ci            _part_info['system_capabilities'] = _component_info.get('syscap')
340bae44755Sopenharmony_ci        if 'hisysevent_config' in _component_info:
341bae44755Sopenharmony_ci            _part_info['hisysevent_config'] = _component_info.get(
342bae44755Sopenharmony_ci                'hisysevent_config')
343bae44755Sopenharmony_ci        _part_info['part_deps'] = _component_info.get('deps', {})
344bae44755Sopenharmony_ci        _part_info['part_deps']['build_config_file'] = self._build_config_file
345bae44755Sopenharmony_ci        _ohos_build_info['parts'] = {_part_name: _part_info}
346bae44755Sopenharmony_ci        return _ohos_build_info
347bae44755Sopenharmony_ci
348bae44755Sopenharmony_ci    def _loading_config(self):
349bae44755Sopenharmony_ci        if not os.path.exists(self._build_config_file):
350bae44755Sopenharmony_ci            raise Exception("file '{}' doesn't exist.".format(
351bae44755Sopenharmony_ci                self._build_config_file), "2011")
352bae44755Sopenharmony_ci        self.bundle_info = _read_json_file(self._build_config_file)
353bae44755Sopenharmony_ci        if not self.bundle_info:
354bae44755Sopenharmony_ci            raise Exception("read file '{}' failed.".format(
355bae44755Sopenharmony_ci                self._build_config_file), "2011")
356bae44755Sopenharmony_ci
357bae44755Sopenharmony_ci
358bae44755Sopenharmony_ciclass LoadBuildConfig(object):
359bae44755Sopenharmony_ci    """load build config file and parse configuration info."""
360bae44755Sopenharmony_ci
361bae44755Sopenharmony_ci    def __init__(self, source_root_dir, subsystem_build_info, subsystem_name):
362bae44755Sopenharmony_ci        self._source_root_dir = source_root_dir
363bae44755Sopenharmony_ci        self._build_info = subsystem_build_info
364bae44755Sopenharmony_ci        self._is_load = False
365bae44755Sopenharmony_ci        self._parts_variants = {}
366bae44755Sopenharmony_ci        self._part_list = {}
367bae44755Sopenharmony_ci        self._part_targets_label = {}
368bae44755Sopenharmony_ci        self._subsystem_name = subsystem_name
369bae44755Sopenharmony_ci        self._parts_info_dict = {}
370bae44755Sopenharmony_ci        self._phony_targets = {}
371bae44755Sopenharmony_ci        self._parts_path_dict = {}
372bae44755Sopenharmony_ci        self._part_hisysevent_config = {}
373bae44755Sopenharmony_ci        self._parts_module_list = {}
374bae44755Sopenharmony_ci        self._parts_deps = {}
375bae44755Sopenharmony_ci
376bae44755Sopenharmony_ci    def parse(self):
377bae44755Sopenharmony_ci        """parse part info from build config file."""
378bae44755Sopenharmony_ci        if self._is_load:
379bae44755Sopenharmony_ci            return
380bae44755Sopenharmony_ci        subsystem_config, parts_path_dict = self._merge_build_config()
381bae44755Sopenharmony_ci        parts_config = subsystem_config.get('parts')
382bae44755Sopenharmony_ci        self._parts_module_list.update(parts_config)
383bae44755Sopenharmony_ci        self._parts_path_dict = parts_path_dict
384bae44755Sopenharmony_ci        self._is_load = True
385bae44755Sopenharmony_ci
386bae44755Sopenharmony_ci    def parts_path_info(self):
387bae44755Sopenharmony_ci        """parts to path info."""
388bae44755Sopenharmony_ci        self.parse()
389bae44755Sopenharmony_ci        return self._parts_path_dict
390bae44755Sopenharmony_ci
391bae44755Sopenharmony_ci    def parts_info_filter(self, save_part):
392bae44755Sopenharmony_ci        if save_part is None:
393bae44755Sopenharmony_ci            raise Exception
394bae44755Sopenharmony_ci        self._parts_info_dict = {
395bae44755Sopenharmony_ci            key: value for key, value in self._parts_info_dict.items() if key in save_part}
396bae44755Sopenharmony_ci
397bae44755Sopenharmony_ci    def _merge_build_config(self):
398bae44755Sopenharmony_ci        _build_files = self._build_info.get('build_files')
399bae44755Sopenharmony_ci        is_thirdparty_subsystem = False
400bae44755Sopenharmony_ci        if _build_files[0].startswith(self._source_root_dir + 'third_party'):
401bae44755Sopenharmony_ci            is_thirdparty_subsystem = True
402bae44755Sopenharmony_ci        subsystem_name = None
403bae44755Sopenharmony_ci        parts_info = {}
404bae44755Sopenharmony_ci        parts_path_dict = {}
405bae44755Sopenharmony_ci        for _build_file in _build_files:
406bae44755Sopenharmony_ci            if _build_file.endswith('bundle.json'):
407bae44755Sopenharmony_ci                bundle_part_obj = BundlePartObj(_build_file)
408bae44755Sopenharmony_ci                _parts_config = bundle_part_obj.to_ohos_build()
409bae44755Sopenharmony_ci            else:
410bae44755Sopenharmony_ci                _parts_config = read_build_file(_build_file)
411bae44755Sopenharmony_ci            _subsystem_name = _parts_config.get('subsystem')
412bae44755Sopenharmony_ci            if not is_thirdparty_subsystem and subsystem_name and _subsystem_name != subsystem_name:
413bae44755Sopenharmony_ci                raise Exception(
414bae44755Sopenharmony_ci                    "subsystem name config incorrect in '{}'.".format(
415bae44755Sopenharmony_ci                        _build_file), "2014")
416bae44755Sopenharmony_ci            subsystem_name = _subsystem_name
417bae44755Sopenharmony_ci            _curr_parts_info = _parts_config.get('parts')
418bae44755Sopenharmony_ci            for _pname in _curr_parts_info.keys():
419bae44755Sopenharmony_ci                parts_path_dict[_pname] = os.path.relpath(
420bae44755Sopenharmony_ci                    os.path.dirname(_build_file), self._source_root_dir)
421bae44755Sopenharmony_ci            parts_info.update(_curr_parts_info)
422bae44755Sopenharmony_ci        subsystem_config = dict()
423bae44755Sopenharmony_ci        subsystem_config['subsystem'] = subsystem_name
424bae44755Sopenharmony_ci        subsystem_config['parts'] = parts_info
425bae44755Sopenharmony_ci        return subsystem_config, parts_path_dict
426bae44755Sopenharmony_ci
427bae44755Sopenharmony_ci
428bae44755Sopenharmony_cidef get_parts_info(source_root_dir, subsystem_info, build_xts=False):
429bae44755Sopenharmony_ci    """
430bae44755Sopenharmony_ci    get parts path info from subsystem info
431bae44755Sopenharmony_ci    :param source_root_dir: oh project path
432bae44755Sopenharmony_ci    :param subsystem_info:
433bae44755Sopenharmony_ci    :param build_xts:
434bae44755Sopenharmony_ci    :return: parts path info
435bae44755Sopenharmony_ci    """
436bae44755Sopenharmony_ci    _phony_target = {}
437bae44755Sopenharmony_ci    _parts_path_info = {}
438bae44755Sopenharmony_ci    _parts_hisysevent_config = {}
439bae44755Sopenharmony_ci    _parts_modules_info = {}
440bae44755Sopenharmony_ci    _parts_deps = {}
441bae44755Sopenharmony_ci    for subsystem_name, build_config_info in subsystem_info.items():
442bae44755Sopenharmony_ci        if not len(build_config_info.get("build_files")):
443bae44755Sopenharmony_ci            continue
444bae44755Sopenharmony_ci        build_loader = LoadBuildConfig(source_root_dir, build_config_info, subsystem_name)
445bae44755Sopenharmony_ci        if subsystem_name == 'xts' and build_xts is False:
446bae44755Sopenharmony_ci            xts_device_attest_name = ['device_attest_lite', 'device_attest']
447bae44755Sopenharmony_ci            build_loader.parse()
448bae44755Sopenharmony_ci            build_loader.parts_info_filter(xts_device_attest_name)
449bae44755Sopenharmony_ci        _parts_path_info.update(build_loader.parts_path_info())
450bae44755Sopenharmony_ci    return _parts_path_info
451bae44755Sopenharmony_ci
452bae44755Sopenharmony_ci
453bae44755Sopenharmony_cidef _read_json_file(input_file):
454bae44755Sopenharmony_ci    if not os.path.exists(input_file):
455bae44755Sopenharmony_ci        print("file '{}' doesn't exist.".format(input_file))
456bae44755Sopenharmony_ci        return {}
457bae44755Sopenharmony_ci    try:
458bae44755Sopenharmony_ci        with open(input_file, 'r') as input_f:
459bae44755Sopenharmony_ci            data = json.load(input_f)
460bae44755Sopenharmony_ci        return data
461bae44755Sopenharmony_ci    except json.decoder.JSONDecodeError:
462bae44755Sopenharmony_ci        print("The file '{}' format is incorrect.".format(input_file))
463bae44755Sopenharmony_ci        raise
464bae44755Sopenharmony_ci    except Exception:
465bae44755Sopenharmony_ci        print("read file '{}' failed.".format(input_file))
466bae44755Sopenharmony_ci        raise
467bae44755Sopenharmony_ci
468bae44755Sopenharmony_ci
469bae44755Sopenharmony_cidef get_product_define_path(source_root_dir):
470bae44755Sopenharmony_ci    return os.path.join(source_root_dir, 'productdefine', 'common', 'inherit')
471bae44755Sopenharmony_ci
472bae44755Sopenharmony_ci
473bae44755Sopenharmony_cidef components_list_handler(product_file_json):
474bae44755Sopenharmony_ci    components_dict = dict()
475bae44755Sopenharmony_ci    for subsystems in product_file_json.get('subsystems'):
476bae44755Sopenharmony_ci        for components in subsystems.get('components'):
477bae44755Sopenharmony_ci            components_dict[components.get('component')] = components.get('syscap')
478bae44755Sopenharmony_ci
479bae44755Sopenharmony_ci    return components_dict
480bae44755Sopenharmony_ci
481bae44755Sopenharmony_ci
482bae44755Sopenharmony_cidef product_component_handler(product_file, product_file_path):
483bae44755Sopenharmony_ci    all_components_dict = dict()
484bae44755Sopenharmony_ci    components_dict = dict()
485bae44755Sopenharmony_ci    try:
486bae44755Sopenharmony_ci        with open(product_file_path, 'r', encoding='utf-8') as f:
487bae44755Sopenharmony_ci            product_file_json = json.load(f)
488bae44755Sopenharmony_ci            components_dict = components_list_handler(product_file_json)
489bae44755Sopenharmony_ci    except FileNotFoundError:
490bae44755Sopenharmony_ci        print(f"read file {product_file_path} failed.")
491bae44755Sopenharmony_ci    all_components_dict.update({product_file.split('.')[0]: components_dict})
492bae44755Sopenharmony_ci    return all_components_dict
493bae44755Sopenharmony_ci
494bae44755Sopenharmony_ci
495bae44755Sopenharmony_cidef collect_all_product_component(product_file_dict: dict):
496bae44755Sopenharmony_ci    all_components_dict = dict()
497bae44755Sopenharmony_ci    for product_file, product_file_path in product_file_dict.items():
498bae44755Sopenharmony_ci        product_components_dict = product_component_handler(product_file, product_file_path)
499bae44755Sopenharmony_ci        all_components_dict.update(product_components_dict)
500bae44755Sopenharmony_ci    return all_components_dict
501bae44755Sopenharmony_ci
502bae44755Sopenharmony_ci
503bae44755Sopenharmony_cidef get_product_define_dict(source_root_dir):
504bae44755Sopenharmony_ci    product_define_path = get_product_define_path(source_root_dir)
505bae44755Sopenharmony_ci    product_file_dict = dict()
506bae44755Sopenharmony_ci    for file in os.scandir(product_define_path):
507bae44755Sopenharmony_ci        if file.name.split('.')[-1] == 'json':
508bae44755Sopenharmony_ci            product_file_dict.update({file.name: os.path.join(product_define_path, file.name)})
509bae44755Sopenharmony_ci    product_define_dict = collect_all_product_component(product_file_dict)
510bae44755Sopenharmony_ci    return product_define_dict
511bae44755Sopenharmony_ci
512bae44755Sopenharmony_ci
513bae44755Sopenharmony_cidef output_path_handler(project_path):
514bae44755Sopenharmony_ci    output_path = os.path.join(project_path, 'interface', 'sdk-js', 'api', 'device-define-common')
515bae44755Sopenharmony_ci    folder = os.path.exists(output_path)
516bae44755Sopenharmony_ci    # 多线程创建文件夹问题
517bae44755Sopenharmony_ci    if not folder:
518bae44755Sopenharmony_ci        os.makedirs(output_path, exist_ok=True)
519bae44755Sopenharmony_ci    return output_path
520bae44755Sopenharmony_ci
521bae44755Sopenharmony_ci
522bae44755Sopenharmony_cidef project_path_handler(project_path):
523bae44755Sopenharmony_ci    if not project_path:
524bae44755Sopenharmony_ci        project_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
525bae44755Sopenharmony_ci    return project_path
526bae44755Sopenharmony_ci
527bae44755Sopenharmony_ci
528bae44755Sopenharmony_cidef main():
529bae44755Sopenharmony_ci    logging.basicConfig(level=logging.INFO)
530bae44755Sopenharmony_ci    args = get_args()
531bae44755Sopenharmony_ci    project_path = args.project_path
532bae44755Sopenharmony_ci    project_path = project_path_handler(project_path)
533bae44755Sopenharmony_ci    output_path = output_path_handler(project_path)
534bae44755Sopenharmony_ci    subsystem_config_file = os.path.join(project_path, 'build', 'subsystem_config.json')
535bae44755Sopenharmony_ci    product_define_dict = get_product_define_dict(project_path)
536bae44755Sopenharmony_ci    _subsystem_info = get_subsystem_info(subsystem_config_file, project_path)
537bae44755Sopenharmony_ci    _parts_path_info = get_parts_info(project_path, _subsystem_info)
538bae44755Sopenharmony_ci    syscap_dict, errors_list = collect_all_product_component_syscap_dict(_parts_path_info, project_path,
539bae44755Sopenharmony_ci                                                                         product_define_dict)
540bae44755Sopenharmony_ci    if syscap_dict:
541bae44755Sopenharmony_ci        dict_to_json(output_path, syscap_dict)
542bae44755Sopenharmony_ci
543bae44755Sopenharmony_ci
544bae44755Sopenharmony_ciif __name__ == "__main__":
545bae44755Sopenharmony_ci    main()