Esempio n. 1
0
 def __init__(self, description):
     description_is_file = False
     if os.path.exists(description):
         description_is_file = True
     try:
         if description_is_file:
             self.description = description
         else:
             self.description_temporary = NamedTemporaryFile()
             with open(self.description_temporary.name, 'wb') as outfile:
                 outfile.write(description)
             self.description = self.description_temporary.name
     except Exception as issue:
         raise KiwiDescriptionInvalid(issue)
     self.post_init()
Esempio n. 2
0
    def post_init(self):
        """
        Convert given description file into XML

        The anymarkup module supports auto detection of the given
        input format and can convert YAML, JSON and INI to XML
        """
        try:
            self.anymarkup = importlib.import_module('anymarkup')
        except Exception as issue:
            raise KiwiAnyMarkupPluginError(issue)
        try:
            self.description_markup_processed = NamedTemporaryFile()
            markup = self.anymarkup.parse_file(self.description,
                                               force_types=None)
            self.anymarkup.serialize_file(
                markup, self.description_markup_processed.name, format='xml')
        except Exception as issue:
            raise KiwiDescriptionInvalid(issue)
Esempio n. 3
0
    def apply_xslt_stylesheets(self, description: str) -> str:
        """
        Apply XSLT style sheet rules to an xml file

        The result of the XSLT processing is stored in a named
        temporary file and returned to the caller

        :param str description: path to an XML description file
        """
        # Parse the provided description, raising the appropriate
        # exception if parsing fails.
        try:
            parsed_description = etree.parse(description)
        except etree.XMLSyntaxError:
            raise KiwiConfigFileFormatNotSupported(
                'Configuration file could not be parsed. '
                'In case your configuration file is XML it most likely '
                'contains a syntax error. For other formats the '
                'Python anymarkup module is required.')

        xslt_transform_parser = etree.XMLParser()
        xslt_transform_parser.resolvers.add(
            FileResolver(os.path.dirname(self.description)))
        xslt_transform = etree.XSLT(
            etree.parse(Defaults.get_xsl_stylesheet_file(),
                        xslt_transform_parser))
        self.description_xslt_processed = Temporary(
            prefix='kiwi_xslt-').new_file()
        try:
            with open(self.description_xslt_processed.name, "wb") as xsltout:
                xsltout.write(
                    etree.tostring(xslt_transform(parsed_description),
                                   pretty_print=True))
        except etree.XMLSyntaxError as issue:
            raise KiwiDescriptionInvalid(issue)

        return self.description_xslt_processed.name
Esempio n. 4
0
    def load(self) -> Any:
        """
        Read XML description, validate it against the schema
        and the schematron rules and pass it to the
        autogenerated(generateDS) parser.

        :return: instance of XML toplevel domain (image)

        :rtype: object
        """
        try:
            schema_doc = etree.parse(Defaults.get_schema_file())
            relaxng = etree.RelaxNG(schema_doc)
            schematron = isoschematron.Schematron(
                schema_doc, store_report=True
            )
        except Exception as issue:
            raise KiwiSchemaImportError(issue)
        try:
            description = etree.parse(self.description)
            validation_rng = relaxng.validate(description)
            validation_schematron = schematron.validate(description)
        except Exception as issue:
            raise KiwiValidationError(issue)
        if not validation_rng:
            XMLDescription._get_relaxng_validation_details(
                Defaults.get_schema_file(),
                self.description,
                relaxng.error_log
            )
        if not validation_schematron:
            XMLDescription._get_schematron_validation_details(
                schematron.validation_report
            )
        if not validation_rng or not validation_schematron:
            raise KiwiDescriptionInvalid(
                'Failed to validate schema and/or schematron rules'
            )

        parse_result = self._parse()

        if parse_result.get_extension():
            extension_namespace_map = \
                description.getroot().xpath('extension')[0].nsmap

            for namespace_name in extension_namespace_map:
                extensions_for_namespace = description.getroot().xpath(
                    'extension/{namespace}:*'.format(namespace=namespace_name),
                    namespaces=extension_namespace_map
                )
                if extensions_for_namespace:
                    # one toplevel entry point per extension via xmlns
                    if len(extensions_for_namespace) > 1:
                        raise KiwiExtensionError(
                            'Multiple toplevel sections for "{0}" found'.format(
                                namespace_name
                            )
                        )

                    # store extension xml data parse tree for this namespace
                    self.extension_data[namespace_name] = \
                        etree.ElementTree(extensions_for_namespace[0])

                    # validate extension xml data
                    try:
                        xml_catalog = Command.run(
                            [
                                'xmlcatalog', '/etc/xml/catalog',
                                extension_namespace_map[namespace_name]
                            ]
                        )
                        extension_schema = xml_catalog.output.rstrip().replace(
                            'file://', ''
                        )
                        extension_relaxng = etree.RelaxNG(
                            etree.parse(extension_schema)
                        )
                    except Exception as issue:
                        raise KiwiExtensionError(
                            'Extension schema error: {0}'.format(issue)
                        )
                    validation_result = extension_relaxng.validate(
                        self.extension_data[namespace_name]
                    )
                    if not validation_result:
                        xml_data_unformatted = etree.tostring(
                            self.extension_data[namespace_name],
                            encoding='utf-8'
                        )
                        xml_data_domtree = minidom.parseString(
                            xml_data_unformatted
                        )
                        extension_file = Temporary().new_file()
                        with open(extension_file.name, 'w') as xml_data:
                            xml_data.write(xml_data_domtree.toprettyxml())
                        XMLDescription._get_relaxng_validation_details(
                            extension_schema,
                            extension_file.name,
                            extension_relaxng.error_log
                        )
                        raise KiwiExtensionError(
                            'Schema validation for extension XML data failed'
                        )

        return parse_result
Esempio n. 5
0
    def load(self):  # noqa: C901
        """
        Read XML description, pass it along to the XSLT processor,
        validate it against the schema and finally pass it to the
        autogenerated(generateDS) parser.

        :return: instance of XML toplevel domain (image)

        :rtype: object
        """
        try:
            self._xsltproc()
            schema_doc = etree.parse(Defaults.get_schema_file())
            relaxng = etree.RelaxNG(schema_doc)
            schematron = isoschematron.Schematron(schema_doc,
                                                  store_report=True)
        except Exception as e:
            raise KiwiSchemaImportError('%s: %s' %
                                        (type(e).__name__, format(e)))
        try:
            description = etree.parse(self.description_xslt_processed.name)
            validation_rng = relaxng.validate(description)
            validation_sch = schematron.validate(description)
        except Exception as e:
            raise KiwiValidationError('%s: %s' % (type(e).__name__, format(e)))
        if not validation_rng:
            self._get_relaxng_validation_details(
                Defaults.get_schema_file(),
                self.description_xslt_processed.name)
        if not validation_sch:
            self._get_schematron_validation_details(
                schematron.validation_report)
        if not validation_rng or not validation_sch:
            if self.description:
                message = 'Schema validation for {description} failed'.format(
                    description=self.description)
            else:
                message = 'Schema validation for XML content failed'
            raise KiwiDescriptionInvalid(message)

        parse_result = self._parse()

        if parse_result.get_extension():
            extension_namespace_map = \
                description.getroot().xpath('extension')[0].nsmap

            for namespace_name in extension_namespace_map:
                extensions_for_namespace = description.getroot().xpath(
                    'extension/{namespace}:*'.format(namespace=namespace_name),
                    namespaces=extension_namespace_map)
                if extensions_for_namespace:
                    # one toplevel entry point per extension via xmlns
                    if len(extensions_for_namespace) > 1:
                        raise KiwiExtensionError(
                            'Multiple toplevel sections for "{0}" found'.
                            format(namespace_name))

                    # store extension xml data parse tree for this namespace
                    self.extension_data[namespace_name] = \
                        etree.ElementTree(extensions_for_namespace[0])

                    # validate extension xml data
                    try:
                        xml_catalog = Command.run([
                            'xmlcatalog', '/etc/xml/catalog',
                            extension_namespace_map[namespace_name]
                        ])
                        extension_schema = xml_catalog.output.rstrip().replace(
                            'file://', '')
                        extension_relaxng = etree.RelaxNG(
                            etree.parse(extension_schema))
                    except Exception as e:
                        raise KiwiExtensionError(
                            'Extension schema error: {0}: {1}'.format(
                                type(e).__name__, e))
                    validation_result = extension_relaxng.validate(
                        self.extension_data[namespace_name])
                    if not validation_result:
                        xml_data_unformatted = etree.tostring(
                            self.extension_data[namespace_name],
                            encoding='utf-8')
                        xml_data_domtree = minidom.parseString(
                            xml_data_unformatted)
                        extension_file = NamedTemporaryFile()
                        with open(extension_file.name, 'w') as xml_data:
                            xml_data.write(xml_data_domtree.toprettyxml())
                        self._get_relaxng_validation_details(
                            extension_schema, extension_file.name)
                        raise KiwiExtensionError(
                            'Schema validation for extension XML data failed')

        return parse_result