• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2# encoding=utf-8
3
4# Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9#     http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
17import os
18import json
19
20from utils.build_utils import color_red
21from utils.build_utils import color_end
22
23__all__ = ["MconfParser", "BuildConfParser"]
24
25def nv_repeat_check(pairs):
26    key_list = []
27    for key_temp in pairs:
28        if key_temp[0] not in key_list:
29            key_list.append(key_temp[0])
30        else:
31            raise Exception("nv items(%s) repeat"%key_temp[0])
32    pairs = dict(pairs)
33    return pairs
34
35class ParserError(Exception):
36    """
37    Parse errors, highlight in red.
38    """
39    def __init__(self, err):
40        emsg = "%s%s%s"%(color_red(), err, color_end())
41        Exception.__init__(self, emsg)
42    pass
43
44"""
45Json format config file parser
46"""
47class BuildConfParser:
48    def __init__(self, conf_path):
49        if not os.path.isfile(conf_path):
50            raise ParserError("Configration file %s NOT found!"%conf_path)
51
52        with open(conf_path, 'r', encoding='utf-8') as conf:
53            try:
54                myread = conf.read()
55                self.conf_data = json.loads(myread)
56                self.nvconf_data = json.loads(myread, object_pairs_hook = nv_repeat_check)
57            except Exception as err:
58                msg = "%s\nParsing file:%s"%(err, conf_path)
59                raise ParserError(msg)
60
61        self.conf_data = self._parse(self.conf_data)
62        self.nvconf_data = self._parse(self.nvconf_data)
63
64    def get_conf_data(self):
65        return self.conf_data
66
67    def get_nvconf_data(self):
68        return self.nvconf_data
69
70    def get(self, option):
71        return self.conf_data.get(option)
72
73    def _parse(self, data):
74        """
75        parse the python sentence starts with ###
76        """
77        for key, value in data.items():
78            if isinstance(value, dict):
79                # Recursion
80                value = self._parse(value)
81            if isinstance(value, list):
82                # Recursion
83                data[key] = self._parse_list(value)
84            if isinstance(value, int):
85                data[key] = value
86            if isinstance(value, str) and value.startswith('###'):
87                value = self._exec(value)
88                data[key] = value
89        return data
90
91    def _parse_list(self, values):
92        new_list = []
93        for val in values:
94            if type(val) is str and val.startswith('###'):
95                value = self._exec(val)
96                new_list.append(value)
97            elif isinstance(val, dict):
98                new_list.append(self._parse(val))
99            else:
100                new_list.append(val)
101        return new_list
102
103    def _exec(self, code):
104        """
105        Execute the simple python sentence.
106        For the security reason, only allows 'os.path.join' to be input, as a path string
107        to support multiple platforms.
108        If it needs to support more python features, please use compile and eval, but careful about
109        the security issues.
110        """
111        start = code.find("os.path.join")
112        if start < 0:
113            raise ParserError("The input doesn't support!")
114        lpt = code.find("(")
115        if lpt < 0 or lpt < start:
116            raise ParserError("The input doesn't support!")
117        rpt = code.find(")")
118        if rpt < 0 or rpt < lpt:
119            raise ParserError("The input doesn't support!")
120        path_parts = code[lpt + 1:rpt].split(",")
121        ret = ""
122        for part in path_parts:
123            ret = os.path.join(ret, part.lstrip(" '\"").rstrip(" '\""))
124        return ret
125
126"""
127Menuconfig format config file parser
128"""
129class MconfParser:
130    def __init__(self, conf_path):
131        if not os.path.isfile(conf_path):
132            raise ParserError("Configration file %s NOT found!"%conf_path)
133
134        with open(conf_path, 'r', encoding='utf-8') as conf:
135            self.conf_data = conf.readlines()
136
137        self.conf_data = self._parse(self.conf_data)
138
139    def get(self, option):
140        data = self.conf_data.get(option)
141        if data is None:
142            # Option not found be treated as false.
143            return 'n'
144        # strip " when met string values.
145        return data.replace('"', '')
146
147    def _parse(self, data):
148        settings = {}
149        for option in data:
150            if self._option_is_valid(option) is True:
151                key, value = self._parse_option(option)
152                settings[key] = value.strip().replace('\n', '').replace('\r', '')
153        return settings
154
155    def _option_is_valid(self, option):
156        option = option.strip()
157        if (option is None) or (option == '') or (option.startswith('#') is True):
158            # skip blanks and comments.
159            return False
160        return True
161
162    def _parse_option(self, option):
163        cfg = option.split('=')
164        if len(cfg) == 2:
165            # like "KEY=value", length always be 2. return in KEY, value
166            return cfg[0], cfg[1]
167        else:
168            raise ParserError("Unknow format of the option:%s"%option)
169
170def test():
171    """
172    Test only.
173    """
174    parser = BuildConfParser("build/config/riscv32_toolchain.json")
175    print(parser.get('TargetFolder'))
176    mparser = MconfParser("build/config/settings.json")
177    print(mparser.get('CONFIG_TARGET_SOFT_VER'))
178
179if __name__ == "__main__":
180    test()
181