1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3""" 4Copyright (c) 2021 Huawei Device Co., Ltd. 5Licensed under the Apache License, Version 2.0 (the "License"); 6you may not use this file except in compliance with the License. 7You may obtain a copy of the License at 8 9 http://www.apache.org/licenses/LICENSE-2.0 10 11Unless required by applicable law or agreed to in writing, software 12distributed under the License is distributed on an "AS IS" BASIS, 13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14See the License for the specific language governing permissions and 15limitations under the License. 16 17""" 18import json 19import argparse 20import os 21import stat 22 23SUBSYS_LIST = "subsystems" 24SUBSYS = "subsystem" 25COMPONENT_LIST = "components" 26COMPONENT = "component" 27FEATRUES = "features" 28FEATRUE = "feature" 29NONE_FEATURES = [] 30TYPE = "type" 31VALUE = "value" 32PROPERTY = "property" 33KCONF_PREFIX = "CONFIG_" 34 35 36def read_full_component(path: str): 37 data = {} 38 with open(path, "rb") as f: 39 data = json.load(f) 40 component_subsys_dict = {} 41 for item in data.get(SUBSYS_LIST): 42 subsys_name = item.get(SUBSYS) 43 for component in item.get(COMPONENT_LIST): 44 component_name = component.get(COMPONENT) 45 component_subsys_dict[component_name] = subsys_name 46 return component_subsys_dict 47 48 49def read_deps_info(path: str): 50 data = {} 51 with open(path, "rb") as f: 52 data = json.load(f) 53 return data 54 55 56def merge(component_subsys_dict: dict, component_deps_dict: dict, subsys_conf: dict): 57 config_component_list = [] 58 for _, components in subsys_conf.items(): 59 for component, _ in components.items(): 60 config_component_list.append(component) 61 62 for component_name in config_component_list: 63 deps = component_deps_dict.get(component_name) 64 if deps is not None: 65 for dep in deps: 66 if dep in config_component_list: 67 continue 68 else: 69 subsys_name = component_subsys_dict.get(dep) 70 if subsys_name is None: 71 continue 72 if subsys_conf.get(subsys_name) is None: 73 subsys_conf[subsys_name] = {dep: NONE_FEATURES} 74 else: 75 subsys_conf[subsys_name][dep] = NONE_FEATURES 76 config_component_list.append(dep) 77 78 79def is_valid_line(line: str): 80 return line.startswith(KCONF_PREFIX) 81 82 83def handle_config_feature(items: dict, arr: list, line: str): 84 items[TYPE] = FEATRUE 85 items[SUBSYS] = arr[1] 86 items[COMPONENT] = arr[2].split("=")[0] 87 features = line.split("=", 1)[1].strip("\"") 88 if features == "": 89 items[FEATRUES] = NONE_FEATURES 90 else: 91 items[FEATRUES] = features.split(",") 92 93 94def handle_config_component(items: dict, arr: list, line: str): 95 items[TYPE] = COMPONENT 96 items[SUBSYS] = arr[0].split("_", 1)[1] 97 items[COMPONENT] = arr[1].split("=")[0] 98 items[VALUE] = line.split("=", 1)[1] 99 100 101def handle_config_property(items: dict, arr: list, line: str): 102 items[PROPERTY] = arr[1].split("=")[0] 103 items[TYPE] = PROPERTY 104 items[VALUE] = line.split("=", 1)[1].strip("\"") 105 106 107def read_line_item(line: str): 108 line = line.strip() 109 items = { 110 TYPE: None, 111 SUBSYS: None, 112 FEATRUES: None, 113 COMPONENT: None, 114 PROPERTY: None, 115 VALUE: None 116 } 117 arr = line.split("$$") 118 if arr[0] == "CONFIG_feature": 119 handle_config_feature(items, arr, line) 120 elif arr[0] == "CONFIG_property": 121 handle_config_property(items, arr, line) 122 else: 123 handle_config_component(items, arr, line) 124 return items 125 126 127def read(kconf: str): 128 result, subsys_conf = {}, {} 129 with open(kconf, "r") as f: 130 for line in f.readlines(): 131 if not is_valid_line(line): 132 continue 133 items = read_line_item(line) 134 subsys = items.get(SUBSYS) 135 component = items.get(COMPONENT) 136 conf_type = items.get(TYPE) 137 features = items.get(FEATRUES) 138 if conf_type == PROPERTY: 139 if len(items.get(VALUE)) > 0: 140 result[items.get(PROPERTY)] = items.get(VALUE) 141 elif conf_type == FEATRUE or conf_type == COMPONENT: 142 if subsys_conf.get(subsys) is None: 143 subsys_conf[subsys] = {} 144 subsys_conf.get(subsys)[component] = features 145 146 result[SUBSYS_LIST] = subsys_conf 147 return result 148 149 150def generate_config_with_full_deps(deps_path: str, base_product_path: str, config_path: str, out: str): 151 kconf = read(config_path) 152 subsys_conf = kconf.get(SUBSYS_LIST) 153 component_subsys_dict = read_full_component(base_product_path) 154 component_deps_dict = read_deps_info(deps_path) 155 merge(component_subsys_dict, component_deps_dict, subsys_conf) 156 subsystems_list = [] 157 for subsys, components in subsys_conf.items(): 158 temp = {SUBSYS: subsys, COMPONENT_LIST: []} 159 for component, features in components.items(): 160 component_element = {COMPONENT: component, FEATRUES: features} 161 temp.get(COMPONENT_LIST).append(component_element) 162 subsystems_list.append(temp) 163 result = kconf 164 result[SUBSYS_LIST] = subsystems_list 165 with os.fdopen(os.open(out, 166 os.O_RDWR | os.O_CREAT, stat.S_IWUSR | stat.S_IRUSR), 'w') as f: 167 f.write(json.dumps(result, indent=2)) 168 print("output file in: ", os.path.abspath(out)) 169 170 171def main(): 172 intro = 'Genenrate newly kconfig input file.\n\ 173 For example: python3 parse_kconf.py --deps={$repo}/out/{your_product}/part_deps_info/part_deps_info.json \n\ 174 or python3 parse_kconf.py --base_product={$repo}/productdefine/common/base/base_product.json \ 175--out=./product.json --deps={$repo}/out/{your_product}/part_deps_info/part_deps_info.json --config=./.config' 176 parser = argparse.ArgumentParser( 177 formatter_class=argparse.RawDescriptionHelpFormatter, 178 description=intro) 179 parser.add_argument('--deps', type=str, required=True, default="", 180 help='Must Required! Depencencies info after gn building') 181 parser.add_argument('--base_product', type=str, default="./../../../productdefine/common/base/base_product.json", 182 help='base_product.json file') 183 parser.add_argument('--config', type=str, default="./.config", 184 help='config file which is generated by kconfig operation, default is .config') 185 parser.add_argument('--out', type=str, default="./product.json", 186 help="define output file path and name, like './product.json'") 187 args = parser.parse_args() 188 print("read deps file: ", os.path.abspath(args.deps)) 189 print("read kconfig file: ", os.path.abspath(args.config)) 190 print("read base_product file: ", os.path.abspath(args.base_product)) 191 192 generate_config_with_full_deps(args.deps, args.base_product, args.config, args.out) 193 194 195if __name__ == "__main__": 196 main() 197