Skip to content

Commit a7c4907

Browse files
committed
Handle includes in python scripts
1 parent 401484e commit a7c4907

File tree

3 files changed

+90
-2
lines changed

3 files changed

+90
-2
lines changed

docs/spec2html.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
from mako.template import Template
77
from mako.lookup import TemplateLookup
88

9+
import sys
10+
sys.path.append(str(pathlib.Path(__file__).parents[1] / "scripts"))
11+
from inject_include import inject_include # noqa
12+
913

1014
class json_navigator:
1115
def __init__(self, ijson):
@@ -32,6 +36,9 @@ def rules_from_pointer(self, pointer):
3236
with open(args.input) as input_file:
3337
input = json.load(input_file)
3438

39+
# TODO: Expose the include path as a parameter
40+
input = inject_include(input, [pathlib.Path(args.input).parent])
41+
3542
# print(input)
3643

3744
print("02 - Templating")

scripts/generate_defaults.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import argparse
22
import json
33
from collections import OrderedDict
4+
import pathlib
5+
6+
import sys
7+
sys.path.append(str(pathlib.Path(__file__).parent))
8+
from inject_include import inject_include # noqa
49

510

611
def find_rules(spec, pointer):
@@ -12,11 +17,11 @@ def generate_defaults(spec, root="/"):
1217
rules = find_rules(spec, root)
1318

1419
default_rule = list(filter(lambda rule: "default" in rule, rules))
15-
assert(len(default_rule) <= 1)
20+
assert (len(default_rule) <= 1)
1621

1722
object_rules = list(filter(lambda rule: rule["type"] == "object", rules))
1823

19-
if(default_rule and default_rule[0]["default"] is not None and not object_rules):
24+
if (default_rule and default_rule[0]["default"] is not None and not object_rules):
2025
return default_rule[0]["default"]
2126
else:
2227
for i, rule in enumerate(object_rules):
@@ -51,6 +56,9 @@ def main():
5156
with open(args.spec_path) as f:
5257
spec = json.load(f)
5358

59+
# TODO: Expose the include path as a parameter
60+
spec = inject_include(spec, [pathlib.Path(args.spec_path).parent])
61+
5462
defaults = generate_defaults(spec)
5563

5664
with open(args.output, "w") as f:

scripts/inject_include.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import json
2+
import pathlib
3+
4+
5+
def prepend_pointer(pointer, key):
6+
if key == "/":
7+
return pointer
8+
elif pointer == "/":
9+
return key
10+
else:
11+
return key + pointer
12+
13+
14+
def inject_include(rules: dict, dirs=None):
15+
if dirs is None:
16+
dirs = []
17+
dirs.append("") # adding default path
18+
dirs = [pathlib.Path(d) for d in dirs]
19+
20+
# max 10 levels of nesting to avoid infinite loops
21+
current = rules
22+
23+
for _ in range(10):
24+
# check if the rules have any include
25+
include_present = any(rule["type"] == "include" for rule in current)
26+
27+
# if there are no includes, return the current ones
28+
if not include_present:
29+
return current
30+
31+
enriched = []
32+
# otherwise, do a round of replacement
33+
for rule in current:
34+
# copy all rules that are not include
35+
if rule["type"] != "include":
36+
enriched.append(rule)
37+
continue
38+
39+
# if the rule is an include, expand the node with a copy of the included file
40+
replaced = False
41+
# the include file could be in any of the include directories
42+
for dir in dirs:
43+
spec_file = rule["spec_file"]
44+
f = dir / spec_file
45+
# check if the file exists
46+
if f.is_file():
47+
with open(f, 'r') as ifs:
48+
include_rules = json.load(ifs)
49+
50+
# loop over all rules to add the prefix
51+
for i_rule in include_rules:
52+
prefix = rule["pointer"]
53+
pointer = i_rule["pointer"]
54+
new_pointer = prepend_pointer(pointer, prefix)
55+
i_rule["pointer"] = new_pointer
56+
57+
# save modified rules
58+
for i_rule in include_rules:
59+
enriched.append(i_rule)
60+
61+
# one substitution is enough, give up the search over include dirs
62+
replaced = True
63+
break
64+
65+
if not replaced:
66+
pointer = rule["pointer"]
67+
raise RuntimeError(
68+
f"Failed to replace the include rule: {pointer}")
69+
70+
# now that we replaced the include, copy it back to current
71+
current = enriched
72+
73+
raise RuntimeError("Reached maximal 10 levels of include recursion.")

0 commit comments

Comments
 (0)