• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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