예제 #1
0
파일: prj.py 프로젝트: GaloisInc/echronos
    def _configure_from_xml(self, dom):
        """Configure a module based on XML input. This may be XML that was
        extracted from a marked-up comment, or directly in an XML file.

        """
        cg_el = maybe_single_named_child(dom, 'code_gen')
        if cg_el:
            code_gen = single_text_child(cg_el)
            if code_gen not in ['template']:
                raise SystemParseError(xml_error_str(cg_el, "not a supported code_gen type: %s" % code_gen))
            self.code_gen = code_gen

        # Get all headers
        hdr_els = maybe_get_element_list(dom, "headers", "header")
        if hdr_els is None:
            hdr_els = []

        def fix_path(hdr):
            if os.path.isabs(hdr):
                return hdr
            else:
                return os.path.join(os.path.dirname(self.filename), hdr)

        for hdr_el in hdr_els:
            code_gen = hdr_el.getAttributeNode('code_gen')
            code_gen = code_gen.value if code_gen is not None else None
            if code_gen not in [None, 'template']:
                raise SystemParseError(xml_error_str(hdr_el, "not a supported code_gen type: %s" % code_gen))
            self.headers.append(Header(fix_path(get_attribute(hdr_el, "path")), code_gen, hdr_el))

        schema = maybe_single_named_child(dom, 'schema')
        self.schema = xml2schema(schema) if schema else None
예제 #2
0
    def _configure_from_xml(self, dom):
        """Configure a module based on XML input. This may be XML that was
        extracted from a marked-up comment, or directly in an XML file.

        """
        cg_el = maybe_single_named_child(dom, 'code_gen')
        if cg_el:
            code_gen = single_text_child(cg_el)
            if code_gen not in ['template']:
                raise SystemParseError(xml_error_str(cg_el, "not a supported code_gen type: %s" % code_gen))
            self.code_gen = code_gen

        # Get all headers
        hdr_els = maybe_get_element_list(dom, "headers", "header")
        if hdr_els is None:
            hdr_els = []

        def fix_path(hdr):
            if os.path.isabs(hdr):
                return hdr
            return os.path.join(os.path.dirname(self.filename), hdr)

        for hdr_el in hdr_els:
            code_gen = hdr_el.getAttributeNode('code_gen')
            code_gen = code_gen.value if code_gen is not None else None
            if code_gen not in [None, 'template']:
                raise SystemParseError(xml_error_str(hdr_el, "not a supported code_gen type: %s" % code_gen))
            self.headers.append(Header(fix_path(get_attribute(hdr_el, "path")), code_gen, hdr_el))

        schema = maybe_single_named_child(dom, 'schema')
        self.schema = xml2schema(schema) if schema else None
예제 #3
0
    def prepare(self, system, config, *, copy_all_files=False):
        """prepare the `system` for building based on the specific config.

        This includes copying any header files to the correct locations, and running any templating.
        All modules are only prepared after validation of all modules has occurred.
        Compilation does not occur until all modules are prepared.

        This is currently only stubbed.

        """
        if self.code_gen is None:
            if copy_all_files:
                path = os.path.join(system.output,
                                    os.path.basename(self.filename))
                shutil.copyfile(self.filename, path)
                logger.info("Preparing: copy %s -> %s", self.filename, path)
                system.add_file(path)
            else:
                system.add_file(self.filename)

        elif self.code_gen == 'template':
            # Create implementation file.
            ext = os.path.splitext(self.filename)[1]
            path = os.path.join(
                system.output, '{}{}'.format(os.path.basename(self.name), ext))
            logger.info("Preparing: template %s -> %s (%s)", self.filename,
                        path, config)
            pystache_render(self.filename, path, config)
            system.add_file(path)

        # Copy any headers across. This should use templating if that is configured.
        for header in self.headers:
            path = os.path.join(system.output, os.path.basename(header.path))
            try:
                if header.code_gen is None:
                    shutil.copyfile(header.path, path)
                elif header.code_gen == 'template':
                    logger.info("Preparing: template %s -> %s (%s)",
                                header.path, path, config)
                    pystache_render(header.path, path, config)
            except FileNotFoundError as e:
                s = xml_error_str(header.xml_element,
                                  "Resource not found: {}".format(header.path))
                raise ResourceNotFoundError(s)
예제 #4
0
    def prepare(self, system, config, *, copy_all_files=False):  # pylint: disable=arguments-differ
        """prepare the `system` for building based on the specific config.

        This includes copying any header files to the correct locations, and running any templating.
        All modules are only prepared after validation of all modules has occurred.
        Compilation does not occur until all modules are prepared.

        This is currently only stubbed.

        """
        if self.code_gen is None:
            if copy_all_files:
                path = system.get_output_path_for_file(self.filename, self.name)
                os.makedirs(os.path.dirname(path), exist_ok=True)
                shutil.copyfile(self.filename, path)
                logger.info("Preparing: copy %s -> %s", self.filename, path)
                system.add_file(path)
            else:
                system.add_file(self.filename)

        elif self.code_gen == 'template':
            # Create implementation file.
            path = system.get_output_path_for_file(self.filename, self.name)
            logger.info("Preparing: template %s -> %s (%s)", self.filename, path, config)
            pystache_render(self.filename, path, config)
            system.add_file(path)

        # Copy any headers across. This should use templating if that is configured.
        for header in self.headers:
            path = system.get_output_path_for_file(header.path, self.name)
            os.makedirs(os.path.dirname(path), exist_ok=True)
            try:
                if header.code_gen is None:
                    shutil.copyfile(header.path, path)
                elif header.code_gen == 'template':
                    logger.info("Preparing: template %s -> %s (%s)", header.path, path, config)
                    pystache_render(header.path, path, config)
                system.add_include_path(os.path.dirname(path))
            except FileNotFoundError:
                error_str = xml_error_str(header.xml_element, "Resource not found: {}".format(header.path))
                raise ResourceNotFoundError(error_str)
예제 #5
0
파일: prj.py 프로젝트: GaloisInc/echronos
    def prepare(self, system, config, *, copy_all_files=False):
        """prepare the `system` for building based on the specific config.

        This includes copying any header files to the correct locations, and running any templating.
        All modules are only prepared after validation of all modules has occurred.
        Compilation does not occur until all modules are prepared.

        This is currently only stubbed.

        """
        if self.code_gen is None:
            if copy_all_files:
                path = os.path.join(system.output, os.path.basename(self.filename))
                shutil.copyfile(self.filename, path)
                logger.info("Preparing: copy %s -> %s", self.filename, path)
                system.add_file(path)
            else:
                system.add_file(self.filename)

        elif self.code_gen == 'template':
            # Create implementation file.
            ext = os.path.splitext(self.filename)[1]
            path = os.path.join(system.output, '{}{}'.format(os.path.basename(self.name), ext))
            logger.info("Preparing: template %s -> %s (%s)", self.filename, path, config)
            pystache_render(self.filename, path, config)
            system.add_file(path)

        # Copy any headers across. This should use templating if that is configured.
        for header in self.headers:
            path = os.path.join(system.output, os.path.basename(header.path))
            try:
                if header.code_gen is None:
                    shutil.copyfile(header.path, path)
                elif header.code_gen == 'template':
                    logger.info("Preparing: template %s -> %s (%s)", header.path, path, config)
                    pystache_render(header.path, path, config)
            except FileNotFoundError as e:
                s = xml_error_str(header.xml_element, "Resource not found: {}".format(header.path))
                raise ResourceNotFoundError(s)
예제 #6
0
    def __init__(self, filename, search_paths=None, prx_include_paths=None):
        """Parses the project definition file `filename` and any imported system and module definition files.

        If filename is None, then a default 'empty' project is created.

        The search path for a project is a list of paths in which modules will be searched.
        The order of the search path matters; the first path in which an entity is found is used.

        The search path consists of the 'user' search paths, and the 'built-in' search paths.
        'user' search paths are searched before 'built-in' search paths.

        The 'user' search paths consist of the 'param' search paths as passed explicitly to the class and
        the 'project' search paths, which are any search paths specified in the project file.
        'param' search paths are searched before the 'project' search paths.
        If no 'param' search paths or 'project' search paths are specified, then the 'user' search path
        defaults to the project file's directory (or the current working directory if no project file is specified.)

        """
        if filename is None:
            self.dom = xml_parse_string('<project></project>')
            self.project_dir = os.getcwd()
        else:
            self.dom = xml_parse_file(filename)
            self.project_dir = os.path.dirname(filename)

        self.entities = {}

        # Find all startup-script items.
        ss_els = self.dom.getElementsByTagName('startup-script')
        for ss in ss_els:
            command = single_text_child(ss)
            if command.split()[0].endswith('.py'):
                # prepend full path of python interpreter as .py files are not necessarily executable on Windows
                # and the command 'python3.3' is likely not in PATH
                command = '{} {}'.format(sys.executable, command)
            ret_code = os.system(command)
            if ret_code != 0:
                err = xml_error_str(
                    ss, "Error running startup-script"
                    ": '{}' {}".format(command, show_exit(ret_code)))
                raise ProjectStartupError(err)

        param_search_paths = search_paths if search_paths is not None else []
        project_search_paths = list(get_paths_from_dom(self.dom,
                                                       'search-path'))
        user_search_paths = param_search_paths + project_search_paths
        if len(user_search_paths) == 0:
            user_search_paths = [self.project_dir]

        built_in_search_paths = []
        if frozen:
            base_file = sys.executable if frozen else __file__
            base_file = follow_link(base_file)

            base_dir = canonical_path(os.path.dirname(base_file))

            def find_share(cur):
                cur = canonical_path(cur)
                maybe_share_path = os.path.join(cur, 'share')
                if os.path.exists(maybe_share_path):
                    return maybe_share_path
                else:
                    up = canonical_path(os.path.join(cur, os.path.pardir))
                    if up == cur:
                        return None
                    return find_share(up)

            share_dir = find_share(base_dir)
            if share_dir is None or not os.path.isdir(share_dir):
                logger.warning("Unable to find 'share' directory.")
            else:
                packages_dir = os.path.join(share_dir, 'packages')
                if not os.path.exists(packages_dir) or not os.path.isdir(
                        packages_dir):
                    logger.warning(
                        "Can't find 'packages' directory in '{}'".format(
                            share_dir))
                else:
                    built_in_search_paths.append(packages_dir)

        self.search_paths = user_search_paths + built_in_search_paths

        logger.debug("search_paths %s", self.search_paths)

        param_prx_include_paths = prx_include_paths if prx_include_paths is not None else []
        self._prx_include_paths = list(
            get_paths_from_dom(self.dom,
                               'prx-include-path')) + param_prx_include_paths

        output_el = maybe_single_named_child(self.dom, 'output')
        if output_el:
            path = get_attribute(output_el, 'path')
        else:
            path = 'out'
        if os.path.isabs(path):
            self.output = path
        else:
            self.output = os.path.join(self.project_dir, path)
예제 #7
0
    def _get_instances(self):
        """Instantiate all modules referenced in the system definition file of this system and validate them.
        This is a prerequisite to invoking such operations as build or load on a system.

        Returns a list of instances of class ModuleInstance.

        """
        # Parse the DOM to load all the entities.
        module_el = single_named_child(self.dom, 'modules')
        module_els = [
            e for e in module_el.childNodes
            if e.nodeType == e.ELEMENT_NODE and e.tagName == 'module'
        ]

        instances = []
        rtos_config_data = {}
        rtos_module_name = None
        non_rtos_modules = []

        for m_el in module_els:
            # First find the module
            name = get_attribute(m_el, 'name')
            if not valid_entity_name(name):
                raise EntityLoadError(
                    xml_error_str(m_el,
                                  "Invalid module name '{}'".format(name)))

            module = self.project.find(name)

            if isinstance(module, Module):
                try:
                    config_data = module.configure(m_el)
                except SystemParseError as e:
                    # The module's configure module is allowed to raise a SystemParseError
                    # we just re-raise it.
                    raise
                except Exception as e:
                    exc_type, exc_value, tb = sys.exc_info()
                    tb_str = ''.join(
                        traceback.format_exception(exc_type,
                                                   exc_value,
                                                   tb.tb_next,
                                                   chain=False))
                    msg = "Error running module '{}' configure method.".format(
                        name)
                    detail = "Traceback:\n{}".format(tb_str)
                    raise EntityLoadError(msg, detail)

                # Find the config data of the RTOS module, identified by a reserved substring
                if ".rtos-" in name:
                    if rtos_module_name is not None:
                        raise EntityLoadError(
                            xml_error_str(
                                m_el,
                                "Multiple RTOS modules found, '{}' and '{}'".
                                format(rtos_module_name, name)))
                    if not config_data:
                        raise EntityLoadError(
                            xml_error_str(
                                m_el,
                                "RTOS module '{}' has no config data".format(
                                    name)))

                    # Commit the RTOS module alone
                    instance = ModuleInstance(module, self, config_data)
                    instances.append(instance)

                    rtos_config_data = config_data
                    rtos_module_name = name
                else:
                    print("APPENDED NON-RTOS MODULE: " + str(name) + ' ' +
                          str(module) + ' ' + str(config_data) + ' ' +
                          str(m_el))
                    non_rtos_modules.append((name, module, config_data, m_el))
            else:
                raise EntityLoadError(
                    xml_error_str(
                        m_el, 'Entity {} has unexpected type {} and cannot be \
                instantiated'.format(name, type(module))))

        # Commit each non-RTOS module's config, with that of the RTOS module present as a dict under the key 'rtos'
        for (name, module, config_data, m_el) in non_rtos_modules:
            print("config data is: " + str(config_data))
            if not config_data:
                config_data = {}
            elif 'rtos' in config_data.keys():
                raise EntityLoadError(
                    xml_error_str(
                        m_el,
                        "Module '{}' cannot have a configuration item with the "
                        "reserved name 'rtos'.").format(name))
            config_data['rtos'] = rtos_config_data
            instance = ModuleInstance(module, self, config_data)
            instances.append(instance)

        os.makedirs(self.output, exist_ok=True)

        for i in instances:
            i.validate()

        return instances
예제 #8
0
파일: prj.py 프로젝트: GaloisInc/echronos
    def __init__(self, filename, search_paths=None, prx_include_paths=None):
        """Parses the project definition file `filename` and any imported system and module definition files.

        If filename is None, then a default 'empty' project is created.

        The search path for a project is a list of paths in which modules will be searched.
        The order of the search path matters; the first path in which an entity is found is used.

        The search path consists of the 'user' search paths, and the 'built-in' search paths.
        'user' search paths are searched before 'built-in' search paths.

        The 'user' search paths consist of the 'param' search paths as passed explicitly to the class and
        the 'project' search paths, which are any search paths specified in the project file.
        'param' search paths are searched before the 'project' search paths.
        If no 'param' search paths or 'project' search paths are specified, then the 'user' search path
        defaults to the project file's directory (or the current working directory if no project file is specified.)

        """
        if filename is None:
            self.dom = xml_parse_string('<project></project>')
            self.project_dir = os.getcwd()
        else:
            self.dom = xml_parse_file(filename)
            self.project_dir = os.path.dirname(filename)

        self.entities = {}

        # Find all startup-script items.
        ss_els = self.dom.getElementsByTagName('startup-script')
        for ss in ss_els:
            command = single_text_child(ss)
            if command.split()[0].endswith('.py'):
                # prepend full path of python interpreter as .py files are not necessarily executable on Windows
                # and the command 'python3.3' is likely not in PATH
                command = '{} {}'.format(sys.executable, command)
            ret_code = os.system(command)
            if ret_code != 0:
                err = xml_error_str(ss, "Error running startup-script"
                                        ": '{}' {}".format(command, show_exit(ret_code)))
                raise ProjectStartupError(err)

        param_search_paths = search_paths if search_paths is not None else []
        project_search_paths = list(get_paths_from_dom(self.dom, 'search-path'))
        user_search_paths = param_search_paths + project_search_paths
        if len(user_search_paths) == 0:
            user_search_paths = [self.project_dir]

        built_in_search_paths = []
        if frozen:
            base_file = sys.executable if frozen else __file__
            base_file = follow_link(base_file)

            base_dir = canonical_path(os.path.dirname(base_file))

            def find_share(cur):
                cur = canonical_path(cur)
                maybe_share_path = os.path.join(cur, 'share')
                if os.path.exists(maybe_share_path):
                    return maybe_share_path
                else:
                    up = canonical_path(os.path.join(cur, os.path.pardir))
                    if up == cur:
                        return None
                    return find_share(up)
            share_dir = find_share(base_dir)
            if share_dir is None or not os.path.isdir(share_dir):
                logger.warning("Unable to find 'share' directory.")
            else:
                packages_dir = os.path.join(share_dir, 'packages')
                if not os.path.exists(packages_dir) or not os.path.isdir(packages_dir):
                    logger.warning("Can't find 'packages' directory in '{}'".format(share_dir))
                else:
                    built_in_search_paths.append(packages_dir)

        self.search_paths = user_search_paths + built_in_search_paths

        logger.debug("search_paths %s", self.search_paths)

        param_prx_include_paths = prx_include_paths if prx_include_paths is not None else []
        self._prx_include_paths = list(get_paths_from_dom(self.dom, 'prx-include-path')) + param_prx_include_paths

        output_el = maybe_single_named_child(self.dom, 'output')
        if output_el:
            path = get_attribute(output_el, 'path')
        else:
            path = 'out'
        if os.path.isabs(path):
            self.output = path
        else:
            self.output = os.path.join(self.project_dir, path)
예제 #9
0
파일: prj.py 프로젝트: GaloisInc/echronos
    def _get_instances(self):
        """Instantiate all modules referenced in the system definition file of this system and validate them.
        This is a prerequisite to invoking such operations as build or load on a system.

        Returns a list of instances of class ModuleInstance.

        """
        # Parse the DOM to load all the entities.
        module_el = single_named_child(self.dom, 'modules')
        module_els = [e for e in module_el.childNodes if e.nodeType == e.ELEMENT_NODE and e.tagName == 'module']

        instances = []
        rtos_config_data = {}
        rtos_module_name = None
        non_rtos_modules = []

        for m_el in module_els:
            # First find the module
            name = get_attribute(m_el, 'name')
            if not valid_entity_name(name):
                raise EntityLoadError(xml_error_str(m_el, "Invalid module name '{}'".format(name)))

            module = self.project.find(name)

            if isinstance(module, Module):
                try:
                    config_data = module.configure(m_el)
                except SystemParseError as e:
                    # The module's configure module is allowed to raise a SystemParseError
                    # we just re-raise it.
                    raise
                except Exception as e:
                    exc_type, exc_value, tb = sys.exc_info()
                    tb_str = ''.join(traceback.format_exception(exc_type, exc_value, tb.tb_next, chain=False))
                    msg = "Error running module '{}' configure method.".format(name)
                    detail = "Traceback:\n{}".format(tb_str)
                    raise EntityLoadError(msg, detail)

                # Find the config data of the RTOS module, identified by a reserved substring
                if ".rtos-" in name:
                    if rtos_module_name is not None:
                        raise EntityLoadError(xml_error_str(m_el, "Multiple RTOS modules found, '{}' and '{}'".format(
                            rtos_module_name, name)))
                    if not config_data:
                        raise EntityLoadError(xml_error_str(m_el, "RTOS module '{}' has no config data".format(name)))

                    # Commit the RTOS module alone
                    instance = ModuleInstance(module, self, config_data)
                    instances.append(instance)

                    rtos_config_data = config_data
                    rtos_module_name = name
                else:
                    non_rtos_modules.append((name, module, config_data, m_el))
            else:
                raise EntityLoadError(xml_error_str(m_el, 'Entity {} has unexpected type {} and cannot be \
                instantiated'.format(name, type(module))))

        # Commit each non-RTOS module's config, with that of the RTOS module present as a dict under the key 'rtos'
        for (name, module, config_data, m_el) in non_rtos_modules:
            if not config_data:
                config_data = {}
            elif 'rtos' in config_data.keys():
                raise EntityLoadError(xml_error_str(m_el, "Module '{}' cannot have a configuration item with the "
                                                          "reserved name 'rtos'.").format(name))
            config_data['rtos'] = rtos_config_data
            instance = ModuleInstance(module, self, config_data)
            instances.append(instance)

        os.makedirs(self.output, exist_ok=True)

        for i in instances:
            i.validate()

        return instances