generator.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import sys
  2. import os
  3. import json
  4. from uuid import UUID
  5. from jinja2.runtime import Macro
  6. from api.od import ODAPI
  7. from jinja2 import Environment, FileSystemLoader, meta
  8. class schedule_generator:
  9. def __init__(self, odApi:ODAPI):
  10. self.env = Environment(loader=FileSystemLoader(os.path.join(os.path.dirname(__file__), 'templates')))
  11. self.env.trim_blocks = True
  12. self.env.lstrip_blocks = True
  13. self.template = self.env.get_template('schedule_template.j2')
  14. self.template_wrap = self.env.get_template('schedule_template_wrap.j2')
  15. self.api = odApi
  16. def get_slot_value_default(item: UUID, slot:str, default):
  17. if slot in self.api.get_slots(item):
  18. return self.api.get_slot_value(item, slot)
  19. return default
  20. name_dict = lambda item: {"name": self.api.get_name(item)}
  21. conn_dict = lambda item: {"name_from": self.api.get_name(self.api.get_source(item)),
  22. "name_to": self.api.get_name(self.api.get_target(item)),
  23. "gate_from": self.api.get_slot_value(item, "gate_from"),
  24. "gate_to": self.api.get_slot_value(item, "gate_to"),
  25. }
  26. conn_data_event = {"Match": lambda item: False,
  27. "Rewrite": lambda item: False,
  28. "Data_modify": lambda item: True,
  29. "Loop": lambda item: True,
  30. "Print": lambda item: get_slot_value_default(item, "event", False)
  31. }
  32. conn_data_dict = lambda item: {"name_from": self.api.get_name(self.api.get_source(item)),
  33. "name_to": self.api.get_name(self.api.get_target(item)),
  34. "event": conn_data_event[self.api.get_type_name(target := self.api.get_target(item))](target)
  35. }
  36. rewrite_dict = lambda item: {"name": self.api.get_name(item),
  37. "file": self.api.get_slot_value(item, "file"),
  38. }
  39. match_dict = lambda item: {"name": self.api.get_name(item),
  40. "file": self.api.get_slot_value(item, "file"),
  41. "n": self.api.get_slot_value(item, "n") \
  42. if "n" in self.api.get_slots(item) else 'float("inf")'
  43. }
  44. data_modify_dict = lambda item: {"name": self.api.get_name(item),
  45. "dict": json.loads(self.api.get_slot_value(item, "modify_dict"))
  46. }
  47. loop_dict = lambda item: {"name": self.api.get_name(item),
  48. "choise": get_slot_value_default(item, "choise", False)}
  49. print_dict = lambda item: {"name": self.api.get_name(item),
  50. "label": get_slot_value_default(item, "label", "")}
  51. arg_map = {"Start": name_dict, "End": name_dict,
  52. "Match": match_dict, "Rewrite": rewrite_dict,
  53. "Data_modify": data_modify_dict, "Loop": loop_dict,
  54. "Exec_con": conn_dict, "Data_con": conn_data_dict,
  55. "Print": print_dict}
  56. self.macro_args = {tp: (macro, arg_map.get(tp)) for tp, macro in self.template.module.__dict__.items()
  57. if type(macro) == Macro}
  58. def _render(self, item):
  59. type_name = self.api.get_type_name(item)
  60. macro, arg_gen = self.macro_args[type_name]
  61. return macro(**arg_gen(item))
  62. def generate_schedule(self, stream = sys.stdout):
  63. start = self.api.get_all_instances("Start")[0][1]
  64. stack = [start]
  65. out = {"blocks":[], "exec_conn":[], "data_conn":[], "match_files":set(), "matchers":[], "start":self.api.get_name(start)}
  66. execBlocks = set()
  67. exec_conn = list()
  68. while len(stack) > 0:
  69. exec_obj = stack.pop()
  70. if exec_obj in execBlocks:
  71. continue
  72. execBlocks.add(exec_obj)
  73. for conn in self.api.get_outgoing(exec_obj, "Exec_con"):
  74. exec_conn.append(conn)
  75. stack.append(self.api.get_target(conn))
  76. stack = list(execBlocks)
  77. data_blocks = set()
  78. for name, p in self.api.get_all_instances("Print"):
  79. if "event" in (event := self.api.get_slots(p)) and event:
  80. stack.append(p)
  81. execBlocks.add(p)
  82. data_conn = set()
  83. while len(stack) > 0:
  84. obj = stack.pop()
  85. for data_c in self.api.get_incoming(obj, "Data_con"):
  86. data_conn.add(data_c)
  87. source = self.api.get_source(data_c)
  88. if not self.api.is_instance(source, "Exec") and \
  89. source not in execBlocks and \
  90. source not in data_blocks:
  91. stack.append(source)
  92. data_blocks.add(source)
  93. for exec_item in execBlocks:
  94. out["blocks"].append(self._render(exec_item))
  95. if self.api.is_instance(exec_item, "Rule"):
  96. d = self.macro_args[self.api.get_type_name(exec_item)][1](exec_item)
  97. out["match_files"].add(d["file"])
  98. out["matchers"].append(d)
  99. for exec_c in exec_conn:
  100. out["exec_conn"].append(self._render(exec_c))
  101. for data_c in data_conn:
  102. out["data_conn"].append(self._render(data_c))
  103. for data_b in data_blocks:
  104. out["blocks"].append(self._render(data_b))
  105. print(self.template_wrap.render(out), file=stream)
  106. # print("with open('test.dot', 'w') as f:", file=stream)
  107. # print(f"\tf.write({self.api.get_name(start)}.generate_dot())", file=stream)