#!/usr/bin/env python3 # =============================================================================== # NAME: codegen.py # # DESCRIPTION: This script is used to generate components, ports and connectors # from XML definition files. # # =============================================================================== import glob import logging import os import sys import time import traceback from optparse import OptionParser from lxml import etree # Meta-model for Component only generation from fprime_ac.models import CompFactory, PortFactory, Serialize, TopoFactory # Parsers to read the XML from fprime_ac.parsers import ( XmlArrayParser, XmlComponentParser, XmlParser, XmlPortsParser, XmlSerializeParser, XmlTopologyParser, XmlEnumParser, ) from fprime_ac.utils import ( ArrayGenerator, ConfigManager, DictTypeConverter, EnumGenerator, Logger, ) from fprime_ac.utils.buildroot import get_build_roots, search_for_file, set_build_roots # Generators to produce the code try: from fprime_ac.generators import GenFactory except ImportError as ime: print("[ERROR] Cheetah templates need to be generated.\n\t", ime, file=sys.stderr) sys.exit(1) # Flag to indicate verbose mode. VERBOSE = False # Global logger init. below. PRINT = logging.getLogger("output") DEBUG = logging.getLogger("debug") # Used by unit test to disable things. TEST = False # After catching exception this is set True # so a clean up routine deletes *_ac_*.[ch] # and *_ac_*.xml files within module. ERROR = False # Configuration manager object. CONFIG = ConfigManager.ConfigManager.getInstance() # Build a default log file name SYS_TIME = time.gmtime() # Deployment name from topology XML only DEPLOYMENT = None # Version label for now class Version: id = "0.1" comment = "Initial prototype" VERSION = Version() def moveCAndHFiles(path_prefix): """ Moves the generated c and h files to a specific directory. """ for f in glob.glob("*.c"): os.rename(f, os.path.join(path_prefix, f)) for f in glob.glob("*.h"): os.rename(f, os.path.join(path_prefix, f)) def cleanUp(): """ If something failed then clean up files generated. """ PRINT.info("ERROR: Cleaning up partially created files.") for file in glob.glob("*_ac_*.new"): os.remove(file) for file in glob.glob("*_token.data"): os.remove(file) for file in glob.glob("*_opcode_offset.data"): os.remove(file) PRINT.info("Completed.") sys.exit(-1) def pinit(): """ Initialize the option parser and return it. """ current_dir = os.getcwd() usage = "usage: %prog [options] [xml_filename]" vers = "%prog " + VERSION.id + " " + VERSION.comment parser = OptionParser(usage, version=vers) parser.add_option( "-b", "--build_root", dest="build_root_flag", help="Enable search for enviornment variable BUILD_ROOT to establish absolute XML directory path", action="store_true", default=False, ) parser.add_option( "-p", "--path", dest="work_path", type="string", help="Switch to new working directory (def: %s)." % current_dir, action="store", default=current_dir, ) parser.add_option( "-v", "--verbose", dest="verbose_flag", help="Enable verbose mode showing more runtime detail (def: False)", action="store_true", default=False, ) parser.add_option( "-t", "--template", dest="impl_flag", help="Enable generation of *Impl_[hpp,cpp].template implementation template files (def: False)", action="store_true", default=False, ) parser.add_option( "-u", "--unit-test", dest="unit_test", help="Enable generation of unit test component files (def: False)", action="store_true", default=False, ) parser.add_option( "-l", "--logger", dest="logger", default="QUIET", help="Set the logging level (def: 'QUIET').", ) parser.add_option( "-L", "--logger-output-file", dest="logger_output", default=None, help="Set the logger output file. (def: defaultgen.log).", ) parser.add_option( "-d", "--dependency-file", dest="dependency_file", default=None, help="Set the output file for build dependencies", ) parser.add_option( "-g", "--default_dict", dest="default_dict", help="Generate default GDS dictionary classes", action="store_true", default=False, ) parser.add_option( "-x", "--xml_topology_dict", dest="xml_topology_dict", help="Generate XML GDS dictionary file", action="store_true", default=False, ) parser.add_option( "-T", "--default_topology_dict", dest="default_topology_dict", help="Generate default GDS topology dictionary classes", action="store_true", default=False, ) parser.add_option( "-o", "--dict_dir", dest="dict_dir", help="Output directory for dictionary. Needed for -g.", default=None, ) parser.add_option( "-H", "--html_docs", dest="html_docs", help="Generate HTML docs for commands, telemetry, events, and parameters", action="store_true", default=False, ) parser.add_option( "-D", "--html_doc_dir", dest="html_doc_dir", help="Directory for HTML documentation", default=None, ) parser.add_option( "-m", "--md_docs", dest="md_docs", help="Generate MarkDown docs for commands, telemetry, events, and parameters", action="store_true", default=False, ) parser.add_option( "-M", "--md_doc_dir", dest="md_doc_dir", help="Directory for MarkDown documentation", default=None, ) parser.add_option( "-P", "--is_ptr", dest="is_ptr", help="Generate component ptr's in topology.", action="store_true", default=False, ) parser.add_option( "-C", "--connect_only", dest="connect_only", help="Only generate port connections in topology.", action="store_true", default=False, ) parser.add_option( "-r", "--gen_report", dest="gen_report", help="Generate reports on component interfaces", action="store_true", default=False, ) # author = os.environ['USER'] # parser.add_option("-a", "--author", dest="author", type="string", # help="Specify the new FSW author (def: %s)." % author, # action="store", default=author) # CONFIG = ConfigManager.ConfigManager.getInstance() # v = CONFIG.get('ipc','FSW_version_id') + '_' + time.strftime("%Y%m%d") # parser.add_option("-f", "--FSW_version_id", dest="fsw_ver", type="string", # help="Specify the version ID here (def: %s)." % v, # action="store", default=v) return parser def generate_topology(the_parsed_topology_xml, xml_filename, opt): DEBUG.debug("Topology xml type description file: %s" % xml_filename) generator = TopoFactory.TopoFactory.getInstance() if not (opt.default_topology_dict or opt.xml_topology_dict): generator.set_generate_ID(False) topology_model = generator.create(the_parsed_topology_xml) if opt.is_ptr: PRINT.info("Topology Components will be initalized as Pointers. ") topology_model.is_ptr = opt.is_ptr if opt.connect_only: PRINT.info("Only port connections will be generated for Topology.") topology_model.connect_only = opt.connect_only generator = GenFactory.GenFactory.getInstance() if "Ai" in xml_filename: base = xml_filename.split("Ai")[0] h_instance_name = base + "_H" cpp_instance_name = base + "_Cpp" csv_instance_name = base + "_ID" cmd_html_instance_name = base + "_Cmd_HTML" channel_html_instance_name = base + "_Channel_HTML" event_html_instance_name = base + "_Event_HTML" else: PRINT.info("Missing Ai at end of file name...") raise OSError # Figures out what visitor to use if opt.default_topology_dict or opt.xml_topology_dict: generator.configureVisitor( h_instance_name, "InstanceTopologyHVisitor", True, True ) generator.configureVisitor( cpp_instance_name, "InstanceTopologyCppVisitor", True, True ) else: generator.configureVisitor(h_instance_name, "TopologyHVisitor", True, True) generator.configureVisitor(cpp_instance_name, "TopologyCppVisitor", True, True) # Used to generate base ID/base ID window CSV files if True: generator.configureVisitor(csv_instance_name, "TopologyIDVisitor", True, True) # Used to generate HTML tables of ID's etc. if opt.default_topology_dict or opt.xml_topology_dict: generator.configureVisitor( cmd_html_instance_name, "InstanceTopologyCmdHTMLVisitor", True, True ) generator.configureVisitor( channel_html_instance_name, "InstanceTopologyChannelsTMLVisitor", True, True ) generator.configureVisitor( event_html_instance_name, "InstanceTopologyEventsHTMLVisitor", True, True ) # uses the topology model to process the items if opt.default_topology_dict or opt.xml_topology_dict: # create list of used parsed component xmls parsed_xml_dict = {} for comp in the_parsed_topology_xml.get_instances(): if comp.get_type() in topology_model.get_base_id_dict(): parsed_xml_dict[comp.get_type()] = comp.get_comp_xml() # comp.set_component_object(comp.) else: PRINT.info( "Components with type {} aren't in the topology model.".format( comp.get_type() ) ) # Hack to set up deployment path for instanced dictionaries (if one exists remove old one) # if opt.default_topology_dict: for build_root in get_build_roots(): if not os.path.exists(os.path.join(build_root, DEPLOYMENT)): continue os.environ["DICT_DIR"] = os.path.join(build_root, DEPLOYMENT, "py_dict") else: raise FileNotFoundError( "{} not found in any of: {}".format(DEPLOYMENT, get_build_roots()) ) dict_dir = os.environ["DICT_DIR"] PRINT.info("Removing old instanced topology dictionaries in: %s", dict_dir) import shutil if os.path.exists(dict_dir): shutil.rmtree(dict_dir) PRINT.info( "Overriding for instanced topology dictionaries the --dict_dir option with xml derived path: %s", dict_dir, ) # xml_list = [] for parsed_xml_type in parsed_xml_dict: if parsed_xml_dict[parsed_xml_type] is None: PRINT.info( "XML of type {} is being used, but has not been parsed correctly. Check if file exists or add xml file with the 'import_component_type' tag to the Topology file.".format( parsed_xml_type ) ) raise Exception() xml_list.append(parsed_xml_dict[parsed_xml_type]) generate_component_instance_dictionary( parsed_xml_dict[parsed_xml_type], opt, topology_model ) topology_model.set_instance_xml_list(xml_list) if opt.xml_topology_dict: topology_dict = etree.Element("dictionary") topology_dict.attrib["topology"] = the_parsed_topology_xml.get_name() # create a new XML tree for dictionary enum_list = etree.Element("enums") serializable_list = etree.Element("serializables") array_list = etree.Element("arrays") command_list = etree.Element("commands") event_list = etree.Element("events") telemetry_list = etree.Element("channels") parameter_list = etree.Element("parameters") for comp in the_parsed_topology_xml.get_instances(): comp_type = comp.get_type() comp_name = comp.get_name() comp_id = int(comp.get_base_id()) PRINT.debug( "Processing {} [{}] ({})".format(comp_name, comp_type, hex(comp_id)) ) # check for included enum XML in referenced XML at top if parsed_xml_dict[comp_type].get_enum_type_files() != []: enum_file_list = parsed_xml_dict[comp_type].get_enum_type_files() for enum_file in enum_file_list: enum_file = search_for_file("Enum", enum_file) enum_model = XmlEnumParser.XmlEnumParser(enum_file) enum_elem = etree.Element("enum") enum_type = ( enum_model.get_namespace() + "::" + enum_model.get_name() ) enum_elem.attrib["type"] = enum_type for ( member_name, member_value, member_comment, ) in enum_model.get_items(): enum_mem = etree.Element("item") enum_mem.attrib["name"] = member_name # keep track of incrementing enum value if member_value is not None: enum_value = int(member_value) enum_mem.attrib["value"] = "%d" % enum_value enum_value = enum_value + 1 if member_comment is not None: enum_mem.attrib["description"] = member_comment enum_elem.append(enum_mem) enum_list.append(enum_elem) # check for included serializable XML if parsed_xml_dict[comp_type].get_serializable_type_files() is not None: serializable_file_list = parsed_xml_dict[ comp_type ].get_serializable_type_files() for serializable_file in serializable_file_list: serializable_file = search_for_file( "Serializable", serializable_file ) serializable_model = XmlSerializeParser.XmlSerializeParser( serializable_file ) if len(serializable_model.get_includes()) != 0: raise Exception( "%s: Can only include one level of serializable for dictionaries" % serializable_file ) # check for included enum XML in included serializable XML if len(serializable_model.get_include_enums()) != 0: enum_file_list = serializable_model.get_include_enums() for enum_file in enum_file_list: enum_file = search_for_file("Enum", enum_file) enum_model = XmlEnumParser.XmlEnumParser(enum_file) enum_elem = etree.Element("enum") enum_type = ( enum_model.get_namespace() + "::" + enum_model.get_name() ) enum_elem.attrib["type"] = enum_type for ( member_name, member_value, member_comment, ) in enum_model.get_items(): enum_mem = etree.Element("item") enum_mem.attrib["name"] = member_name # keep track of incrementing enum value if member_value is not None: enum_value = int(member_value) enum_mem.attrib["value"] = "%d" % enum_value enum_value = enum_value + 1 if member_comment is not None: enum_mem.attrib["description"] = member_comment enum_elem.append(enum_mem) enum_list.append(enum_elem) serializable_elem = etree.Element("serializable") serializable_type = ( serializable_model.get_namespace() + "::" + serializable_model.get_name() ) serializable_elem.attrib["type"] = serializable_type members_elem = etree.Element("members") for ( member_name, member_type, member_size, member_format_specifier, member_comment, ) in serializable_model.get_members(): member_elem = etree.Element("member") member_elem.attrib["name"] = member_name member_elem.attrib[ "format_specifier" ] = member_format_specifier if member_comment is not None: member_elem.attrib["description"] = member_comment if isinstance(member_type, tuple): enum_value = 0 type_name = "{}::{}::{}".format( serializable_type, member_name, member_type[0][1], ) # Add enum entry enum_elem = etree.Element("enum") enum_elem.attrib["type"] = type_name # Add enum members for (membername, value, comment) in member_type[1]: enum_mem = etree.Element("item") enum_mem.attrib["name"] = membername # keep track of incrementing enum value if value is not None: enum_value = int(value) enum_mem.attrib["value"] = "%d" % enum_value enum_value = enum_value + 1 if comment is not None: enum_mem.attrib["description"] = comment enum_elem.append(enum_mem) enum_list.append(enum_elem) else: type_name = member_type if member_type == "string": member_elem.attrib["len"] = member_size member_elem.attrib["type"] = type_name members_elem.append(member_elem) serializable_elem.append(members_elem) serializable_list.append(serializable_elem) # check for commands if parsed_xml_dict[comp_type].get_commands() is not None: for command in parsed_xml_dict[comp_type].get_commands(): PRINT.debug("Processing Command %s" % command.get_mnemonic()) command_elem = etree.Element("command") command_elem.attrib["component"] = comp_name command_elem.attrib["mnemonic"] = command.get_mnemonic() command_elem.attrib["opcode"] = "%s" % ( hex(int(command.get_opcodes()[0], base=0) + comp_id) ) if "comment" in list(command_elem.attrib.keys()): command_elem.attrib["description"] = command_elem.attrib[ "comment" ] args_elem = etree.Element("args") for arg in command.get_args(): arg_elem = etree.Element("arg") arg_elem.attrib["name"] = arg.get_name() arg_type = arg.get_type() if isinstance(arg_type, tuple): enum_value = 0 type_name = "{}::{}::{}".format( comp_type, arg.get_name(), arg_type[0][1], ) # Add enum entry enum_elem = etree.Element("enum") enum_elem.attrib["type"] = type_name # Add enum members for (membername, value, comment) in arg_type[1]: enum_mem = etree.Element("item") enum_mem.attrib["name"] = membername # keep track of incrementing enum value if value is not None: enum_value = int(value) enum_mem.attrib["value"] = "%d" % enum_value enum_value = enum_value + 1 if comment is not None: enum_mem.attrib["description"] = comment enum_elem.append(enum_mem) enum_list.append(enum_elem) else: type_name = arg_type if arg_type == "string": arg_elem.attrib["len"] = arg.get_size() arg_elem.attrib["type"] = type_name args_elem.append(arg_elem) command_elem.append(args_elem) command_list.append(command_elem) # check for channels if parsed_xml_dict[comp_type].get_channels() is not None: for chan in parsed_xml_dict[comp_type].get_channels(): PRINT.debug("Processing Channel %s" % chan.get_name()) channel_elem = etree.Element("channel") channel_elem.attrib["component"] = comp_name channel_elem.attrib["name"] = chan.get_name() channel_elem.attrib["id"] = "%s" % ( hex(int(chan.get_ids()[0], base=0) + comp_id) ) if chan.get_format_string() is not None: channel_elem.attrib[ "format_string" ] = chan.get_format_string() if chan.get_comment() is not None: channel_elem.attrib["description"] = chan.get_comment() channel_elem.attrib["id"] = "%s" % ( hex(int(chan.get_ids()[0], base=0) + comp_id) ) if "comment" in list(channel_elem.attrib.keys()): channel_elem.attrib["description"] = channel_elem.attrib[ "comment" ] channel_type = chan.get_type() if isinstance(channel_type, tuple): enum_value = 0 type_name = "{}::{}::{}".format( comp_type, chan.get_name(), channel_type[0][1], ) # Add enum entry enum_elem = etree.Element("enum") enum_elem.attrib["type"] = type_name # Add enum members for (membername, value, comment) in channel_type[1]: enum_mem = etree.Element("item") enum_mem.attrib["name"] = membername # keep track of incrementing enum value if value is not None: enum_value = int(value) enum_mem.attrib["value"] = "%d" % enum_value enum_value = enum_value + 1 if comment is not None: enum_mem.attrib["description"] = comment enum_elem.append(enum_mem) enum_list.append(enum_elem) else: type_name = channel_type if channel_type == "string": channel_elem.attrib["len"] = chan.get_size() (lr, lo, ly, hy, ho, hr) = chan.get_limits() if lr is not None: channel_elem.attrib["low_red"] = lr if lo is not None: channel_elem.attrib["low_orange"] = lo if ly is not None: channel_elem.attrib["low_yellow"] = ly if hy is not None: channel_elem.attrib["high_yellow"] = hy if ho is not None: channel_elem.attrib["high_orange"] = ho if hr is not None: channel_elem.attrib["high_red"] = hr channel_elem.attrib["type"] = type_name telemetry_list.append(channel_elem) # check for events if parsed_xml_dict[comp_type].get_events() is not None: for event in parsed_xml_dict[comp_type].get_events(): PRINT.debug("Processing Event %s" % event.get_name()) event_elem = etree.Element("event") event_elem.attrib["component"] = comp_name event_elem.attrib["name"] = event.get_name() event_elem.attrib["id"] = "%s" % ( hex(int(event.get_ids()[0], base=0) + comp_id) ) event_elem.attrib["severity"] = event.get_severity() format_string = event.get_format_string() if "comment" in list(event_elem.attrib.keys()): event_elem.attrib["description"] = event_elem.attrib[ "comment" ] args_elem = etree.Element("args") arg_num = 0 for arg in event.get_args(): arg_elem = etree.Element("arg") arg_elem.attrib["name"] = arg.get_name() arg_type = arg.get_type() if isinstance(arg_type, tuple): enum_value = 0 type_name = "{}::{}::{}".format( comp_type, arg.get_name(), arg_type[0][1], ) # Add enum entry enum_elem = etree.Element("enum") enum_elem.attrib["type"] = type_name # Add enum members for (membername, value, comment) in arg_type[1]: enum_mem = etree.Element("item") enum_mem.attrib["name"] = membername # keep track of incrementing enum value if value is not None: enum_value = int(value) enum_mem.attrib["value"] = "%d" % enum_value enum_value = enum_value + 1 if comment is not None: enum_mem.attrib["description"] = comment enum_elem.append(enum_mem) enum_list.append(enum_elem) # replace enum format string %d with %s for ground system format_string = DictTypeConverter.DictTypeConverter().format_replace( format_string, arg_num, "d", "s" ) else: type_name = arg_type if arg_type == "string": arg_elem.attrib["len"] = arg.get_size() arg_elem.attrib["type"] = type_name args_elem.append(arg_elem) arg_num += 1 event_elem.attrib["format_string"] = format_string event_elem.append(args_elem) event_list.append(event_elem) # check for parameters if parsed_xml_dict[comp_type].get_parameters() is not None: for parameter in parsed_xml_dict[comp_type].get_parameters(): PRINT.debug("Processing Parameter %s" % chan.get_name()) param_default = None command_elem_set = etree.Element("command") command_elem_set.attrib["component"] = comp_name command_elem_set.attrib["mnemonic"] = ( parameter.get_name() + "_PRM_SET" ) command_elem_set.attrib["opcode"] = "%s" % ( hex(int(parameter.get_set_opcodes()[0], base=0) + comp_id) ) if "comment" in list(command_elem.attrib.keys()): command_elem_set.attrib["description"] = ( command_elem_set.attrib["comment"] + " parameter set" ) else: command_elem_set.attrib["description"] = ( parameter.get_name() + " parameter set" ) args_elem = etree.Element("args") arg_elem = etree.Element("arg") arg_elem.attrib["name"] = "val" arg_type = parameter.get_type() if isinstance(arg_type, tuple): enum_value = 0 type_name = "{}::{}::{}".format( comp_type, arg.get_name(), arg_type[0][1], ) # Add enum entry enum_elem = etree.Element("enum") enum_elem.attrib["type"] = type_name # Add enum members for (membername, value, comment) in arg_type[1]: enum_mem = etree.Element("item") enum_mem.attrib["name"] = membername # keep track of incrementing enum value if value is not None: enum_value = int(value) enum_mem.attrib["value"] = "%d" % enum_value enum_value = enum_value + 1 if comment is not None: enum_mem.attrib["description"] = comment enum_elem.append(enum_mem) # assign default to be first enum member if param_default is None: param_default = membername enum_list.append(enum_elem) else: type_name = arg_type if arg_type == "string": arg_elem.attrib["len"] = arg.get_size() else: param_default = "0" arg_elem.attrib["type"] = type_name args_elem.append(arg_elem) command_elem_set.append(args_elem) command_list.append(command_elem_set) command_elem_save = etree.Element("command") command_elem_save.attrib["component"] = comp_name command_elem_save.attrib["mnemonic"] = ( parameter.get_name() + "_PRM_SAVE" ) command_elem_save.attrib["opcode"] = "%s" % ( hex(int(parameter.get_save_opcodes()[0], base=0) + comp_id) ) if "comment" in list(command_elem.attrib.keys()): command_elem_save.attrib["description"] = ( command_elem_set.attrib["comment"] + " parameter set" ) else: command_elem_save.attrib["description"] = ( parameter.get_name() + " parameter save" ) command_list.append(command_elem_save) param_elem = etree.Element("parameter") param_elem.attrib["component"] = comp_name param_elem.attrib["name"] = parameter.get_name() param_elem.attrib["id"] = "%s" % ( hex(int(parameter.get_ids()[0], base=0) + comp_id) ) if parameter.get_default() is not None: param_default = parameter.get_default() param_elem.attrib["default"] = param_default parameter_list.append(param_elem) # Check for arrays if parsed_xml_dict[comp_type].get_array_type_files() is not None: array_file_list = parsed_xml_dict[comp_type].get_array_type_files() for array_file in array_file_list: array_file = search_for_file("Array", array_file) array_model = XmlArrayParser.XmlArrayParser(array_file) array_elem = etree.Element("array") array_name = ( array_model.get_namespace() + "::" + array_model.get_name() ) array_elem.attrib["name"] = array_name array_type = array_model.get_type() array_elem.attrib["type"] = array_type array_type_id = array_model.get_type_id() array_elem.attrib["type_id"] = array_type_id array_size = array_model.get_size() array_elem.attrib["size"] = array_size array_format = array_model.get_format() array_elem.attrib["format"] = array_format members_elem = etree.Element("defaults") for d_val in array_model.get_default(): member_elem = etree.Element("default") member_elem.attrib["value"] = d_val members_elem.append(member_elem) array_elem.append(members_elem) array_list.append(array_elem) topology_dict.append(enum_list) topology_dict.append(serializable_list) topology_dict.append(array_list) topology_dict.append(command_list) topology_dict.append(event_list) topology_dict.append(telemetry_list) topology_dict.append(parameter_list) fileName = the_parsed_topology_xml.get_xml_filename().replace( "Ai.xml", "Dictionary.xml" ) PRINT.info("Generating XML dictionary %s" % fileName) fd = open( fileName, "wb" ) # Note: binary forces the same encoding of the source files fd.write(etree.tostring(topology_dict, pretty_print=True)) initFiles = generator.create("initFiles") # startSource = generator.create("startSource") includes1 = generator.create("includes1") # includes2 = generator.create("includes2") # namespace = generator.create("namespace") public = generator.create("public") finishSource = generator.create("finishSource") # # Generate the source code products here. # # 1. Open all the files initFiles(topology_model) # # 2. Generate includes and static code here. includes1(topology_model) # # 3. Generate public function to instance components and connect them here. public(topology_model) # # 4. Generate final code here and close all files. finishSource(topology_model) return topology_model def generate_component_instance_dictionary( the_parsed_component_xml, opt, topology_model ): global DEPLOYMENT # parsed_port_xml_list = [] parsed_serializable_xml_list = [] # uses the topology model to process the items # checks if the topology model exists if topology_model is None: PRINT.info( "Topology model was not specified. Please also input a topology model when running this command." ) raise OSError port_type_files_list = the_parsed_component_xml.get_port_type_files() for port_file in port_type_files_list: port_file = search_for_file("Port", port_file) xml_parser_obj = XmlPortsParser.XmlPortsParser(port_file) # print xml_parser_obj.get_args() parsed_port_xml_list.append(xml_parser_obj) del xml_parser_obj serializable_type_files_list = ( the_parsed_component_xml.get_serializable_type_files() ) for serializable_file in serializable_type_files_list: serializable_file = search_for_file("Serializable", serializable_file) xml_parser_obj = XmlSerializeParser.XmlSerializeParser( serializable_file ) # Telemetry/Params can only use generated serializable types # check to make sure that the serializables don't have things that channels and parameters can't have # can't have external non-xml members if len(xml_parser_obj.get_include_header_files()): PRINT.info( "ERROR: Component include serializables cannot use user-defined types. file: " % serializable_file ) sys.exit(-1) # print xml_parser_obj.get_args() parsed_serializable_xml_list.append(xml_parser_obj) del xml_parser_obj generator = CompFactory.CompFactory.getInstance() component_model = generator.create( the_parsed_component_xml, parsed_port_xml_list, parsed_serializable_xml_list ) if opt.default_topology_dict: default_dict_generator = GenFactory.GenFactory.getInstance() # iterate through command instances default_dict_generator.configureVisitor( "Commands", "InstanceCommandVisitor", True, True ) for command_model in component_model.get_commands(): DEBUG.info("Processing command %s" % command_model.get_mnemonic()) defaultStartCmd = default_dict_generator.create("InstanceDictStart") defaultCmdHeader = default_dict_generator.create("InstanceDictHeader") defaultCmdBody = default_dict_generator.create("InstanceDictBody") defaultStartCmd(command_model, topology_model) defaultCmdHeader(command_model, topology_model) defaultCmdBody(command_model, topology_model) for parameter_model in component_model.get_parameters(): DEBUG.info("Processing parameter %s" % parameter_model.get_name()) defaultStartCmd = default_dict_generator.create("InstanceDictStart") defaultCmdHeader = default_dict_generator.create("InstanceDictHeader") defaultCmdBody = default_dict_generator.create("InstanceDictBody") defaultStartCmd(parameter_model, topology_model) defaultCmdHeader(parameter_model, topology_model) defaultCmdBody(parameter_model, topology_model) default_dict_generator = GenFactory.GenFactory.getInstance() # iterate through command instances default_dict_generator.configureVisitor( "Events", "InstanceEventVisitor", True, True ) for event_model in component_model.get_events(): DEBUG.info("Processing event %s" % event_model.get_name()) defaultStartEvent = default_dict_generator.create("InstanceDictStart") defaultEventHeader = default_dict_generator.create("InstanceDictHeader") defaultEventBody = default_dict_generator.create("InstanceDictBody") defaultStartEvent(event_model, topology_model) defaultEventHeader(event_model, topology_model) defaultEventBody(event_model, topology_model) default_dict_generator = GenFactory.GenFactory.getInstance() # iterate through command instances default_dict_generator.configureVisitor( "Channels", "InstanceChannelVisitor", True, True ) for channel_model in component_model.get_channels(): DEBUG.info("Processing channel %s" % channel_model.get_name()) defaultStartChannel = default_dict_generator.create("InstanceDictStart") defaultChannelHeader = default_dict_generator.create("InstanceDictHeader") defaultChannelBody = default_dict_generator.create("InstanceDictBody") defaultStartChannel(channel_model, topology_model) defaultChannelHeader(channel_model, topology_model) defaultChannelBody(channel_model, topology_model) def generate_component( the_parsed_component_xml, xml_filename, opt, topology_model=None ): """ Creates a component meta-model, configures visitors and generates the component files. Nothing is returned. """ parsed_port_xml_list = [] if opt.gen_report: report_file = open("%sReport.txt" % xml_filename.replace("Ai.xml", ""), "w") num_input_ports = 0 num_output_ports = 0 # Count ports for port in the_parsed_component_xml.get_ports(): if port.get_direction() == "input": num_input_ports = num_input_ports + int(port.get_max_number()) if port.get_direction() == "output": num_output_ports = num_output_ports + int(port.get_max_number()) if len(the_parsed_component_xml.get_ports()): if num_input_ports: report_file.write("Input Ports: %d\n" % num_input_ports) if num_output_ports: report_file.write("Output Ports: %d\n" % num_output_ports) # Count regular commands commands = 0 idList = "" if len(the_parsed_component_xml.get_commands()): for command in the_parsed_component_xml.get_commands(): commands += len(command.get_opcodes()) for opcode in command.get_opcodes(): idList += opcode + "," # Count parameter commands if len(the_parsed_component_xml.get_parameters()): for parameter in the_parsed_component_xml.get_parameters(): commands += len(parameter.get_set_opcodes()) for opcode in parameter.get_set_opcodes(): idList += opcode + "," commands += len(parameter.get_save_opcodes()) for opcode in parameter.get_save_opcodes(): idList += opcode + "," if commands > 0: report_file.write("Commands: %d\n OpCodes: %s\n" % (commands, idList[:-1])) if len(the_parsed_component_xml.get_channels()): idList = "" channels = 0 for channel in the_parsed_component_xml.get_channels(): channels += len(channel.get_ids()) for id in channel.get_ids(): idList += id + "," report_file.write("Channels: %d\n ChanIds: %s\n" % (channels, idList[:-1])) if len(the_parsed_component_xml.get_events()): idList = "" events = 0 for event in the_parsed_component_xml.get_events(): events += len(event.get_ids()) for id in event.get_ids(): idList += id + "," report_file.write("Events: %d\n EventIds: %s\n" % (events, idList[:-1])) if len(the_parsed_component_xml.get_parameters()): idList = "" parameters = 0 for parameter in the_parsed_component_xml.get_parameters(): parameters += len(parameter.get_ids()) for id in parameter.get_ids(): idList += id + "," report_file.write( "Parameters: %d\n ParamIds: %s\n" % (parameters, idList[:-1]) ) # # Configure the meta-model for the component # port_type_files_list = the_parsed_component_xml.get_port_type_files() for port_file in port_type_files_list: port_file = search_for_file("Port", port_file) xml_parser_obj = XmlPortsParser.XmlPortsParser(port_file) # print xml_parser_obj.get_args() parsed_port_xml_list.append(xml_parser_obj) del xml_parser_obj parsed_serializable_xml_list = [] # # Configure the meta-model for the component # serializable_type_files_list = ( the_parsed_component_xml.get_serializable_type_files() ) for serializable_file in serializable_type_files_list: serializable_file = search_for_file("Serializable", serializable_file) xml_parser_obj = XmlSerializeParser.XmlSerializeParser( serializable_file ) # Telemetry/Params can only use generated serializable types # check to make sure that the serializables don't have things that channels and parameters can't have # can't have external non-xml members if len(xml_parser_obj.get_include_header_files()): PRINT.info( "ERROR: Component include serializables cannot use user-defined types. file: " % serializable_file ) sys.exit(-1) # print xml_parser_obj.get_args() parsed_serializable_xml_list.append(xml_parser_obj) del xml_parser_obj # # for p in the_parsed_component_xml.get_ports(): # print p.get_name(), p.get_type() # print parsed_port_xml_list # for p in parsed_port_xml_list: # print p.get_interface().get_name(), p.get_interface().get_namespace() # print p.get_args() # print p.get_include_header_files() # generator = CompFactory.CompFactory.getInstance() component_model = generator.create( the_parsed_component_xml, parsed_port_xml_list, parsed_serializable_xml_list ) # tv = [x for x in component_model.get_events()] # for event_model in component_model.get_events(): # event_model.set_ids([1,2,3]) # tv.append(event_model) # # Configure and create the visitors that will generate the code. # generator = GenFactory.GenFactory.getInstance() # # Configure each visitor here. # if "Ai" in xml_filename: base = xml_filename.split("Ai")[0] h_instance_name = base + "_H" cpp_instance_name = base + "_Cpp" h_instance_name_tmpl = base + "_Impl_H" cpp_instance_name_tmpl = base + "_Impl_Cpp" h_instance_test_name = base + "_Test_H" cpp_instance_test_name = base + "_Test_Cpp" h_instance_gtest_name = base + "_GTest_H" cpp_instance_gtest_name = base + "_GTest_Cpp" h_instance_test_impl_name = base + "_TestImpl_H" cpp_instance_test_impl_name = base + "_TestImpl_Cpp" else: PRINT.info("Missing Ai at end of file name...") raise OSError # if opt.impl_flag: PRINT.info("Enabled generation of implementation template files...") generator.configureVisitor(h_instance_name_tmpl, "ImplHVisitor", True, True) generator.configureVisitor(cpp_instance_name_tmpl, "ImplCppVisitor", True, True) elif opt.unit_test: PRINT.info("Enabled generation of unit test component files...") generator.configureVisitor( h_instance_test_name, "ComponentTestHVisitor", True, True ) generator.configureVisitor( cpp_instance_test_name, "ComponentTestCppVisitor", True, True ) generator.configureVisitor(h_instance_gtest_name, "GTestHVisitor", True, True) generator.configureVisitor( cpp_instance_gtest_name, "GTestCppVisitor", True, True ) generator.configureVisitor( h_instance_test_impl_name, "TestImplHVisitor", True, True ) generator.configureVisitor( cpp_instance_test_impl_name, "TestImplCppVisitor", True, True ) else: generator.configureVisitor(h_instance_name, "ComponentHVisitor", True, True) generator.configureVisitor(cpp_instance_name, "ComponentCppVisitor", True, True) # for port_file in port_type_files_list: # if "Ai" in port_file: # base = port_file.split("Ai")[0] # h_instance_name = base + "_H" # cpp_instance_name = base + "_Cpp" # else: # PRINT.info("Missing Ai at end of file: %s" % port_file) # raise IOError # generator.configureVisitor(h_instance_name, "PortCppVisitor", True, True) # generator.configureVisitor(cpp_instance_name, "PortHVisitor", True, True) # # The idea here is that each of these generators is used to create # a certain portion of each output file. # initFiles = generator.create("initFiles") startSource = generator.create("startSource") includes1 = generator.create("includes1") includes2 = generator.create("includes2") namespace = generator.create("namespace") public = generator.create("public") protected = generator.create("protected") private = generator.create("private") finishSource = generator.create("finishSource") # # Generate the source code products here. # # 1. Open all the files initFiles(component_model) # # 2. Produce caltech notice here and other starting stuff. startSource(component_model) # # 3. Generate includes that all files get here. includes1(component_model) # # 4. Generate includes from model that a specific here. includes2(component_model) # # 5. Generate start of namespace here. namespace(component_model) # # 6. Generate public class code here. public(component_model) # # 7. Generate protected class code here. protected(component_model) # # 8. Generate private class code here. private(component_model) # # 9. Generate final code here and close all files. finishSource(component_model) # # if requested, generate ground system dictionary if opt.default_dict: if opt.dict_dir is None: PRINT.info("Dictionary output directory not specified!") raise OSError os.environ["DICT_DIR"] = opt.dict_dir default_dict_generator = GenFactory.GenFactory.getInstance() # iterate through command instances default_dict_generator.configureVisitor( "Commands", "CommandVisitor", True, True ) for command_model in component_model.get_commands(): DEBUG.info("Processing command %s" % command_model.get_mnemonic()) defaultStartCmd = default_dict_generator.create("DictStart") defaultCmdHeader = default_dict_generator.create("DictHeader") defaultCmdBody = default_dict_generator.create("DictBody") defaultStartCmd(command_model) defaultCmdHeader(command_model) defaultCmdBody(command_model) for parameter_model in component_model.get_parameters(): DEBUG.info("Processing parameter %s" % parameter_model.get_name()) defaultStartCmd = default_dict_generator.create("DictStart") defaultCmdHeader = default_dict_generator.create("DictHeader") defaultCmdBody = default_dict_generator.create("DictBody") defaultStartCmd(parameter_model) defaultCmdHeader(parameter_model) defaultCmdBody(parameter_model) default_dict_generator = GenFactory.GenFactory.getInstance() # iterate through command instances default_dict_generator.configureVisitor("Events", "EventVisitor", True, True) for event_model in component_model.get_events(): DEBUG.info("Processing event %s" % event_model.get_name()) defaultStartEvent = default_dict_generator.create("DictStart") defaultEventHeader = default_dict_generator.create("DictHeader") defaultEventBody = default_dict_generator.create("DictBody") defaultStartEvent(event_model) defaultEventHeader(event_model) defaultEventBody(event_model) default_dict_generator = GenFactory.GenFactory.getInstance() # iterate through command instances default_dict_generator.configureVisitor( "Channels", "ChannelVisitor", True, True ) for channel_model in component_model.get_channels(): DEBUG.info("Processing channel %s" % channel_model.get_name()) defaultStartChannel = default_dict_generator.create("DictStart") defaultChannelHeader = default_dict_generator.create("DictHeader") defaultChannelBody = default_dict_generator.create("DictBody") defaultStartChannel(channel_model) defaultChannelHeader(channel_model) defaultChannelBody(channel_model) if opt.html_docs: if opt.html_doc_dir is None: PRINT.info("HTML documentation output directory not specified!") raise OSError os.environ["HTML_DOC_SUBDIR"] = opt.html_doc_dir html_doc_generator = GenFactory.GenFactory.getInstance() html_doc_generator.configureVisitor( base + "_Html", "HtmlDocVisitor", True, True ) htmlStart = html_doc_generator.create("HtmlStart") htmlDoc = html_doc_generator.create("HtmlDoc") finisher = html_doc_generator.create("finishSource") htmlStart(component_model) htmlDoc(component_model) finisher(component_model) if opt.md_docs: if opt.md_doc_dir is None: PRINT.info("MD documentation output directory not specified!") raise OSError os.environ["MD_DOC_SUBDIR"] = opt.md_doc_dir md_doc_generator = GenFactory.GenFactory.getInstance() md_doc_generator.configureVisitor(base + "_Md", "MdDocVisitor", True, True) mdStart = md_doc_generator.create("MdStart") mdDoc = md_doc_generator.create("MdDoc") finisher = md_doc_generator.create("finishSource") mdStart(component_model) mdDoc(component_model) finisher(component_model) def generate_port(the_parsed_port_xml, port_file): """ Creates a port meta-model, configures visitors and generates the port/interface type files. Nothing is returned. """ # # Configure the meta-model for the component # DEBUG.debug("Port xml type description file: %s" % port_file) generator = PortFactory.PortFactory.getInstance() port_model = generator.create(the_parsed_port_xml) # # Configure and create the visitors that will generate the code. # generator = GenFactory.GenFactory.getInstance() # # Configure file names and each visitor here. # type = the_parsed_port_xml.get_interface().get_name() # # Configure each visitor here. # if "Ai" in port_file: base = type h_instance_name = base + "_H" cpp_instance_name = base + "_Cpp" else: PRINT.info("Missing Ai at end of file name...") raise OSError # generator.configureVisitor(h_instance_name, "PortCppVisitor", True, True) generator.configureVisitor(cpp_instance_name, "PortHVisitor", True, True) # # The idea here is that each of these generators is used to create # a certain portion of each output file. # initFiles = generator.create("initFiles") startSource = generator.create("startSource") includes1 = generator.create("includes1") includes2 = generator.create("includes2") namespace = generator.create("namespace") public = generator.create("public") protected = generator.create("protected") private = generator.create("private") finishSource = generator.create("finishSource") # # Generate the source code products here. # # 1. Open all the files initFiles(port_model) # # 2. Produce caltech notice here and other starting stuff. startSource(port_model) # # 3. Generate includes that all files get here. includes1(port_model) # # 4. Generate includes from model that a specific here. includes2(port_model) # # 5. Generate start of namespace here. namespace(port_model) # # 6. Generate public class code here. public(port_model) # # 7. Generate protected class code here. protected(port_model) # # 8. Generate private class code here. private(port_model) # # 9. Generate final code here and close all files. finishSource(port_model) def generate_serializable(the_serial_xml, opt): """ Creates a serializable meta-model class, configures visitors and generates the serializable class files. Nothing is returned. """ # # Configure the meta-model for the serializable here # f = the_serial_xml.get_xml_filename() DEBUG.debug("Serializable xml type description file: %s" % f) n = the_serial_xml.get_name() ns = the_serial_xml.get_namespace() c = the_serial_xml.get_comment() i = ( the_serial_xml.get_includes() + the_serial_xml.get_include_enums() + the_serial_xml.get_include_arrays() ) i2 = the_serial_xml.get_include_header_files() m = the_serial_xml.get_members() t = the_serial_xml.get_typeid() model = Serialize.Serialize(f, n, ns, c, i, i2, m, t) # # Configure each visitor here. # t = f.split(".")[0][-2:] if ("Ai" in f) & (t == "Ai"): base = n h_instance_name = base + "_H" cpp_instance_name = base + "_Cpp" else: PRINT.info("Missing Ai at end of file name...") raise OSError # generator = GenFactory.GenFactory.getInstance() generator.configureVisitor(h_instance_name, "SerialCppVisitor", True, True) generator.configureVisitor(cpp_instance_name, "SerialHVisitor", True, True) # only generate if serializable is usable for dictionary. Can't have includes of other types if opt.default_dict: if len(i) != 0 or len(i2) != 0: PRINT.info("Dictionary: Skipping %s because of external includes" % (f)) else: # borrow source visitor pattern for serializable dictionary if opt.dict_dir is None: PRINT.info("Dictionary output directory not specified!") raise OSError os.environ["DICT_DIR"] = opt.dict_dir generator.configureVisitor("SerialDict", "SerializableVisitor", True, True) if opt.default_topology_dict: if len(i) != 0 or len(i2) != 0: PRINT.info("Dictionary: Skipping %s because of external includes" % (f)) else: # borrow source visitor pattern for serializable dictionary if opt.dict_dir is None: PRINT.info("Dictionary output directory not specified!") raise OSError os.environ["DICT_DIR"] = opt.dict_dir print("\n") print(opt.dict_dir) print("\n") generator.configureVisitor( "SerialDict", "InstanceSerializableVisitor", True, True ) # # The idea here is that each of these generators is used to create # a certain portion of each output file. # initFiles = generator.create("initFiles") startSource = generator.create("startSource") includes1 = generator.create("includes1") includes2 = generator.create("includes2") namespace = generator.create("namespace") public = generator.create("public") protected = generator.create("protected") private = generator.create("private") finishSource = generator.create("finishSource") # # Generate the source code products here. # # 1. Open all the files initFiles(model) # # 2. Produce caltech notice here and other starting stuff. startSource(model) # # 3. Generate includes that all files get here. includes1(model) # # 4. Generate includes from model that a specific here. includes2(model) # # 5. Generate start of namespace here. namespace(model) # # 6. Generate public class code here. public(model) # # 7. Generate protected class code here. protected(model) # # 8. Generate private class code here. private(model) # # 9. Generate final code here and close all files. finishSource(model) def generate_dependency_file(filename, target_file, subst_path, parser, type): # verify directory exists for dependency file and is directory if not os.path.isdir(os.path.dirname(filename)): PRINT.info( "ERROR: Dependency file path %s does not exist!", os.path.dirname(filename) ) sys.exit(-1) # open dependency file dep_file = open(filename, "w") # get working directory and normalize path target_directory = os.getcwd().replace("\\", "/") target_file_local = target_file.replace("\\", "/").replace("Ai.xml", "Ac.cpp") subst_path_local = subst_path.replace("\\", "/") # normalize path to target file full_path = os.path.abspath(target_directory + "/" + target_file_local).replace( "\\", "/" ) # if path to substitute is specified, replace with build root if subst_path_local is not None: full_path = full_path.replace(subst_path_local, "$(BUILD_ROOT)") # print("sub: %s\ndep_file: %s\ntdir: %s\ntfile: %s\nfp: %s"%(subst_path_local,filename,target_directory,target_file_local,full_path)) # write target to file dep_file.write("%s:" % full_path) # assemble list of files if type == "interface": file_list = ( parser.get_include_header_files() + parser.get_includes_serial_files() + parser.get_include_enum_files() + parser.get_include_array_files() ) elif type == "component": file_list = ( parser.get_port_type_files() + parser.get_header_files() + parser.get_serializable_type_files() + parser.get_imported_dictionary_files() + parser.get_enum_type_files() + parser.get_array_type_files() ) elif type == "serializable": file_list = ( parser.get_include_header_files() + parser.get_includes() + parser.get_include_enums() + parser.get_include_arrays() ) elif type == "assembly" or type == "deployment": # get list of dependency files from XML/header file list file_list_tmp = list(parser.get_comp_type_file_header_dict().keys()) file_list = file_list_tmp # file_list = list() # for f in file_list_tmp: # file_list.append(f.replace("Ai.xml","Ac.hpp")) else: PRINT.info("ERROR: Unrecognized dependency type %s!", type) sys.exit(-1) # write dependencies for include in file_list: # print("include %s\n"%include) if subst_path_local is not None: full_path = "$(BUILD_ROOT)/" + include.replace("\\", "/") else: PRINT.info( "ERROR: No build root to attach. Not sure how to generate dependency." ) sys.exit(-1) dep_file.write("\\\n %s " % full_path) # carriage return dep_file.write("\n\n") # close file dep_file.close() def main(): """ Main program. """ global ERROR # prevent local creation of variable global VERBOSE # prevent local creation of variable global GEN_TEST_CODE # indicate if test code should be generated global DEPLOYMENT # deployment set in topology xml only and used to install new instance dicts ERROR = False # Sets up the initial (singleton) instance ConfigManager.ConfigManager.getInstance() Parser = pinit() (opt, args) = Parser.parse_args() VERBOSE = opt.verbose_flag # Check that the specified working directory exists. Remember, the # default working directory is the current working directory which # always exists. We are basically only checking for when the user # specifies an alternate working directory. if os.path.exists(opt.work_path) == False: Parser.error("Specified path does not exist (%s)!" % opt.work_path) working_dir = opt.work_path # Get the current working directory so that we can return to it when # the program completes. We always want to return to the place where # we started. starting_directory = os.getcwd() os.chdir(working_dir) # print working_dir # print os.getcwd() # Configure the logging. log_level = opt.logger.upper() log_level_dict = dict() log_level_dict["QUIET"] = None log_level_dict["DEBUG"] = logging.DEBUG log_level_dict["INFO"] = logging.INFO log_level_dict["WARNING"] = logging.WARN log_level_dict["ERROR"] = logging.ERROR log_level_dict["CRITICAL"] = logging.CRITICAL if log_level_dict[log_level] is None: stdout_enable = False else: stdout_enable = True log_fd = opt.logger_output # For now no log file Logger.connectDebugLogger(log_level_dict[log_level], log_fd, stdout_enable) Logger.connectOutputLogger(log_fd) # # Parse the input Component XML file and create internal meta-model # if len(args) == 0: PRINT.info("Usage: %s [options] xml_filename" % sys.argv[0]) return else: xml_filenames = args[0:] # # Check for BUILD_ROOT variable for XML port searches # if opt.build_root_flag == True: # Check for BUILD_ROOT env. variable if ("BUILD_ROOT" in list(os.environ.keys())) == False: PRINT.info( "ERROR: The -b command option requires that BUILD_ROOT environmental variable be set to root build path..." ) sys.exit(-1) else: set_build_roots(os.environ.get("BUILD_ROOT")) for xml_filename in xml_filenames: xml_filename = os.path.basename(xml_filename) xml_type = XmlParser.XmlParser(xml_filename)() if xml_type == "component": DEBUG.info("Detected Component XML so Generating Component C++ Files...") the_parsed_component_xml = XmlComponentParser.XmlComponentParser( xml_filename ) generate_component(the_parsed_component_xml, xml_filename, opt) dependency_parser = the_parsed_component_xml elif xml_type == "interface": DEBUG.info("Detected Port type XML so Generating Port type C++ Files...") the_parsed_port_xml = XmlPortsParser.XmlPortsParser(xml_filename) generate_port(the_parsed_port_xml, xml_filename) dependency_parser = the_parsed_port_xml elif xml_type == "serializable": DEBUG.info( "Detected Serializable XML so Generating Serializable C++ Files..." ) the_serial_xml = XmlSerializeParser.XmlSerializeParser(xml_filename) generate_serializable(the_serial_xml, opt) dependency_parser = the_serial_xml elif xml_type == "assembly" or xml_type == "deployment": DEBUG.info("Detected Topology XML so Generating Topology C++ Files...") the_parsed_topology_xml = XmlTopologyParser.XmlTopologyParser(xml_filename) DEPLOYMENT = the_parsed_topology_xml.get_deployment() print("Found assembly or deployment named: %s\n" % DEPLOYMENT) generate_topology(the_parsed_topology_xml, xml_filename, opt) dependency_parser = the_parsed_topology_xml elif xml_type == "enum": DEBUG.info("Detected Enum XML so Generating hpp, cpp, and py files...") curdir = os.getcwd() if EnumGenerator.generate_enum(xml_filename): ERROR = False PRINT.info( "Completed generating files for %s Enum XML...." % xml_filename ) else: ERROR = True os.chdir(curdir) elif xml_type == "array": DEBUG.info("Detected Array XML so Generating hpp, cpp, and py files...") curdir = os.getcwd() if ArrayGenerator.generate_array(xml_filename): ERROR = False PRINT.info( "Completed generating files for %s Array XML..." % xml_filename ) else: ERROR = True os.chdir(curdir) else: PRINT.info("Invalid XML found...this format not supported") ERROR = True if opt.dependency_file is not None: if opt.build_root_flag: generate_dependency_file( opt.dependency_file, xml_filename, list(get_build_roots())[0], dependency_parser, xml_type, ) # Always return to directory where we started. os.chdir(starting_directory) if ERROR == True: sys.exit(-1) else: sys.exit(0) if __name__ == "__main__": try: main() except Exception as exc: print(exc, file=sys.stderr) traceback.print_exc(file=sys.stdout) sys.exit(-1)