15f9996aaSopenharmony_ci#!/usr/bin/env python
25f9996aaSopenharmony_ci# -*- coding: utf-8 -*-
35f9996aaSopenharmony_ci
45f9996aaSopenharmony_ci#
55f9996aaSopenharmony_ci# Copyright (c) 2023 Huawei Device Co., Ltd.
65f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
75f9996aaSopenharmony_ci# you may not use this file except in compliance with the License.
85f9996aaSopenharmony_ci# You may obtain a copy of the License at
95f9996aaSopenharmony_ci#
105f9996aaSopenharmony_ci#     http://www.apache.org/licenses/LICENSE-2.0
115f9996aaSopenharmony_ci#
125f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software
135f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
145f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
155f9996aaSopenharmony_ci# See the License for the specific language governing permissions and
165f9996aaSopenharmony_ci# limitations under the License.
175f9996aaSopenharmony_ci
185f9996aaSopenharmony_ciimport os
195f9996aaSopenharmony_ciimport re
205f9996aaSopenharmony_cifrom collections import defaultdict
215f9996aaSopenharmony_ci
225f9996aaSopenharmony_cifrom util.io_util import IoUtil
235f9996aaSopenharmony_cifrom exceptions.ohos_exception import OHOSException
245f9996aaSopenharmony_cifrom resources.config import Config
255f9996aaSopenharmony_cifrom containers.status import throw_exception
265f9996aaSopenharmony_ci
275f9996aaSopenharmony_cifrom hb.helper.no_instance import NoInstance
285f9996aaSopenharmony_ci
295f9996aaSopenharmony_ci
305f9996aaSopenharmony_ciclass ProductUtil(metaclass=NoInstance):
315f9996aaSopenharmony_ci
325f9996aaSopenharmony_ci    @staticmethod
335f9996aaSopenharmony_ci    def get_products():
345f9996aaSopenharmony_ci        config = Config()
355f9996aaSopenharmony_ci        # ext products configuration
365f9996aaSopenharmony_ci        _ext_scan_path = os.path.join(config.root_path,
375f9996aaSopenharmony_ci                                      'out/products_ext/vendor')
385f9996aaSopenharmony_ci        if os.path.exists(_ext_scan_path):
395f9996aaSopenharmony_ci            for company in os.listdir(_ext_scan_path):
405f9996aaSopenharmony_ci                company_path = os.path.join(_ext_scan_path, company)
415f9996aaSopenharmony_ci                if not os.path.isdir(company_path):
425f9996aaSopenharmony_ci                    continue
435f9996aaSopenharmony_ci
445f9996aaSopenharmony_ci                for product in os.listdir(company_path):
455f9996aaSopenharmony_ci                    p_config_path = os.path.join(company_path, product)
465f9996aaSopenharmony_ci                    config_path = os.path.join(p_config_path, 'config.json')
475f9996aaSopenharmony_ci
485f9996aaSopenharmony_ci                    if os.path.isfile(config_path):
495f9996aaSopenharmony_ci                        info = IoUtil.read_json_file(config_path)
505f9996aaSopenharmony_ci                        product_name = info.get('product_name')
515f9996aaSopenharmony_ci                        if info.get('product_path'):
525f9996aaSopenharmony_ci                            product_path = os.path.join(
535f9996aaSopenharmony_ci                                config.root_path, info.get('product_path'))
545f9996aaSopenharmony_ci                        else:
555f9996aaSopenharmony_ci                            product_path = p_config_path
565f9996aaSopenharmony_ci                        if product_name is not None:
575f9996aaSopenharmony_ci                            subsystem_config_overlay_path = os.path.join(product_path,
585f9996aaSopenharmony_ci                                'subsystem_config_overlay.json')
595f9996aaSopenharmony_ci                            if os.path.isfile(subsystem_config_overlay_path):
605f9996aaSopenharmony_ci                                yield {
615f9996aaSopenharmony_ci                                    'company': company,
625f9996aaSopenharmony_ci                                    "name": product_name,
635f9996aaSopenharmony_ci                                    'product_config_path': p_config_path,
645f9996aaSopenharmony_ci                                    'product_path': product_path,
655f9996aaSopenharmony_ci                                    'version': info.get('version', '3.0'),
665f9996aaSopenharmony_ci                                    'os_level': info.get('type', "mini"),
675f9996aaSopenharmony_ci                                    'build_out_path': info.get('build_out_path'),
685f9996aaSopenharmony_ci                                    'subsystem_config_json':
695f9996aaSopenharmony_ci                                    info.get('subsystem_config_json'),
705f9996aaSopenharmony_ci                                    'subsystem_config_overlay_json':
715f9996aaSopenharmony_ci                                    subsystem_config_overlay_path,
725f9996aaSopenharmony_ci                                    'config': config_path,
735f9996aaSopenharmony_ci                                    'component_type': info.get('component_type', '')
745f9996aaSopenharmony_ci                                }
755f9996aaSopenharmony_ci                            else:
765f9996aaSopenharmony_ci                                yield {
775f9996aaSopenharmony_ci                                    'company': company,
785f9996aaSopenharmony_ci                                    "name": product_name,
795f9996aaSopenharmony_ci                                    'product_config_path': p_config_path,
805f9996aaSopenharmony_ci                                    'product_path': product_path,
815f9996aaSopenharmony_ci                                    'version': info.get('version', '3.0'),
825f9996aaSopenharmony_ci                                    'os_level': info.get('type', "mini"),
835f9996aaSopenharmony_ci                                    'build_out_path': info.get('build_out_path'),
845f9996aaSopenharmony_ci                                    'subsystem_config_json':
855f9996aaSopenharmony_ci                                    info.get('subsystem_config_json'),
865f9996aaSopenharmony_ci                                    'config': config_path,
875f9996aaSopenharmony_ci                                    'component_type': info.get('component_type', '')
885f9996aaSopenharmony_ci                                }
895f9996aaSopenharmony_ci        if config.vendor_path != '':
905f9996aaSopenharmony_ci            for company in os.listdir(config.vendor_path):
915f9996aaSopenharmony_ci                company_path = os.path.join(config.vendor_path, company)
925f9996aaSopenharmony_ci                if not os.path.isdir(company_path):
935f9996aaSopenharmony_ci                    continue
945f9996aaSopenharmony_ci
955f9996aaSopenharmony_ci                for product in os.listdir(company_path):
965f9996aaSopenharmony_ci                    product_path = os.path.join(company_path, product)
975f9996aaSopenharmony_ci                    config_path = os.path.join(product_path, 'config.json')
985f9996aaSopenharmony_ci
995f9996aaSopenharmony_ci                    if os.path.isfile(config_path):
1005f9996aaSopenharmony_ci                        info = IoUtil.read_json_file(config_path)
1015f9996aaSopenharmony_ci                        product_name = info.get('product_name')
1025f9996aaSopenharmony_ci                        if product_name is not None:
1035f9996aaSopenharmony_ci                            yield {
1045f9996aaSopenharmony_ci                                'company': company,
1055f9996aaSopenharmony_ci                                "name": product_name,
1065f9996aaSopenharmony_ci                                'product_config_path': product_path,
1075f9996aaSopenharmony_ci                                'product_path': product_path,
1085f9996aaSopenharmony_ci                                'version': info.get('version', '3.0'),
1095f9996aaSopenharmony_ci                                'os_level': info.get('type', "mini"),
1105f9996aaSopenharmony_ci                                'config': config_path,
1115f9996aaSopenharmony_ci                                'component_type': info.get('component_type', '')
1125f9996aaSopenharmony_ci                            }
1135f9996aaSopenharmony_ci        bip_path = config.built_in_product_path
1145f9996aaSopenharmony_ci        for item in os.listdir(bip_path):
1155f9996aaSopenharmony_ci            if item[0] in ".":
1165f9996aaSopenharmony_ci                continue
1175f9996aaSopenharmony_ci            else:
1185f9996aaSopenharmony_ci                product_name = item[0:-len('.json')
1195f9996aaSopenharmony_ci                                    ] if item.endswith('.json') else item
1205f9996aaSopenharmony_ci                config_path = os.path.join(bip_path, item)
1215f9996aaSopenharmony_ci                info = IoUtil.read_json_file(config_path)
1225f9996aaSopenharmony_ci                yield {
1235f9996aaSopenharmony_ci                    'company': 'built-in',
1245f9996aaSopenharmony_ci                    "name": product_name,
1255f9996aaSopenharmony_ci                    'product_config_path': bip_path,
1265f9996aaSopenharmony_ci                    'product_path': bip_path,
1275f9996aaSopenharmony_ci                    'version': info.get('version', '2.0'),
1285f9996aaSopenharmony_ci                    'os_level': info.get('type', 'standard'),
1295f9996aaSopenharmony_ci                    'config': config_path,
1305f9996aaSopenharmony_ci                    'component_type': info.get('component_type', '')
1315f9996aaSopenharmony_ci                }
1325f9996aaSopenharmony_ci
1335f9996aaSopenharmony_ci        bipl_path = config.built_in_product_path_for_llvm
1345f9996aaSopenharmony_ci        if os.path.isdir(bipl_path):
1355f9996aaSopenharmony_ci            for item in os.listdir(bipl_path):
1365f9996aaSopenharmony_ci                if item[0] in ".":
1375f9996aaSopenharmony_ci                    continue
1385f9996aaSopenharmony_ci                else:
1395f9996aaSopenharmony_ci                    product_name = item[0:-len('.json')
1405f9996aaSopenharmony_ci                                        ] if item.endswith('.json') else item
1415f9996aaSopenharmony_ci                    config_path = os.path.join(bipl_path, item)
1425f9996aaSopenharmony_ci                    info = IoUtil.read_json_file(config_path)
1435f9996aaSopenharmony_ci                    yield {
1445f9996aaSopenharmony_ci                        'company': 'built-in',
1455f9996aaSopenharmony_ci                        "name": product_name,
1465f9996aaSopenharmony_ci                        'product_config_path': bipl_path,
1475f9996aaSopenharmony_ci                        'product_path': bipl_path,
1485f9996aaSopenharmony_ci                        'version': info.get('version', '2.0'),
1495f9996aaSopenharmony_ci                        'os_level': info.get('type', 'standard'),
1505f9996aaSopenharmony_ci                        'config': config_path,
1515f9996aaSopenharmony_ci                        'component_type': info.get('component_type', '')
1525f9996aaSopenharmony_ci                    }
1535f9996aaSopenharmony_ci
1545f9996aaSopenharmony_ci    @staticmethod
1555f9996aaSopenharmony_ci    @throw_exception
1565f9996aaSopenharmony_ci    def get_device_info(product_json: str):
1575f9996aaSopenharmony_ci        info = IoUtil.read_json_file(product_json)
1585f9996aaSopenharmony_ci        config = Config()
1595f9996aaSopenharmony_ci        version = info.get('version', '3.0')
1605f9996aaSopenharmony_ci
1615f9996aaSopenharmony_ci        if version == '3.0':
1625f9996aaSopenharmony_ci            device_company = info.get('device_company')
1635f9996aaSopenharmony_ci            board = info.get('board')
1645f9996aaSopenharmony_ci            _board_path = info.get('board_path')
1655f9996aaSopenharmony_ci            if _board_path and os.path.exists(
1665f9996aaSopenharmony_ci                    os.path.join(config.root_path, _board_path)):
1675f9996aaSopenharmony_ci                board_path = os.path.join(config.root_path, _board_path)
1685f9996aaSopenharmony_ci            else:
1695f9996aaSopenharmony_ci                board_path = os.path.join(config.root_path, 'device',
1705f9996aaSopenharmony_ci                                          device_company, board)
1715f9996aaSopenharmony_ci                # board and soc decoupling feature will add boards
1725f9996aaSopenharmony_ci                # directory path here.
1735f9996aaSopenharmony_ci                if not os.path.exists(board_path):
1745f9996aaSopenharmony_ci                    board_path = os.path.join(config.root_path, 'device',
1755f9996aaSopenharmony_ci                                              'board', device_company, board)
1765f9996aaSopenharmony_ci            board_config_path = None
1775f9996aaSopenharmony_ci            if info.get('board_config_path'):
1785f9996aaSopenharmony_ci                board_config_path = os.path.join(config.root_path,
1795f9996aaSopenharmony_ci                                                 info.get('board_config_path'))
1805f9996aaSopenharmony_ci
1815f9996aaSopenharmony_ci            return {
1825f9996aaSopenharmony_ci                'board': info.get('board'),
1835f9996aaSopenharmony_ci                'kernel': info.get('kernel_type'),
1845f9996aaSopenharmony_ci                'kernel_version': info.get('kernel_version'),
1855f9996aaSopenharmony_ci                'company': info.get('device_company'),
1865f9996aaSopenharmony_ci                'board_path': board_path,
1875f9996aaSopenharmony_ci                'board_config_path': board_config_path,
1885f9996aaSopenharmony_ci                'target_cpu': info.get('target_cpu'),
1895f9996aaSopenharmony_ci                'target_os': info.get('target_os'),
1905f9996aaSopenharmony_ci                'support_cpu': info.get('support_cpu'),
1915f9996aaSopenharmony_ci            }
1925f9996aaSopenharmony_ci        else:
1935f9996aaSopenharmony_ci            raise OHOSException(f'wrong version number in {product_json}')
1945f9996aaSopenharmony_ci
1955f9996aaSopenharmony_ci    @staticmethod
1965f9996aaSopenharmony_ci    @throw_exception
1975f9996aaSopenharmony_ci    def get_all_components(product_json: str):
1985f9996aaSopenharmony_ci        if not os.path.isfile(product_json):
1995f9996aaSopenharmony_ci            raise OHOSException(f'features {product_json} not found')
2005f9996aaSopenharmony_ci
2015f9996aaSopenharmony_ci        config = Config()
2025f9996aaSopenharmony_ci        # Get all inherit files
2035f9996aaSopenharmony_ci        files = [os.path.join(config.root_path, file) for file in IoUtil.read_json_file(
2045f9996aaSopenharmony_ci            product_json).get('inherit', [])]
2055f9996aaSopenharmony_ci        # Add the product config file to last with highest priority
2065f9996aaSopenharmony_ci        files.append(product_json)
2075f9996aaSopenharmony_ci
2085f9996aaSopenharmony_ci        # Read all parts in order
2095f9996aaSopenharmony_ci        all_parts = {}
2105f9996aaSopenharmony_ci        for _file in files:
2115f9996aaSopenharmony_ci            if not os.path.isfile(_file):
2125f9996aaSopenharmony_ci                continue
2135f9996aaSopenharmony_ci            _info = IoUtil.read_json_file(_file)
2145f9996aaSopenharmony_ci            parts = _info.get('parts')
2155f9996aaSopenharmony_ci            if parts:
2165f9996aaSopenharmony_ci                all_parts.update(parts)
2175f9996aaSopenharmony_ci            else:
2185f9996aaSopenharmony_ci                # v3 config files
2195f9996aaSopenharmony_ci                all_parts.update(ProductUtil.get_vendor_parts_list(_info))
2205f9996aaSopenharmony_ci
2215f9996aaSopenharmony_ci        return all_parts
2225f9996aaSopenharmony_ci
2235f9996aaSopenharmony_ci    @staticmethod
2245f9996aaSopenharmony_ci    @throw_exception
2255f9996aaSopenharmony_ci    def get_features(product_json: str):
2265f9996aaSopenharmony_ci        if not os.path.isfile(product_json):
2275f9996aaSopenharmony_ci            raise OHOSException(f'features {product_json} not found')
2285f9996aaSopenharmony_ci
2295f9996aaSopenharmony_ci        config = Config()
2305f9996aaSopenharmony_ci        # Get all inherit files
2315f9996aaSopenharmony_ci        files = [os.path.join(config.root_path, file) for file in IoUtil.read_json_file(
2325f9996aaSopenharmony_ci            product_json).get('inherit', [])]
2335f9996aaSopenharmony_ci        # Add the product config file to last with highest priority
2345f9996aaSopenharmony_ci        files.append(product_json)
2355f9996aaSopenharmony_ci
2365f9996aaSopenharmony_ci        # Read all parts in order
2375f9996aaSopenharmony_ci        all_parts = {}
2385f9996aaSopenharmony_ci        for _file in files:
2395f9996aaSopenharmony_ci            if not os.path.isfile(_file):
2405f9996aaSopenharmony_ci                continue
2415f9996aaSopenharmony_ci            _info = IoUtil.read_json_file(_file)
2425f9996aaSopenharmony_ci            parts = _info.get('parts')
2435f9996aaSopenharmony_ci            if parts:
2445f9996aaSopenharmony_ci                all_parts.update(parts)
2455f9996aaSopenharmony_ci            else:
2465f9996aaSopenharmony_ci                # v3 config files
2475f9996aaSopenharmony_ci                all_parts.update(ProductUtil.get_vendor_parts_list(_info))
2485f9996aaSopenharmony_ci
2495f9996aaSopenharmony_ci        # Get all features
2505f9996aaSopenharmony_ci        features_list = []
2515f9996aaSopenharmony_ci        for part, value in all_parts.items():
2525f9996aaSopenharmony_ci            if "features" not in value:
2535f9996aaSopenharmony_ci                continue
2545f9996aaSopenharmony_ci            for key, val in value["features"].items():
2555f9996aaSopenharmony_ci                _item = ''
2565f9996aaSopenharmony_ci                if isinstance(val, bool):
2575f9996aaSopenharmony_ci                    _item = f'{key}={str(val).lower()}'
2585f9996aaSopenharmony_ci                elif isinstance(val, int):
2595f9996aaSopenharmony_ci                    _item = f'{key}={val}'
2605f9996aaSopenharmony_ci                elif isinstance(val, str):
2615f9996aaSopenharmony_ci                    _item = f'{key}="{val}"'
2625f9996aaSopenharmony_ci                else:
2635f9996aaSopenharmony_ci                    raise Exception(
2645f9996aaSopenharmony_ci                        "part feature '{key}:{val}' type not support.")
2655f9996aaSopenharmony_ci                features_list.append(_item)
2665f9996aaSopenharmony_ci        return features_list
2675f9996aaSopenharmony_ci
2685f9996aaSopenharmony_ci    @staticmethod
2695f9996aaSopenharmony_ci    @throw_exception
2705f9996aaSopenharmony_ci    def get_features_dict(product_json: str):
2715f9996aaSopenharmony_ci        all_parts = ProductUtil.get_all_components(product_json)
2725f9996aaSopenharmony_ci        features_dict = {}
2735f9996aaSopenharmony_ci        for part, value in all_parts.items():
2745f9996aaSopenharmony_ci            if "features" not in value:
2755f9996aaSopenharmony_ci                continue
2765f9996aaSopenharmony_ci            for key, val in value["features"].items():
2775f9996aaSopenharmony_ci                if type(val) in [bool, int, str]:
2785f9996aaSopenharmony_ci                    features_dict[key] = val
2795f9996aaSopenharmony_ci                else:
2805f9996aaSopenharmony_ci                    raise Exception(
2815f9996aaSopenharmony_ci                        "part feature '{key}:{val}' type not support.")
2825f9996aaSopenharmony_ci        return features_dict
2835f9996aaSopenharmony_ci
2845f9996aaSopenharmony_ci    @staticmethod
2855f9996aaSopenharmony_ci    @throw_exception
2865f9996aaSopenharmony_ci    def get_components(product_json: str, subsystems: str):
2875f9996aaSopenharmony_ci        if not os.path.isfile(product_json):
2885f9996aaSopenharmony_ci            raise OHOSException(f'{product_json} not found')
2895f9996aaSopenharmony_ci
2905f9996aaSopenharmony_ci        components_dict = defaultdict(list)
2915f9996aaSopenharmony_ci        product_data = IoUtil.read_json_file(product_json)
2925f9996aaSopenharmony_ci        for subsystem in product_data.get('subsystems', []):
2935f9996aaSopenharmony_ci            sname = subsystem.get('subsystem', '')
2945f9996aaSopenharmony_ci            if not len(subsystems) or sname in subsystems:
2955f9996aaSopenharmony_ci                components_dict[sname] += [
2965f9996aaSopenharmony_ci                    comp['component']
2975f9996aaSopenharmony_ci                    for comp in subsystem.get('components', [])
2985f9996aaSopenharmony_ci                ]
2995f9996aaSopenharmony_ci
3005f9996aaSopenharmony_ci        return components_dict, product_data.get('board', ''),\
3015f9996aaSopenharmony_ci            product_data.get('kernel_type', '')
3025f9996aaSopenharmony_ci
3035f9996aaSopenharmony_ci    @staticmethod
3045f9996aaSopenharmony_ci    @throw_exception
3055f9996aaSopenharmony_ci    def get_product_info(product_name: str, company=None):
3065f9996aaSopenharmony_ci        for product_info in ProductUtil.get_products():
3075f9996aaSopenharmony_ci            cur_company = product_info['company']
3085f9996aaSopenharmony_ci            cur_product = product_info['name']
3095f9996aaSopenharmony_ci            if company:
3105f9996aaSopenharmony_ci                if cur_company == company and cur_product == product_name:
3115f9996aaSopenharmony_ci                    return product_info
3125f9996aaSopenharmony_ci            else:
3135f9996aaSopenharmony_ci                if cur_product == product_name:
3145f9996aaSopenharmony_ci                    return product_info
3155f9996aaSopenharmony_ci
3165f9996aaSopenharmony_ci        raise OHOSException(f'product {product_name}@{company} not found')
3175f9996aaSopenharmony_ci
3185f9996aaSopenharmony_ci    @staticmethod
3195f9996aaSopenharmony_ci    @throw_exception
3205f9996aaSopenharmony_ci    def get_compiler(config_path: str):
3215f9996aaSopenharmony_ci        config = os.path.join(config_path, 'config.gni')
3225f9996aaSopenharmony_ci        if not os.path.isfile(config):
3235f9996aaSopenharmony_ci            return ''
3245f9996aaSopenharmony_ci        compiler_pattern = r'board_toolchain_type ?= ?"(\w+)"'
3255f9996aaSopenharmony_ci        with open(config, 'rt', encoding='utf-8') as config_file:
3265f9996aaSopenharmony_ci            data = config_file.read()
3275f9996aaSopenharmony_ci        compiler_list = re.findall(compiler_pattern, data)
3285f9996aaSopenharmony_ci        if not len(compiler_list):
3295f9996aaSopenharmony_ci            raise OHOSException(f'board_toolchain_type is None in {config}')
3305f9996aaSopenharmony_ci
3315f9996aaSopenharmony_ci        return compiler_list[0]
3325f9996aaSopenharmony_ci
3335f9996aaSopenharmony_ci    @staticmethod
3345f9996aaSopenharmony_ci    def get_vendor_parts_list(config: dict):
3355f9996aaSopenharmony_ci        return _transform(config).get('parts')
3365f9996aaSopenharmony_ci
3375f9996aaSopenharmony_ci    @staticmethod
3385f9996aaSopenharmony_ci    def has_component(product_name: str) -> bool:
3395f9996aaSopenharmony_ci        pass
3405f9996aaSopenharmony_ci
3415f9996aaSopenharmony_ci
3425f9996aaSopenharmony_cidef _transform(config: dict):
3435f9996aaSopenharmony_ci    subsystems = config.get('subsystems')
3445f9996aaSopenharmony_ci    if subsystems:
3455f9996aaSopenharmony_ci        config.pop('subsystems')
3465f9996aaSopenharmony_ci        parts = _from_ss_to_parts(subsystems)
3475f9996aaSopenharmony_ci        config['parts'] = parts
3485f9996aaSopenharmony_ci    return config
3495f9996aaSopenharmony_ci
3505f9996aaSopenharmony_ci
3515f9996aaSopenharmony_cidef _from_ss_to_parts(subsystems: dict):
3525f9996aaSopenharmony_ci    parts = dict()
3535f9996aaSopenharmony_ci    for subsystem in subsystems:
3545f9996aaSopenharmony_ci        ss_name = subsystem.get('subsystem')
3555f9996aaSopenharmony_ci        components = subsystem.get('components')
3565f9996aaSopenharmony_ci        if components:
3575f9996aaSopenharmony_ci            for com in components:
3585f9996aaSopenharmony_ci                com_name = com.get('component')
3595f9996aaSopenharmony_ci                features = com.get('features')
3605f9996aaSopenharmony_ci                syscap = com.get('syscap')
3615f9996aaSopenharmony_ci                exclusions = com.get('exclusions')
3625f9996aaSopenharmony_ci                if features:
3635f9996aaSopenharmony_ci                    pairs = get_features(features)
3645f9996aaSopenharmony_ci                    parts['{}:{}'.format(ss_name, com_name)] = pairs
3655f9996aaSopenharmony_ci                else:
3665f9996aaSopenharmony_ci                    parts['{}:{}'.format(ss_name, com_name)] = dict()
3675f9996aaSopenharmony_ci                if syscap:
3685f9996aaSopenharmony_ci                    pairs = get_syscap(syscap)
3695f9996aaSopenharmony_ci                    parts.get('{}:{}'.format(ss_name, com_name)).update(pairs)
3705f9996aaSopenharmony_ci                if exclusions:
3715f9996aaSopenharmony_ci                    pairs = get_exclusion_modules(exclusions)
3725f9996aaSopenharmony_ci                    parts.get('{}:{}'.format(ss_name, com_name)).update(pairs)
3735f9996aaSopenharmony_ci                # Copy other key-values
3745f9996aaSopenharmony_ci                for key, val in com.items():
3755f9996aaSopenharmony_ci                    if key in ['component', 'features', 'syscap', 'exclusions']:
3765f9996aaSopenharmony_ci                        continue
3775f9996aaSopenharmony_ci                    parts.get('{}:{}'.format(ss_name, com_name)).update(key=val)
3785f9996aaSopenharmony_ci    return parts
3795f9996aaSopenharmony_ci
3805f9996aaSopenharmony_ci
3815f9996aaSopenharmony_cidef get_features(features: dict):
3825f9996aaSopenharmony_ci    feats = {}
3835f9996aaSopenharmony_ci    for feat in features:
3845f9996aaSopenharmony_ci        if not feat:
3855f9996aaSopenharmony_ci            continue
3865f9996aaSopenharmony_ci        match = feat.index("=")
3875f9996aaSopenharmony_ci        if match <= 0:
3885f9996aaSopenharmony_ci            print("Warning: invalid feature [{}]".format(feat))
3895f9996aaSopenharmony_ci            continue
3905f9996aaSopenharmony_ci        key = feat[:match].strip()
3915f9996aaSopenharmony_ci        val = feat[match + 1:].strip().strip('"')
3925f9996aaSopenharmony_ci        if val == 'true':
3935f9996aaSopenharmony_ci            feats[key] = True
3945f9996aaSopenharmony_ci        elif val == 'false':
3955f9996aaSopenharmony_ci            feats[key] = False
3965f9996aaSopenharmony_ci        elif re.match(r'[0-9]+', val):
3975f9996aaSopenharmony_ci            feats[key] = int(val)
3985f9996aaSopenharmony_ci        else:
3995f9996aaSopenharmony_ci            feats[key] = val.replace('\"', '"')
4005f9996aaSopenharmony_ci
4015f9996aaSopenharmony_ci    pairs = dict()
4025f9996aaSopenharmony_ci    pairs['features'] = feats
4035f9996aaSopenharmony_ci    return pairs
4045f9996aaSopenharmony_ci
4055f9996aaSopenharmony_ci
4065f9996aaSopenharmony_cidef get_syscap(syscap: dict):
4075f9996aaSopenharmony_ci    feats = {}
4085f9996aaSopenharmony_ci    for feat in syscap:
4095f9996aaSopenharmony_ci        if not feat:
4105f9996aaSopenharmony_ci            continue
4115f9996aaSopenharmony_ci        if '=' not in feat:
4125f9996aaSopenharmony_ci            raise Exception("Error: invalid syscap [{}]".format(feat))
4135f9996aaSopenharmony_ci        match = feat.index("=")
4145f9996aaSopenharmony_ci        key = feat[:match].strip()
4155f9996aaSopenharmony_ci        val = feat[match + 1:].strip().strip('"')
4165f9996aaSopenharmony_ci        if val == 'true':
4175f9996aaSopenharmony_ci            feats[key] = True
4185f9996aaSopenharmony_ci        elif val == 'false':
4195f9996aaSopenharmony_ci            feats[key] = False
4205f9996aaSopenharmony_ci        elif re.match(r'[0-9]+', val):
4215f9996aaSopenharmony_ci            feats[key] = int(val)
4225f9996aaSopenharmony_ci        else:
4235f9996aaSopenharmony_ci            feats[key] = val.replace('\"', '"')
4245f9996aaSopenharmony_ci
4255f9996aaSopenharmony_ci    pairs = dict()
4265f9996aaSopenharmony_ci    pairs['syscap'] = feats
4275f9996aaSopenharmony_ci    return pairs
4285f9996aaSopenharmony_ci
4295f9996aaSopenharmony_ci
4305f9996aaSopenharmony_cidef get_exclusion_modules(exclusions: str):
4315f9996aaSopenharmony_ci    pairs = dict()
4325f9996aaSopenharmony_ci    pairs['exclusions'] = exclusions
4335f9996aaSopenharmony_ci    return pairs
434