Parser: fix template inheritance
This commit is contained in:
parent
fab1f94faa
commit
bd65674875
2 changed files with 60 additions and 27 deletions
|
@ -169,10 +169,12 @@ orca:
|
|||
range:
|
||||
from: 9026
|
||||
to: 9042
|
||||
template: LocalForward ${port} localhost:${port}
|
||||
property: LocalForward
|
||||
template: ${port} localhost:${port}
|
||||
- variable: env
|
||||
range: ["FOO=bar", "BAR=foo"]
|
||||
template: SendEnv ${env}
|
||||
property: SendEnv
|
||||
template: ${env}
|
||||
```
|
||||
|
||||
Expands to:
|
||||
|
|
81
src/main.py
81
src/main.py
|
@ -6,7 +6,7 @@ from pathlib import Path
|
|||
|
||||
parser = argparse.ArgumentParser(description="Process some integers.")
|
||||
parser.add_argument("file", type=Path, help="yaml config")
|
||||
parser.add_argument("--json", action="store_true", help="output as json")
|
||||
parser.add_argument("--json", action="store_true", help="output parse as json")
|
||||
parser.add_argument("--out", type=Path, help="write into file")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
@ -66,23 +66,57 @@ def expand_for_loop(props):
|
|||
return expand
|
||||
|
||||
|
||||
def get_ssh_props(data, hosts):
|
||||
props = list()
|
||||
|
||||
if data.get('template'):
|
||||
props = list(hosts[data.get('template')])
|
||||
def get_ssh_props(data):
|
||||
props = dict()
|
||||
|
||||
for k, v in data["ssh_props"].items():
|
||||
if isinstance(v, list):
|
||||
for x in v:
|
||||
props.append(f"{k} {x}")
|
||||
else:
|
||||
props.append(f"{k} {v}")
|
||||
props[k] = v if isinstance(v, list) else [v]
|
||||
|
||||
return props
|
||||
|
||||
|
||||
def remove_templates(expanded, data):
|
||||
def parse_props(host, props, hosts):
|
||||
parsed = dict()
|
||||
|
||||
# Standard ssh properties
|
||||
for k, v in props.get("ssh_props", {}).items():
|
||||
parsed[k] = v if isinstance(v, list) else [v]
|
||||
|
||||
# For-loops in config
|
||||
for loop in props.get("for", []):
|
||||
prop = loop["property"]
|
||||
r = loop["range"]
|
||||
|
||||
if isinstance(r, dict):
|
||||
iterations = range(r["from"], r["to"])
|
||||
elif isinstance(r, list):
|
||||
iterations = r
|
||||
else:
|
||||
raise TypeError("Expected list or dict in `for` loop `range`")
|
||||
|
||||
if not parsed.get(prop):
|
||||
parsed[prop] = list()
|
||||
|
||||
pattern = re.compile(rf'\$\{{{loop["variable"]}\}}')
|
||||
|
||||
for i in iterations:
|
||||
sub = pattern.sub(str(i), loop["template"])
|
||||
parsed[prop].append(sub)
|
||||
|
||||
# Inherit from template
|
||||
template = props.get("template")
|
||||
|
||||
if template and template not in hosts:
|
||||
raise SyntaxError(f"Template `{template}` required by `{host}` is not declared above `{host}` in the yaml")
|
||||
elif template:
|
||||
for k, v in hosts[props.get("template")].items():
|
||||
if k not in parsed:
|
||||
parsed[k] = v
|
||||
|
||||
return parsed
|
||||
|
||||
|
||||
def remove_templates(expanded):
|
||||
hosts = dict(expanded)
|
||||
|
||||
for host, props in data.items():
|
||||
|
@ -109,21 +143,14 @@ def stringify_booleans(props):
|
|||
|
||||
|
||||
def parse_yaml(data):
|
||||
expanded = dict()
|
||||
hosts = dict()
|
||||
check_duplicate_hosts(data)
|
||||
|
||||
for host, props in data.items():
|
||||
parsed = list()
|
||||
parsed.extend(get_ssh_props(props, expanded))
|
||||
parsed.extend(expand_for_loop(props))
|
||||
hosts[host] = parse_props(host, props, hosts)
|
||||
|
||||
parsed = stringify_booleans(parsed)
|
||||
run_assertions(host, parsed)
|
||||
|
||||
expanded[host] = sorted(parsed)
|
||||
|
||||
expanded = remove_templates(expanded, data)
|
||||
return expanded
|
||||
hosts = remove_templates(hosts)
|
||||
return hosts
|
||||
|
||||
|
||||
# ╔───────────────────────────────────────────────────────────────────────────╗
|
||||
|
@ -134,8 +161,12 @@ def to_ssh_config_string(parse):
|
|||
|
||||
for host, keys in parse.items():
|
||||
s += f"Host {host}\n"
|
||||
for key in keys:
|
||||
s += f"\t{key}\n"
|
||||
for key, values in keys.items():
|
||||
for value in values:
|
||||
if isinstance(value, bool):
|
||||
s += f"\t{key} {'true' if value else 'no'}\n"
|
||||
else:
|
||||
s += f"\t{key} {value}\n"
|
||||
s += "\n"
|
||||
|
||||
return s
|
||||
|
|
Loading…
Reference in a new issue