# ==================================================================================================================== #
# _____ ____ _ _ ___ ______ __ _ ____ _____ #
# _ __ _ _| ____| _ \ / \ / \ |_ _| _ \ \/ / / \ / ___|_ _| #
# | '_ \| | | | _| | | | |/ _ \ / _ \ | || |_) \ / / _ \| | | | #
# | |_) | |_| | |___| |_| / ___ \ / ___ \ _ | || __// \ / ___ \ |___ | | #
# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)___|_| /_/\_\/_/ \_\____| |_| #
# |_| |___/ #
# ==================================================================================================================== #
# Authors: #
# Patrick Lehmann #
# #
# License: #
# ==================================================================================================================== #
# Copyright 2017-2024 Patrick Lehmann - Bötzingen, Germany #
# Copyright 2016-2016 Patrick Lehmann - Dresden, Germany #
# #
# Licensed under the Apache License, Version 2.0 (the "License"); #
# you may not use this file except in compliance with the License. #
# You may obtain a copy of the License at #
# #
# http://www.apache.org/licenses/LICENSE-2.0 #
# #
# Unless required by applicable law or agreed to in writing, software #
# distributed under the License is distributed on an "AS IS" BASIS, #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
# See the License for the specific language governing permissions and #
# limitations under the License. #
# #
# SPDX-License-Identifier: Apache-2.0 #
# ==================================================================================================================== #
#
from sys import version_info
from typing import List
from lxml import etree
from os import chdir as os_chdir
from textwrap import dedent
from pathlib import Path
from pyTooling.Common import getFullyQualifiedName
from pyTooling.Decorators import export
from pyEDAA.IPXACT import RootElement, Vlnv, PyIpxactException, __URI_MAP__, __DEFAULT_SCHEMA__
from pyEDAA.IPXACT.Component import Component
[docs]
@export
class IpxactFile:
"""Represents a IP-XACT file."""
_vlnv: Vlnv #: VLNV unique identifier
_name: str #: Name
_description: str #: Description
[docs]
def __init__(self, vlnv: Vlnv, name: str, description: str):
"""Constructor"""
self._vlnv = vlnv
self._name = name
self._description = description
[docs]
@classmethod
def FromXml(cls, element):
"""Constructs an instance of ``IpxactFile`` from an lxml element."""
elementTag = etree.QName(element.tag)
if elementTag.localname != "ipxactFile":
raise PyIpxactException("Expected tag 'ipxactFile'.")
for element2 in element:
element3 = etree.QName(element2)
if element3.localname == "vlnv":
vendor = element2.get("vendor")
library = element2.get("library")
name2 = element2.get("name")
version = element2.get("version")
vlnv = Vlnv(vendor, library, name2, version)
elif element3.localname == "name":
name = element2.text
elif element3.localname == "description":
description = element2.text
else:
raise PyIpxactException(f"Unsupported tag '{element.localname}' in node 'ipxactFile'.")
ipxactFile = cls(vlnv, name, description)
return ipxactFile
[docs]
def ToXml(self, indent):
"""Converts the object's data into XML format."""
_indent = "\t" * indent
prefix = __DEFAULT_SCHEMA__.NamespacePrefix
buffer = dedent(f"""\
{_indent}<{prefix}:ipxactFile>
{_indent} {self._vlnv.ToXml(0)}
{_indent} <{prefix}:name>{self._name}</{prefix}:name>
{_indent} <{prefix}:description>{self._description}</{prefix}:description>
{_indent}</{prefix}:ipxactFile>
""")
return buffer
[docs]
@export
class Catalog(RootElement):
"""Represents an IP-XACT catalog."""
_description: str
_abstractionDefinitions: List
_abstractors: List
_busInterfaces: List
_catalogs: List
_components: List
_designConfigurations: List
_designs: List
_generatorChains: List
[docs]
def __init__(self, vlnv: Vlnv, description: str):
super().__init__(vlnv)
self._description = description
self._abstractionDefinitions = []
self._abstractors = []
self._busInterfaces = []
self._catalogs = []
self._components = []
self._designConfigurations = []
self._designs = []
self._generatorChains = []
[docs]
@classmethod
def FromFile(cls, filePath : Path):
"""Constructs an instance of ``Catalog`` from a file."""
if not filePath.exists():
raise PyIpxactException(f"File '{filePath}' not found.") from FileNotFoundError(str(filePath))
try:
with filePath.open("r", encoding="utf-8") as fileHandle: # TODO: why not open in binary?
content = fileHandle.read()
content = bytes(bytearray(content, encoding='utf-8'))
except OSError as ex:
raise PyIpxactException("Couldn't open '{0!s}'.".format(filePath)) from ex
schemaPath = Path("../lib/schema/ieee-1685-2014/index.xsd")
try:
with schemaPath.open("r", encoding="utf-8") as fileHandle: # TODO: why not opening as binary?
schema = fileHandle.read()
schema = bytes(bytearray(schema, encoding='utf-8'))
except OSError as ex:
raise PyIpxactException(f"Couldn't open '{schemaPath}'.") from ex
xmlParser = etree.XMLParser(remove_blank_text=True, encoding="utf-8")
schemaRoot = etree.XML(schema, xmlParser)
schemaTree = etree.ElementTree(schemaRoot)
xmlschema = etree.XMLSchema(schemaTree)
root = etree.XML(content, xmlParser)
rootTag = etree.QName(root.tag)
if not xmlschema.validate(root):
raise PyIpxactException("The input IP-XACT file is not valid.")
elif rootTag.namespace not in __URI_MAP__:
raise PyIpxactException(f"The input IP-XACT file uses an unsupported namespace: '{rootTag.namespace}'.")
elif rootTag.localname != "catalog":
raise PyIpxactException("The input IP-XACT file is not a catalog file.")
print("==" * 20)
items = []
for rootElements in root:
element = etree.QName(rootElements)
if element.localname == "vendor":
vendor = rootElements.text
elif element.localname == "library":
library = rootElements.text
elif element.localname == "name":
name = rootElements.text
elif element.localname == "version":
version = rootElements.text
elif element.localname == "description":
description = rootElements.text
elif element.localname == "catalogs":
for ipxactFileElement in rootElements:
items.append(IpxactFile.FromXml(ipxactFileElement))
else:
raise PyIpxactException(f"Unsupported tag '{element.localname}' at root-level.")
print("==" * 20)
vlnv = Vlnv(vendor=vendor, library=library, name=name, version=version)
catalog = cls(vlnv, description=description)
for item in items:
catalog.AddItem(item)
return catalog
def AddItem(self, item) -> None:
if isinstance(item, IpxactFile):
self._catalogs.append(item)
elif isinstance(item, Component):
self._components.append(item)
else:
ex = TypeError(f"Parameter 'item' is neither a 'IpxactFile' nor a 'Component'.")
if version_info >= (3, 11): # pragma: no cover
ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.")
raise ex
[docs]
def ToXml(self) -> str:
"""Converts the object's data into XML format."""
buffer = dedent("""\
<?xml version="1.0" encoding="UTF-8"?>
<{xmlns}:catalog
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:{xmlns}="{schemaUri}"
xsi:schemaLocation="{schemaUri} {schemaUrl}">
{versionedIdentifier}
<{xmlns}:description>{description}</{xmlns}:description>
""").format(
xmlns=__DEFAULT_SCHEMA__.NamespacePrefix,
schemaUri=__DEFAULT_SCHEMA__.SchemaUri,
schemaUrl=__DEFAULT_SCHEMA__.SchemaUrl,
versionedIdentifier=self._vlnv.ToXml(isVersionedIdentifier=True),
description=self._description
)
if self._catalogs:
buffer += "\t<{xmlns}:catalogs>\n"
for ipxactFile in self._catalogs:
buffer += ipxactFile.ToXml(2)
buffer += "\t</{xmlns}:catalogs>\n"
if self._components:
buffer += "\t<{xmlns}:components>\n"
for ipxactFile in self._components:
buffer += ipxactFile.ToXml(2)
buffer += "\t</{xmlns}:components>\n"
buffer += dedent("""\
</{xmlns}:catalog>
""")
return buffer.format(xmlns=__DEFAULT_SCHEMA__.NamespacePrefix)