15f9996aaSopenharmony_ci#!/usr/bin/env python3
25f9996aaSopenharmony_ci# -*- coding: utf-8 -*-
35f9996aaSopenharmony_ci"""
45f9996aaSopenharmony_ciCopyright (c) 2021 Huawei Device Co., Ltd.
55f9996aaSopenharmony_ciLicensed under the Apache License, Version 2.0 (the "License");
65f9996aaSopenharmony_ciyou may not use this file except in compliance with the License.
75f9996aaSopenharmony_ciYou may obtain a copy of the License at
85f9996aaSopenharmony_ci
95f9996aaSopenharmony_ci    http://www.apache.org/licenses/LICENSE-2.0
105f9996aaSopenharmony_ci
115f9996aaSopenharmony_ciUnless required by applicable law or agreed to in writing, software
125f9996aaSopenharmony_cidistributed under the License is distributed on an "AS IS" BASIS,
135f9996aaSopenharmony_ciWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145f9996aaSopenharmony_ciSee the License for the specific language governing permissions and
155f9996aaSopenharmony_cilimitations under the License.
165f9996aaSopenharmony_ci
175f9996aaSopenharmony_ci"""
185f9996aaSopenharmony_ciimport json
195f9996aaSopenharmony_ciimport argparse
205f9996aaSopenharmony_ciimport os
215f9996aaSopenharmony_ci
225f9996aaSopenharmony_ciSUBSYS_LIST = "subsystems"
235f9996aaSopenharmony_ciSUBSYS = "subsystem"
245f9996aaSopenharmony_ciCOMPONENT_LIST = "components"
255f9996aaSopenharmony_ciCOMPONENT = "component"
265f9996aaSopenharmony_ciFEATRUES = "features"
275f9996aaSopenharmony_ciFEATRUE = "feature"
285f9996aaSopenharmony_ciNONE_FEATURES = []
295f9996aaSopenharmony_ciTYPE = "type"
305f9996aaSopenharmony_ciVALUE = "value"
315f9996aaSopenharmony_ciPROPERTY = "property"
325f9996aaSopenharmony_ciKCONF_PREFIX = "CONFIG_"
335f9996aaSopenharmony_ci
345f9996aaSopenharmony_ci
355f9996aaSopenharmony_cidef read_full_component(path: str):
365f9996aaSopenharmony_ci    data = {}
375f9996aaSopenharmony_ci    with open(path, "rb") as f:
385f9996aaSopenharmony_ci        data = json.load(f)
395f9996aaSopenharmony_ci    component_subsys_dict = {}
405f9996aaSopenharmony_ci    for item in data.get(SUBSYS_LIST):
415f9996aaSopenharmony_ci        subsys_name = item.get(SUBSYS)
425f9996aaSopenharmony_ci        for component in item.get(COMPONENT_LIST):
435f9996aaSopenharmony_ci            component_name = component.get(COMPONENT)
445f9996aaSopenharmony_ci            component_subsys_dict[component_name] = subsys_name
455f9996aaSopenharmony_ci    return component_subsys_dict
465f9996aaSopenharmony_ci
475f9996aaSopenharmony_ci
485f9996aaSopenharmony_cidef read_deps_info(path: str):
495f9996aaSopenharmony_ci    data = {}
505f9996aaSopenharmony_ci    with open(path, "rb") as f:
515f9996aaSopenharmony_ci        data = json.load(f)
525f9996aaSopenharmony_ci    return data
535f9996aaSopenharmony_ci
545f9996aaSopenharmony_ci
555f9996aaSopenharmony_cidef merge(component_subsys_dict: dict, component_deps_dict: dict, subsys_conf: dict):
565f9996aaSopenharmony_ci    config_component_list = []
575f9996aaSopenharmony_ci    for _, components in subsys_conf.items():
585f9996aaSopenharmony_ci        for component, _ in components.items():
595f9996aaSopenharmony_ci            config_component_list.append(component)
605f9996aaSopenharmony_ci
615f9996aaSopenharmony_ci    for component_name in config_component_list:
625f9996aaSopenharmony_ci        deps = component_deps_dict.get(component_name)
635f9996aaSopenharmony_ci        if deps is not None:
645f9996aaSopenharmony_ci            for dep in deps:
655f9996aaSopenharmony_ci                if dep in config_component_list:
665f9996aaSopenharmony_ci                    continue
675f9996aaSopenharmony_ci                else:
685f9996aaSopenharmony_ci                    subsys_name = component_subsys_dict.get(dep)
695f9996aaSopenharmony_ci                    if subsys_name is None:
705f9996aaSopenharmony_ci                        continue
715f9996aaSopenharmony_ci                    if subsys_conf.get(subsys_name) is None:
725f9996aaSopenharmony_ci                        subsys_conf[subsys_name] = {dep: NONE_FEATURES}
735f9996aaSopenharmony_ci                    else:
745f9996aaSopenharmony_ci                        subsys_conf[subsys_name][dep] = NONE_FEATURES
755f9996aaSopenharmony_ci                    config_component_list.append(dep)
765f9996aaSopenharmony_ci
775f9996aaSopenharmony_ci
785f9996aaSopenharmony_cidef is_valid_line(line: str):
795f9996aaSopenharmony_ci    return line.startswith(KCONF_PREFIX)
805f9996aaSopenharmony_ci
815f9996aaSopenharmony_ci
825f9996aaSopenharmony_cidef handle_config_feature(items: dict, arr: list, line: str):
835f9996aaSopenharmony_ci    items[TYPE] = FEATRUE
845f9996aaSopenharmony_ci    items[SUBSYS] = arr[1]
855f9996aaSopenharmony_ci    items[COMPONENT] = arr[2].split("=")[0]
865f9996aaSopenharmony_ci    features = line.split("=", 1)[1].strip("\"")
875f9996aaSopenharmony_ci    if features == "":
885f9996aaSopenharmony_ci        items[FEATRUES] = NONE_FEATURES
895f9996aaSopenharmony_ci    else:
905f9996aaSopenharmony_ci        items[FEATRUES] = features.split(",")
915f9996aaSopenharmony_ci
925f9996aaSopenharmony_ci
935f9996aaSopenharmony_cidef handle_config_component(items: dict, arr: list, line: str):
945f9996aaSopenharmony_ci    items[TYPE] = COMPONENT
955f9996aaSopenharmony_ci    items[SUBSYS] = arr[0].split("_", 1)[1]
965f9996aaSopenharmony_ci    items[COMPONENT] = arr[1].split("=")[0]
975f9996aaSopenharmony_ci    items[VALUE] = line.split("=", 1)[1]
985f9996aaSopenharmony_ci
995f9996aaSopenharmony_ci
1005f9996aaSopenharmony_cidef handle_config_property(items: dict, arr: list, line: str):
1015f9996aaSopenharmony_ci    items[PROPERTY] = arr[1].split("=")[0]
1025f9996aaSopenharmony_ci    items[TYPE] = PROPERTY
1035f9996aaSopenharmony_ci    items[VALUE] = line.split("=", 1)[1].strip("\"")
1045f9996aaSopenharmony_ci
1055f9996aaSopenharmony_ci
1065f9996aaSopenharmony_cidef read_line_item(line: str):
1075f9996aaSopenharmony_ci    line = line.strip()
1085f9996aaSopenharmony_ci    items = {
1095f9996aaSopenharmony_ci        TYPE: None,
1105f9996aaSopenharmony_ci        SUBSYS: None,
1115f9996aaSopenharmony_ci        FEATRUES: None,
1125f9996aaSopenharmony_ci        COMPONENT: None,
1135f9996aaSopenharmony_ci        PROPERTY: None,
1145f9996aaSopenharmony_ci        VALUE: None
1155f9996aaSopenharmony_ci    }
1165f9996aaSopenharmony_ci    arr = line.split("$$")
1175f9996aaSopenharmony_ci    if arr[0] == "CONFIG_feature":
1185f9996aaSopenharmony_ci        handle_config_feature(items, arr, line)
1195f9996aaSopenharmony_ci    elif arr[0] == "CONFIG_property":
1205f9996aaSopenharmony_ci        handle_config_property(items, arr, line)
1215f9996aaSopenharmony_ci    else:
1225f9996aaSopenharmony_ci        handle_config_component(items, arr, line)
1235f9996aaSopenharmony_ci    return items
1245f9996aaSopenharmony_ci
1255f9996aaSopenharmony_ci
1265f9996aaSopenharmony_cidef read(kconf: str):
1275f9996aaSopenharmony_ci    result, subsys_conf = {}, {}
1285f9996aaSopenharmony_ci    with open(kconf, "r") as f:
1295f9996aaSopenharmony_ci        for line in f.readlines():
1305f9996aaSopenharmony_ci            if not is_valid_line(line):
1315f9996aaSopenharmony_ci                continue
1325f9996aaSopenharmony_ci            items = read_line_item(line)
1335f9996aaSopenharmony_ci            subsys = items.get(SUBSYS)
1345f9996aaSopenharmony_ci            component = items.get(COMPONENT)
1355f9996aaSopenharmony_ci            conf_type = items.get(TYPE)
1365f9996aaSopenharmony_ci            features = items.get(FEATRUES)
1375f9996aaSopenharmony_ci            if conf_type == PROPERTY:
1385f9996aaSopenharmony_ci                if len(items.get(VALUE)) > 0:
1395f9996aaSopenharmony_ci                    result[items.get(PROPERTY)] = items.get(VALUE)
1405f9996aaSopenharmony_ci            elif conf_type == FEATRUE or conf_type == COMPONENT:
1415f9996aaSopenharmony_ci                if subsys_conf.get(subsys) is None:
1425f9996aaSopenharmony_ci                    subsys_conf[subsys] = {}
1435f9996aaSopenharmony_ci                subsys_conf.get(subsys)[component] = features
1445f9996aaSopenharmony_ci
1455f9996aaSopenharmony_ci    result[SUBSYS_LIST] = subsys_conf
1465f9996aaSopenharmony_ci    return result
1475f9996aaSopenharmony_ci
1485f9996aaSopenharmony_ci
1495f9996aaSopenharmony_cidef generate_config_with_full_deps(deps_path: str, base_product_path: str, config_path: str, out: str):
1505f9996aaSopenharmony_ci    kconf = read(config_path)
1515f9996aaSopenharmony_ci    subsys_conf = kconf.get(SUBSYS_LIST)
1525f9996aaSopenharmony_ci    component_subsys_dict = read_full_component(base_product_path)
1535f9996aaSopenharmony_ci    component_deps_dict = read_deps_info(deps_path)
1545f9996aaSopenharmony_ci    merge(component_subsys_dict, component_deps_dict, subsys_conf)
1555f9996aaSopenharmony_ci    subsystems_list = []
1565f9996aaSopenharmony_ci    for subsys, components in subsys_conf.items():
1575f9996aaSopenharmony_ci        temp = {SUBSYS: subsys, COMPONENT_LIST: []}
1585f9996aaSopenharmony_ci        for component, features in components.items():
1595f9996aaSopenharmony_ci            component_element = {COMPONENT: component, FEATRUES: features}
1605f9996aaSopenharmony_ci            temp.get(COMPONENT_LIST).append(component_element)
1615f9996aaSopenharmony_ci        subsystems_list.append(temp)
1625f9996aaSopenharmony_ci    result = kconf
1635f9996aaSopenharmony_ci    result[SUBSYS_LIST] = subsystems_list
1645f9996aaSopenharmony_ci    with open(out, "w") as f:
1655f9996aaSopenharmony_ci        f.write(json.dumps(result, indent=2))
1665f9996aaSopenharmony_ci    print("output file in: ", os.path.abspath(out))
1675f9996aaSopenharmony_ci
1685f9996aaSopenharmony_ci
1695f9996aaSopenharmony_cidef main():
1705f9996aaSopenharmony_ci    intro = 'Genenrate newly kconfig input file.\n\
1715f9996aaSopenharmony_ci        For example: python3 parse_kconf.py --deps={$repo}/out/{your_product}/part_deps_info/part_deps_info.json \n\
1725f9996aaSopenharmony_ci        or           python3 parse_kconf.py --base_product={$repo}/productdefine/common/base/base_product.json \
1735f9996aaSopenharmony_ci--out=./product.json --deps={$repo}/out/{your_product}/part_deps_info/part_deps_info.json --config=./.config'
1745f9996aaSopenharmony_ci    parser = argparse.ArgumentParser(
1755f9996aaSopenharmony_ci        formatter_class=argparse.RawDescriptionHelpFormatter,
1765f9996aaSopenharmony_ci        description=intro)
1775f9996aaSopenharmony_ci    parser.add_argument('--deps', type=str, required=True, default="",
1785f9996aaSopenharmony_ci                        help='Must Required! Depencencies info after gn building')
1795f9996aaSopenharmony_ci    parser.add_argument('--base_product', type=str, default="./../../../productdefine/common/base/base_product.json",
1805f9996aaSopenharmony_ci                        help='base_product.json file')
1815f9996aaSopenharmony_ci    parser.add_argument('--config', type=str, default="./.config",
1825f9996aaSopenharmony_ci                        help='config file which is generated by kconfig operation, default is .config')
1835f9996aaSopenharmony_ci    parser.add_argument('--out', type=str, default="./product.json",
1845f9996aaSopenharmony_ci                        help="define output file path and name, like './product.json'")
1855f9996aaSopenharmony_ci    args = parser.parse_args()
1865f9996aaSopenharmony_ci    print("read deps file: ", os.path.abspath(args.deps))
1875f9996aaSopenharmony_ci    print("read kconfig file: ", os.path.abspath(args.config))
1885f9996aaSopenharmony_ci    print("read base_product file: ", os.path.abspath(args.base_product))
1895f9996aaSopenharmony_ci
1905f9996aaSopenharmony_ci    generate_config_with_full_deps(args.deps, args.base_product, args.config, args.out)
1915f9996aaSopenharmony_ci
1925f9996aaSopenharmony_ci
1935f9996aaSopenharmony_ciif __name__ == "__main__":
1945f9996aaSopenharmony_ci    main()
195