1#!/usr/bin/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 21 22SUBSYS_LIST = "subsystems" 23SUBSYS = "subsystem" 24COMPONENT_LIST = "components" 25COMPONENT = "component" 26FEATRUES = "features" 27FEATRUE = "feature" 28NONE_FEATURES = [] 29TYPE = "type" 30VALUE = "value" 31PROPERTY = "property" 32KCONF_PREFIX = "CONFIG_" 33 34 35def read_full_component(path): 36 data = {} 37 with open(path, "rb") as f: 38 data = json.load(f) 39 component_subsys_dict = {} 40 for item in data.get(SUBSYS_LIST): 41 subsys_name = item.get(SUBSYS) 42 for component in item.get(COMPONENT_LIST): 43 component_name = component.get(COMPONENT) 44 component_subsys_dict[component_name] = subsys_name 45 return component_subsys_dict 46 47 48def read_deps_info(path): 49 data = {} 50 with open(path, "rb") as f: 51 data = json.load(f) 52 return data 53 54 55def merge(component_subsys_dict, component_deps_dict, subsys_conf): 56 config_component_list = [] 57 for _, components in subsys_conf.items(): 58 for component, _ in components.items(): 59 config_component_list.append(component) 60 61 for component_name in config_component_list: 62 deps = component_deps_dict.get(component_name) 63 if deps is not None: 64 for dep in deps: 65 if dep in config_component_list: 66 continue 67 else: 68 subsys_name = component_subsys_dict.get(dep) 69 if subsys_name is None: 70 continue 71 if subsys_conf.get(subsys_name) is None: 72 subsys_conf[subsys_name] = {dep: NONE_FEATURES} 73 else: 74 subsys_conf[subsys_name][dep] = NONE_FEATURES 75 config_component_list.append(dep) 76 77 78def is_valid_line(line): 79 return line.startswith(KCONF_PREFIX) 80 81 82def handle_config_feature(items, arr, line): 83 items[TYPE] = FEATRUE 84 items[SUBSYS] = arr[1] 85 items[COMPONENT] = arr[2].split("=")[0] 86 features = line.split("=", 1)[1].strip("\"") 87 if features == "": 88 items[FEATRUES] = NONE_FEATURES 89 else: 90 items[FEATRUES] = features.split(",") 91 92 93def handle_config_component(items, arr, line): 94 items[TYPE] = COMPONENT 95 items[SUBSYS] = arr[0].split("_", 1)[1] 96 items[COMPONENT] = arr[1].split("=")[0] 97 items[VALUE] = line.split("=", 1)[1] 98 99 100def handle_config_property(items, arr, line): 101 items[PROPERTY] = arr[1].split("=")[0] 102 items[TYPE] = PROPERTY 103 items[VALUE] = line.split("=", 1)[1].strip("\"") 104 105 106def read_line_item(line): 107 line = line.strip() 108 items = { 109 TYPE: None, 110 SUBSYS: None, 111 FEATRUES: None, 112 COMPONENT: None, 113 PROPERTY: None, 114 VALUE: None 115 } 116 arr = line.split("$$") 117 if arr[0] == "CONFIG_feature": 118 handle_config_feature(items, arr, line) 119 elif arr[0] == "CONFIG_property": 120 handle_config_property(items, arr, line) 121 else: 122 handle_config_component(items, arr, line) 123 return items 124 125 126def read(kconf): 127 result, subsys_conf = {}, {} 128 with open(kconf, "r") as f: 129 for line in f.readlines(): 130 if not is_valid_line(line): 131 continue 132 items = read_line_item(line) 133 subsys = items.get(SUBSYS) 134 component = items.get(COMPONENT) 135 conf_type = items.get(TYPE) 136 features = items.get(FEATRUES) 137 if conf_type == PROPERTY: 138 if len(items.get(VALUE)) > 0: 139 result[items.get(PROPERTY)] = items.get(VALUE) 140 elif conf_type == FEATRUE or conf_type == COMPONENT: 141 if subsys_conf.get(subsys) is None: 142 subsys_conf[subsys] = {} 143 subsys_conf.get(subsys)[component] = features 144 145 result[SUBSYS_LIST] = subsys_conf 146 return result 147 148 149def generate_config_with_full_deps(deps_path, base_product_path, config_path, out): 150 kconf = read(config_path) 151 subsys_conf = kconf.get(SUBSYS_LIST) 152 component_subsys_dict = read_full_component(base_product_path) 153 component_deps_dict = read_deps_info(deps_path) 154 merge(component_subsys_dict, component_deps_dict, subsys_conf) 155 subsystems_list = [] 156 for subsys, components in subsys_conf.items(): 157 temp = {SUBSYS: subsys, COMPONENT_LIST: []} 158 for component, features in components.items(): 159 component_element = {COMPONENT: component, FEATRUES: features} 160 temp.get(COMPONENT_LIST).append(component_element) 161 subsystems_list.append(temp) 162 result = kconf 163 result[SUBSYS_LIST] = subsystems_list 164 with open(out, "w") as f: 165 f.write(json.dumps(result, indent=2)) 166 print("output file in: ", os.path.abspath(out)) 167 168 169def main(): 170 intro = 'Genenrate newly kconfig input file.\n\ 171 For example: python3 parse_kconf.py --deps={$repo}/out/{your_product}/part_deps_info/part_deps_info.json \n\ 172 or python3 parse_kconf.py --base_product={$repo}/productdefine/common/base/base_product.json \ 173--out=./product.json --deps={$repo}/out/{your_product}/part_deps_info/part_deps_info.json --config=./.config' 174 parser = argparse.ArgumentParser( 175 formatter_class=argparse.RawDescriptionHelpFormatter, 176 description=intro) 177 parser.add_argument('--deps', type=str, required=True, default="", 178 help='Must Required! Depencencies info after gn building') 179 parser.add_argument('--base_product', type=str, default="./../../../productdefine/common/base/base_product.json", 180 help='base_product.json file') 181 parser.add_argument('--config', type=str, default="./.config", 182 help='config file which is generated by kconfig operation, default is .config') 183 parser.add_argument('--out', type=str, default="./product.json", 184 help="define output file path and name, like './product.json'") 185 args = parser.parse_args() 186 print("read deps file: ", os.path.abspath(args.deps)) 187 print("read kconfig file: ", os.path.abspath(args.config)) 188 print("read base_product file: ", os.path.abspath(args.base_product)) 189 190 generate_config_with_full_deps(args.deps, args.base_product, args.config, args.out) 191 192 193if __name__ == "__main__": 194 main() 195