Tool for creating JSON from configuration file
This commit is contained in:
parent
1d05c2b5d4
commit
cbc0c09d65
|
@ -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)
|
Loading…
Reference in New Issue