169 lines
5.2 KiB
Python
Executable File
169 lines
5.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# encoding=utf-8
|
|
# Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2022-2022. All rights reserved.
|
|
|
|
import os
|
|
import json
|
|
|
|
from utils.build_utils import color_red
|
|
from utils.build_utils import color_end
|
|
|
|
__all__ = ["MconfParser", "BuildConfParser"]
|
|
|
|
def nv_repeat_check(pairs):
|
|
key_list = []
|
|
for key_temp in pairs:
|
|
if key_temp[0] not in key_list:
|
|
key_list.append(key_temp[0])
|
|
else:
|
|
raise Exception("nv items(%s) repeat"%key_temp[0])
|
|
pairs = dict(pairs)
|
|
return pairs
|
|
|
|
class ParserError(Exception):
|
|
"""
|
|
Parse errors, highlight in red.
|
|
"""
|
|
def __init__(self, err):
|
|
emsg = "%s%s%s"%(color_red(), err, color_end())
|
|
Exception.__init__(self, emsg)
|
|
pass
|
|
|
|
"""
|
|
Json format config file parser
|
|
"""
|
|
class BuildConfParser:
|
|
def __init__(self, conf_path):
|
|
if not os.path.isfile(conf_path):
|
|
raise ParserError("Configration file %s NOT found!"%conf_path)
|
|
|
|
with open(conf_path, 'r', encoding='utf-8') as conf:
|
|
try:
|
|
myread = conf.read()
|
|
self.conf_data = json.loads(myread)
|
|
self.nvconf_data = json.loads(myread, object_pairs_hook = nv_repeat_check)
|
|
except Exception as err:
|
|
msg = "%s\nParsing file:%s"%(err, conf_path)
|
|
raise ParserError(msg)
|
|
|
|
self.conf_data = self._parse(self.conf_data)
|
|
self.nvconf_data = self._parse(self.nvconf_data)
|
|
|
|
def get_conf_data(self):
|
|
return self.conf_data
|
|
|
|
def get_nvconf_data(self):
|
|
return self.nvconf_data
|
|
|
|
def get(self, option):
|
|
return self.conf_data.get(option)
|
|
|
|
def _parse(self, data):
|
|
"""
|
|
parse the python sentence starts with ###
|
|
"""
|
|
for key, value in data.items():
|
|
if isinstance(value, dict):
|
|
# Recursion
|
|
value = self._parse(value)
|
|
if isinstance(value, list):
|
|
# Recursion
|
|
data[key] = self._parse_list(value)
|
|
if isinstance(value, int):
|
|
data[key] = value
|
|
if isinstance(value, str) and value.startswith('###'):
|
|
value = self._exec(value)
|
|
data[key] = value
|
|
return data
|
|
|
|
def _parse_list(self, values):
|
|
new_list = []
|
|
for val in values:
|
|
if type(val) is str and val.startswith('###'):
|
|
value = self._exec(val)
|
|
new_list.append(value)
|
|
elif isinstance(val, dict):
|
|
new_list.append(self._parse(val))
|
|
else:
|
|
new_list.append(val)
|
|
return new_list
|
|
|
|
def _exec(self, code):
|
|
"""
|
|
Execute the simple python sentence.
|
|
For the security reason, only allows 'os.path.join' to be input, as a path string
|
|
to support multiple platforms.
|
|
If it needs to support more python features, please use compile and eval, but careful about
|
|
the security issues.
|
|
"""
|
|
start = code.find("os.path.join")
|
|
if start < 0:
|
|
raise ParserError("The input doesn't support!")
|
|
lpt = code.find("(")
|
|
if lpt < 0 or lpt < start:
|
|
raise ParserError("The input doesn't support!")
|
|
rpt = code.find(")")
|
|
if rpt < 0 or rpt < lpt:
|
|
raise ParserError("The input doesn't support!")
|
|
path_parts = code[lpt + 1:rpt].split(",")
|
|
ret = ""
|
|
for part in path_parts:
|
|
ret = os.path.join(ret, part.lstrip(" '\"").rstrip(" '\""))
|
|
return ret
|
|
|
|
"""
|
|
Menuconfig format config file parser
|
|
"""
|
|
class MconfParser:
|
|
def __init__(self, conf_path):
|
|
if not os.path.isfile(conf_path):
|
|
raise ParserError("Configration file %s NOT found!"%conf_path)
|
|
|
|
with open(conf_path, 'r', encoding='utf-8') as conf:
|
|
self.conf_data = conf.readlines()
|
|
|
|
self.conf_data = self._parse(self.conf_data)
|
|
|
|
def get(self, option):
|
|
data = self.conf_data.get(option)
|
|
if data is None:
|
|
# Option not found be treated as false.
|
|
return 'n'
|
|
# strip " when met string values.
|
|
return data.replace('"', '')
|
|
|
|
def _parse(self, data):
|
|
settings = {}
|
|
for option in data:
|
|
if self._option_is_valid(option) is True:
|
|
key, value = self._parse_option(option)
|
|
settings[key] = value.strip().replace('\n', '').replace('\r', '')
|
|
return settings
|
|
|
|
def _option_is_valid(self, option):
|
|
option = option.strip()
|
|
if (option is None) or (option == '') or (option.startswith('#') is True):
|
|
# skip blanks and comments.
|
|
return False
|
|
return True
|
|
|
|
def _parse_option(self, option):
|
|
cfg = option.split('=')
|
|
if len(cfg) == 2:
|
|
# like "KEY=value", length always be 2. return in KEY, value
|
|
return cfg[0], cfg[1]
|
|
else:
|
|
raise ParserError("Unknow format of the option:%s"%option)
|
|
|
|
def test():
|
|
"""
|
|
Test only.
|
|
"""
|
|
parser = BuildConfParser("build/config/riscv32_toolchain.json")
|
|
print(parser.get('TargetFolder'))
|
|
mparser = MconfParser("build/config/settings.json")
|
|
print(mparser.get('CONFIG_TARGET_SOFT_VER'))
|
|
|
|
if __name__ == "__main__":
|
|
test()
|