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