from src.parser import Parser, ParseException, parse_environment from jinja2 import Template import argparse import sys import os _here = os.path.dirname(os.path.realpath(__file__)) class ListFormalisms(argparse.Action): def __init__(self, option_strings, dest=argparse.SUPPRESS, default=argparse.SUPPRESS, **kwargs): super().__init__( option_strings=option_strings, dest=dest, default=default, nargs=0, **kwargs) def __call__(self, parser, namespace, values, option_string=None): print("The following formalisms are available for generation " "('ENV' identifies which environment variables are available):") self.list() print("\nUse the -F/--formalism flag to specify which one you want to use.") parser.exit() @staticmethod def list(): contents = os.listdir(os.path.join(_here, "formalisms")) for file in contents: path = os.path.join(_here, "formalisms", file) if os.path.isdir(path) and "__init__.py" in os.listdir(path): _local = {} with open(os.path.join(path, "__init__.py")) as F: exec(F.read(), {}, _local) print(" -", "{:<10}".format(file), "ENV:", _local["setup"]["generator"]["environment"]) # Read commandline variables argprs = argparse.ArgumentParser(description='Create model/simulation files from draw.io/diagrams.net XML files.') argprs.add_argument('input', type=str, help="The input file to convert.") argprs.add_argument("-F", "--formalism", required=True, help="The formalism for which files must be generated. " "Use -L or --list to show the available formalisms.") argprs.add_argument("-e", "--entry", default='', help="The topmost class to use in the simulation.") argprs.add_argument("-t", "--time", default=10, type=float, help="Total simulation time. (default: 10)") argprs.add_argument('-L', '--list', action=ListFormalisms, help="Lists the available formalisms.") argprs.add_argument('-s', '--skip', action='store_true', help="When set, empty blocks will be skipped in the generation, otherwise they are created.") argprs.add_argument('-d', '--directory', default='./', help="Directory of where the files must be generated. (default: ./)") argprs.add_argument('-f', '--force', action='store_true', help="Force generation of the experiment file.") argprs.add_argument('-a', '--all', action='store_true', help="Generate all files associated to the formalism.") argprs.add_argument('-v', '--verbose', action='store_true', help="Output generation information.") argprs.add_argument('-E', '--environment', help="Optional parameters to add to the generation; " "as comma-separated key-value list. See -L/--list for more info.") args = argprs.parse_args() if args.verbose: print("[ DEBUG ] Loading Formalism...") # Load correct formalism setup file form = args.formalism contents = os.listdir(os.path.join(_here, "formalisms")) if form not in contents: print(f"[ ERROR ] Could not find formalism '{form}'. Try one of:") ListFormalisms.list() sys.exit(1) try: with open(os.path.join(_here, "formalisms", form, "__init__.py"), 'r') as file: _locals = {} exec(file.read(), {}, _locals) setup = _locals["setup"] default_setup_parser = { "input class": "InputPort", "output class": "OutputPort", "class object xpath": ".//object/mxCell/mxGeometry/mxRectangle/../../..[@class_name]", "special object xpath": ".//object/mxCell/mxGeometry/../..[@role]" } setup_parser = setup.get("parser", {}) setup_parser = {**default_setup_parser, **setup_parser} default_setup_generator = { "verify": [], "ignore": [], "environment": [], "templates": [] } setup_generator = setup.get("generator", {}) setup_generator = {**default_setup_generator, **setup_generator} except Exception as e: print("[ ERROR ] Could not load formalism.") print(e) sys.exit(1) if args.verbose: print("[ DEBUG ] Parsing DrawIO File...") # Parse the drawio file parser = Parser(args.input, setup_parser, args.skip) nodes = list(parser.parse()) for ver in setup_generator["verify"]: if not ver["function"](nodes): raise ParseException(ver["error"]) # Create the files fields = { "command": " ".join(sys.argv), "nodes": nodes, "ignore": setup_generator["ignore"], "time": args.time, "imports": parser.get_imports() } for blueprint in setup_generator["templates"]: if blueprint.get("auto", True) or args.all: loc = os.path.join(args.directory, blueprint["filename"]) if os.path.isfile(loc) and not blueprint.get("overwrite", True) and not args.force: print(f"[ WARNING ] File '{loc}' already exists. Use -f/--force to regenerate this file.") continue path = os.path.join(_here, "formalisms", form, blueprint["filename"] + ".jinja") with open(path, 'r') as file: template = Template(file.read(), trim_blocks=True, lstrip_blocks=True) env = parse_environment(args.environment) a = {} if blueprint.get("entry", False): if args.entry == '': print(f"[ WARNING ] Could not generate '{loc}' file. -e/--entry missing.") continue a["entry"] = args.entry contents = template.render(**fields, **a, **env) with open(loc, 'w') as file: file.write(contents) if args.verbose: print(f"[ DEBUG ] Generated '{loc}'.") if args.verbose: print("[ DEBUG ] Done.")