Skip to content

Commit

Permalink
feat: add write functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
tngraf committed Dec 24, 2023
1 parent effb2b2 commit 1433b8d
Show file tree
Hide file tree
Showing 21 changed files with 1,069 additions and 136 deletions.
5 changes: 5 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Python library to read Component License Information (CLI) files

## 2.0.0

* add CLI write functionality.
* add type information

## V1.3 (2023-01-10)

* relicensed to MIT.
Expand Down
165 changes: 133 additions & 32 deletions cli_support/CLI.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -------------------------------------------------------------------------------
# (c) 2019-2022 Siemens AG
# (c) 2019-2023 Siemens AG
# All Rights Reserved.
# Author: [email protected]
#
Expand All @@ -8,14 +8,34 @@
# -------------------------------------------------------------------------------

import xml.etree.ElementTree as ET
# from typing import List
from typing import Any

from .cli_assessment_summary import CliAssessmentSummary
from .cli_copyright import CliCopyright
from .cli_export_restriction import CliExportRestriction
from .cli_external_id import CliExternalId
from .cli_general_information import CliGeneralInformation
from .cli_irrelevant_files import CliIrrelevantFiles
from .cli_license import CliLicense
from .cli_obligation import CliObligation
from .xml_base import XmlBase

# have our own serialization to handle CDATA
ET._original_serialize_xml = ET._serialize_xml # type: ignore

class CliFile:

def _serialize_xml(write, elem, qnames, namespaces, short_empty_elements, **kwargs) -> Any: # type: ignore
if elem.tag == XmlBase.CDATA_ID:
write("<%s%s]]>" % (elem.tag, elem.text))
return
return ET._original_serialize_xml(write, elem, qnames, namespaces, short_empty_elements, **kwargs) # type: ignore


ET._serialize_xml = ET._serialize["xml"] = _serialize_xml # type: ignore


class CliFile(XmlBase):
"""Encapsulates a CLI file, i.e. all licenses and copyrights
found in a component"""

Expand All @@ -24,27 +44,37 @@ class CliFile:
EXPORTRESTRICTIONS_TAG = "ExportRestrictions"
OBLIGATION_TAG = "Obligation"
TAGS_TAG = "Tags"

def __init__(self):
self.filename = ""
self.component = ""
self.creator = ""
self.date = ""
self.baseDoc = ""
self.toolUsed = ""
self.componentId = ""
self.includesAcknowledgements = False
self.componentSha1 = ""
self.version = ""

self.licenses = []
self.copyrights = []
self.obligations = []
self.tags = []
self.irrelevant_files = []
self.export_restrictions = []

def read_from_file(self, filename: str):
GENERAL_INFORMATION_TAG = "GeneralInformation"
ASSESSMENT_SUMMARY_TAG = "AssessmentSummary"
EXTERNAL_IDS_TAG = "ExternalIds"
IRRELEVANT_FILES_TAG = "IrrelevantFiles"
COMMENT_TAG = "Comment"

def __init__(self) -> None:
self.filename: str = ""
self.component: str = ""
self.creator: str = ""
self.date: str = ""
self.baseDoc: str = ""
self.toolUsed: str = ""
self.componentId: str = ""
self.includesAcknowledgements: bool = False
self.componentSha1: str = ""
self.version: str = ""

self.general_information = CliGeneralInformation()
self.assessment_summary = CliAssessmentSummary()

self.licenses: list[CliLicense] = []
self.copyrights: list[CliCopyright] = []
self.obligations: list[CliObligation] = []
self.tags: list[str] = []
self.export_restrictions: list[CliExportRestriction] = []
self.external_ids: list[CliExternalId] = []
self.irrelevant_files = CliIrrelevantFiles()
self.comment: str = ""

def read_from_file(self, filename: str) -> None:
tree = ET.parse(filename)
root = tree.getroot()

Expand All @@ -61,7 +91,8 @@ def read_from_file(self, filename: str):
self.componentId = root.attrib["componentID"]

if "includesAcknowledgements" in root.attrib:
self.includesAcknowledgements = root.attrib["includesAcknowledgements"]
if root.attrib["includesAcknowledgements"].lower() == "true":
self.includesAcknowledgements = True

if "componentSHA1" in root.attrib:
self.componentSha1 = root.attrib["componentSHA1"]
Expand All @@ -72,33 +103,103 @@ def read_from_file(self, filename: str):
for elem in root:
if elem.tag == self.LICENSE_TAG:
lic = CliLicense()
lic.read_from_element(elem)
lic._read_from_element(elem)
self.licenses.append(lic)
continue

if elem.tag == self.COPYRIGHT_TAG:
copyr = CliCopyright()
copyr.read_from_element(elem)
copyr._read_from_element(elem)
self.copyrights.append(copyr)
continue

if elem.tag == self.EXPORTRESTRICTIONS_TAG:
restriction = CliExportRestriction()
restriction.read_from_element(elem)
restriction._read_from_element(elem)
self.export_restrictions.append(restriction)
continue

if elem.tag == self.OBLIGATION_TAG:
obligation = CliObligation()
obligation.read_from_element(elem)
obligation._read_from_element(elem)
self.obligations.append(obligation)
continue

if elem.tag == self.GENERAL_INFORMATION_TAG:
self.general_information._read_from_element(elem)
continue

if elem.tag == self.ASSESSMENT_SUMMARY_TAG:
self.assessment_summary._read_from_element(elem)
continue

if elem.tag == self.EXTERNAL_IDS_TAG:
for el in elem:
ext_id = CliExternalId()
ext_id._read_from_element(el)
self.external_ids.append(ext_id)
continue

if elem.tag == self.IRRELEVANT_FILES_TAG:
self.irrelevant_files._read_from_element(elem)
continue

if elem.tag == self.COMMENT_TAG:
self.comment = self.get_value(elem)
continue

if elem.tag == self.TAGS_TAG:
if elem.text is not None:
taglist = elem.text.strip()
if "," in taglist:
self.tags = taglist.split(",")
else:
self.tags = taglist.split(" ")
if taglist:
if "," in taglist:
self.tags = taglist.split(",")
else:
self.tags = taglist.split(" ")
continue

def write_to_file(self, filename: str) -> None:
"""Write CLI data to a file with the given name."""
root = ET.Element(
"ComponentLicenseInformation",
component=self.component,
creator=self.creator,
date=self.date,
baseDoc=self.baseDoc,
toolUsed=self.toolUsed,
componentID=self.componentId,
includesAcknowledgements=self.bool2str(self.includesAcknowledgements),
componentSHA1=self.componentSha1,
Version="1.6")

self.general_information._append_to_xml(root)
self.assessment_summary._append_to_xml(root)

for license in self.licenses:
license._append_to_xml(root)

for copyright in self.copyrights:
copyright._append_to_xml(root)

for obligation in self.obligations:
obligation._append_to_xml(root)

for expr in self.export_restrictions:
expr._append_to_xml(root)

self.irrelevant_files._append_to_xml(root)

extids = ET.SubElement(root, "ExternalIds")
for extid in self.external_ids:
extid._append_to_xml(extids)

tags = ET.SubElement(root, "Tags")
tags.text = ",".join(str(x) for x in self.tags)

comment = ET.SubElement(root, "Comment")
cdata = self.CDATA(self.comment)
comment.append(cdata)

tree = ET.ElementTree(root)
ET.indent(tree)
tree.write(filename, encoding="UTF-8")
80 changes: 80 additions & 0 deletions cli_support/cli_assessment_summary.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# -------------------------------------------------------------------------------
# (c) 2023 Siemens AG
# All Rights Reserved.
# Author: [email protected]
#
# Licensed under the MIT license.
# SPDX-License-Identifier: MIT
# -------------------------------------------------------------------------------

import xml.etree.ElementTree as ET

from .xml_base import XmlBase


class CliAssessmentSummary(XmlBase):
"""Encapsulates the assessment summary."""
GENERAL_ASSESSMENT_TAG = "GeneralAssessment"
CRITICAL_FILES_TAG = "CriticalFilesFound"
DEPENDENCY_NOTES_TAG = "DependencyNotes"
EXPORT_RESTRICTIONS_TAG = "ExportRestrictionsFound"
USAGE_RESTRICTIONS_TAG = "UsageRestrictionsFound"
ADDITIONAL_NOTES_TAG = "AdditionalNotes"

def __init__(self) -> None:
self.general_assessment: str = ""
self.critical_files_found: str = "None"
self.dependency_notes: str = "None"
self.export_restrictions_found: str = "None"
self.usage_restrictions_found: str = "None"
self.additional_notes: str = ""

def _read_from_element(self, element: ET.Element) -> None:
"""Read assessment summary from XML element."""
for elem in element:
if elem.tag == self.GENERAL_ASSESSMENT_TAG:
self.general_assessment = self.get_value(elem)
continue

if elem.tag == self.CRITICAL_FILES_TAG:
self.critical_files_found = self.get_value(elem)
continue

if elem.tag == self.DEPENDENCY_NOTES_TAG:
self.dependency_notes = self.get_value(elem)
continue

if elem.tag == self.EXPORT_RESTRICTIONS_TAG:
self.export_restrictions_found = self.get_value(elem)
continue

if elem.tag == self.USAGE_RESTRICTIONS_TAG:
self.usage_restrictions_found = self.get_value(elem)
continue

if elem.tag == self.ADDITIONAL_NOTES_TAG:
self.additional_notes = self.get_value(elem)
continue

def _append_to_xml(self, parent: ET.Element) -> None:
"""Write assessment summary to XML element."""
gi = ET.SubElement(parent, "AssessmentSummary")
node = ET.SubElement(gi, "GeneralAssessment")
cdata = self.CDATA(self.general_assessment)
node.append(cdata)

node = ET.SubElement(gi, "CriticalFilesFound")
node.text = self.critical_files_found

node = ET.SubElement(gi, "DependencyNotes")
node.text = self.dependency_notes

node = ET.SubElement(gi, "ExportRestrictionsFound")
node.text = self.export_restrictions_found

node = ET.SubElement(gi, "UsageRestrictionsFound")
node.text = self.usage_restrictions_found

node = ET.SubElement(gi, "AdditionalNotes")
cdata = self.CDATA(self.additional_notes)
node.append(cdata)
28 changes: 19 additions & 9 deletions cli_support/cli_copyright.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# -------------------------------------------------------------------------------
# (c) 2019-2022 Siemens AG
# (c) 2019-2023 Siemens AG
# All Rights Reserved.
# Author: [email protected]
#
Expand All @@ -13,20 +13,30 @@


class CliCopyright(CliFileItemBase):
"""Encapsulates a copyright statement"""
"""Encapsulates a copyright statement."""

CONTENT_TAG = "Content"

def __init__(self):
def __init__(self) -> None:
CliFileItemBase.__init__(self)
self.text = ""
self.files = []
self.hashes = []
self.text: str = ""
self.files: list[str] = []
self.hashes: list[str] = []

def read_from_element(self, element: ET.Element):
self.read_files_from_element(element)
def _read_from_element(self, element: ET.Element) -> None:
"""Read copyright from XML element."""
self._read_files_from_element(element)
for elem in element:
if elem.tag == self.CONTENT_TAG:
if elem.tag == self.CONTENT_TAG and elem.text:
if elem.text is not None:
self.text = elem.text.strip()
continue

def _append_to_xml(self, parent: ET.Element) -> None:
"""Write copyright to XML element."""
cr = ET.SubElement(parent, "Copyright")
node = ET.SubElement(cr, "Content")
cdata = self.CDATA(self.text)
node.append(cdata)

CliFileItemBase._append_to_xml(self, cr)
Loading

0 comments on commit 1433b8d

Please sign in to comment.