Tool for creating JSON from configuration file

This commit is contained in:
Thomas Hooge 2025-08-05 12:07:07 +02:00
parent 1d05c2b5d4
commit cbc0c09d65
1 changed files with 172 additions and 0 deletions

172
lib/obp60task/utils/make_json.py Executable file
View File

@ -0,0 +1,172 @@
#!/usr/bin/python
"""
Convert config file to JSON
The JSON contains array of single fields. There is no hierarchy.
Fields are being grouped in GUI with "category".
A group is shown if a minimum of one field is visible.
Hints
capabilities is a dictionary
field:[true | false]
optional comma separated multiple values
"""
import os
import sys
import getopt
import configparser
from io import StringIO
from pyparsing import alphas, alphanums, Word, Literal, Combine, Group, Forward, ZeroOrMore, delimitedList
__author__ = "Thomas Hooge"
__copyright__ = "Copyleft 2025, all rights reversed"
__version__ = "0.1"
__email__ = "thomas@hoogi.de"
__status__ = "Development"
infile = None
outfile = ""
force = False # overwrite outfile
# Variables for condition parsing
fieldname = Combine(Word(alphas, exact=1) + Word(alphanums, max=15))
fieldvalue = Word(alphanums, max=16)
equals = Literal("=")
in_op = Literal("IN")
and_op = Literal("AND")
or_op = Literal("OR")
comparison = Group(fieldname + equals + fieldvalue) \
| Group(fieldname + in_op + delimitedList(fieldvalue))
expr = Forward()
expr <<= comparison + ZeroOrMore((and_op | or_op) + comparison)
def parse_condition(condition):
try:
result = expr.parseString(condition, parseAll=True)
except Exception as e:
return ""
out = StringIO()
andlist = []
for token in result:
# list: field = value or field IN value [, value ...]
# str: AND, OR
# combine ANDs and output reaching OR
if type(token) == str:
if token == "OR":
andstr = ",\n".join(andlist)
out.write(f'\t\t{{ {andstr} }},\n')
andlist = []
else:
if token[1] == '=':
andlist.append(f'"{token[0]}": "{token[2]}"')
elif token[1] == 'IN':
n = len(token) - 2
if n == 1:
# no list, write single value
andlist.append(f'"{token[0]}": "{token[2]}"')
else:
# write list
inlist = '", "'.join(token[2:])
andlist.append(f'"{token[0]}": [ "{inlist}" ]\n')
if len(andlist) > 0:
out.write("\t\t{{ {} }}".format(", ".join(andlist)))
return out.getvalue()
def create_flist():
flist = []
for field in config.sections():
properties = [f'\t"name": "{field}"']
for prop, val in config.items(field):
if prop in ["label", "type", "default", "description", "category", "check"]:
properties.append(f'\t"{prop}": "{val}"')
elif prop == "capabilities":
# multiple values possible
capas = []
for capa in val.split(','):
k, v = capa.split(':')
capas.append(f'"{k.strip()}":"{v.strip()}"')
capalist = ','.join(capas)
properties.append(f'\t"{prop}": {{{capalist}}}')
elif prop in ("min", "max"):
properties.append(f'\t"{prop}": {val}')
elif prop == "list":
entries = '", "'.join([x.strip() for x in val.split(',')])
properties.append(f'\t"list": ["{entries}"]')
elif prop == "dict":
d = {}
for l in val.splitlines():
if len(l) < 3:
continue
k, v = l.split(':')
d[k.strip()] = v.strip()
lines = []
for k,v in d.items():
lines.append(f'\t\t{{"l":"{v}","v":"{k}"}}')
entries = ",\n".join(lines)
properties.append(f'\t"list": [\n{entries}\n\t]')
elif prop == "condition":
jsoncond = parse_condition(val)
properties.append(f'\t"{prop}": [\n{jsoncond}\n\t]\n')
else:
pass # ignore unknown stuff
fieldprops = ",\n".join(properties)
flist.append(f'{{\n{fieldprops}\n}}')
return flist
def usage():
print("{} v{}".format(os.path.basename(__file__), __version__))
print(__copyright__)
print()
print("Command line options")
print(" -c --config config file name to use")
print(" -j --json json file name to generate")
print(" -f force overwrite of existing json file")
print(" -h show this help")
print()
if __name__ == '__main__':
try:
options, remainder = getopt.getopt(sys.argv[1:], 'c:j:fh', ['config=', 'json='])
except getopt.GetoptError as e:
print(e)
sys.exit(1)
filename = None
for opt, arg in options:
if opt in ('-c', '--config'):
infile = arg
elif opt in ('-j', '--json'):
outfile = arg
elif opt == '-h':
usage()
sys.exit(0)
elif opt == '-f':
force = True
if not infile:
print("Error: config filename missing")
sys.exit(1)
if not os.path.isfile(infile):
print(f"Error: configuration file '{filename} not found'")
sys.exit(1)
if os.path.isfile(outfile) and not force:
print(f"Error: json file '{outfile}' already exists")
sys.exit(1)
config = configparser.ConfigParser()
ret = config.read(infile)
if len(ret) == 0:
print(f"ERROR: Config file '{infile}' not found")
sys.exit(1)
flist = create_flist()
out = "[\n{}\n]\n".format(",\n".join(flist))
if not outfile:
# print to console
print(out)
else:
# write to file
with open(outfile, "w") as fh:
fh.write(out)