mirror of
ssh://git.janware.com/srv/git/janware/proj/jw-python
synced 2026-01-15 09:53:32 +01:00
106 lines
3.7 KiB
Python
106 lines
3.7 KiB
Python
import os
|
|
|
|
from jwutils.stree.StringTree import *
|
|
from jwutils.log import *
|
|
|
|
def _cleanup_line(line: str) -> str:
|
|
line = line.strip()
|
|
r = ''
|
|
in_quote = None
|
|
for c in line:
|
|
# slog(DEBUG, "in_quote = >" + str(in_quote) + "<")
|
|
if in_quote is not None:
|
|
if c == in_quote:
|
|
in_quote = None
|
|
else:
|
|
if c in [ '"', "'" ]:
|
|
in_quote = c
|
|
elif in_quote is None and c == '#':
|
|
return r.strip()
|
|
r += c
|
|
if len(r) >= 2 and r[0] in [ '"', "'" ] and r[-1] == r[0]:
|
|
return r[1:-1]
|
|
return r
|
|
|
|
def parse(s: str, allow_full_lines: bool=True, root_content: str='root') -> StringTree: # export
|
|
slog_m(DEBUG, "--->--- parsing --->---\n" + s + "\n---<--- parsing ---<---\n")
|
|
root = StringTree('', content=root_content)
|
|
sec = ''
|
|
for line in s.splitlines():
|
|
slog(DEBUG, f'Parsing: "{line}"')
|
|
line = _cleanup_line(line)
|
|
#slog(DEBUG, "cleaned line=", line)
|
|
if not len(line):
|
|
continue
|
|
if line[0] == '[':
|
|
if line[-1] == ']':
|
|
sec = line[1:-1]
|
|
elif line[-1] == '[':
|
|
if len(sec):
|
|
sec += '.'
|
|
sec += line[1:-1]
|
|
else:
|
|
raise Exception("failed to parse section line", line)
|
|
if root.get(sec) is None:
|
|
root.add(sec)
|
|
continue
|
|
elif line[0] == ']':
|
|
assert(len(sec) > 0)
|
|
sec = '.'.join(sec.split('.')[0:-1])
|
|
continue
|
|
lhs = ''
|
|
rhs = None
|
|
for c in line:
|
|
if rhs is None:
|
|
if c == '=':
|
|
rhs = ''
|
|
continue
|
|
lhs += c
|
|
continue
|
|
rhs += c
|
|
|
|
split = True
|
|
if rhs is None:
|
|
if not allow_full_lines:
|
|
raise Exception("failed to parse assignment", line)
|
|
rhs = 'empty'
|
|
split = False
|
|
root.add(sec + '.' + cleanup_string(lhs), cleanup_string(rhs), split=split)
|
|
return root
|
|
|
|
def _read_lines(path: str, throw=True, level=0, log_prio=INFO, paths_buf=None):
|
|
try:
|
|
with open(path, 'r') as infile:
|
|
slog(log_prio, 'Reading {}"{}"'.format(' ' * level * 2, path))
|
|
if paths_buf is not None:
|
|
paths_buf.append(path)
|
|
ret = []
|
|
for line in infile: # lines are all trailed by \n
|
|
m = re.search(r'^\s*(-)*include\s+(\S+)', line)
|
|
if m:
|
|
optional = m.group(1) == '-'
|
|
include_path = m.group(2)
|
|
if include_path[0] != '/':
|
|
dir_name = os.path.dirname(path)
|
|
if len(dir_name):
|
|
include_path = dir_name + '/' + include_path
|
|
include_lines = _read_lines(include_path, throw=(not optional), level=level+1, paths_buf=paths_buf)
|
|
if include_lines is None:
|
|
msg = f'{path}: Failed to process "{line}"'
|
|
slog(DEBUG, line)
|
|
continue
|
|
ret.extend(include_lines)
|
|
continue
|
|
ret.append(line)
|
|
return ret
|
|
except Exception as e:
|
|
msg = f'Failed to read file "{path}": {e}'
|
|
if throw:
|
|
raise Exception(msg)
|
|
slog(DEBUG, msg)
|
|
return None
|
|
|
|
def read(path: str, root_content: str='root', log_prio=INFO, paths_buf=None) -> StringTree: # export
|
|
lines = _read_lines(path, log_prio=log_prio, paths_buf=paths_buf)
|
|
s = ''.join(lines)
|
|
return parse(s, root_content=root_content)
|