Module continuous_delivery_scripts.spdx_report.spdx_document
Definition of an SPDX Document.
Expand source code
#
# Copyright (C) 2020-2025 Arm Limited or its affiliates and Contributors. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
"""Definition of an SPDX Document."""
from pathlib import Path
from spdx.creationinfo import Person, Organization, Tool
from spdx.document import Document, License
from spdx.review import Review
from spdx.version import Version
from typing import List, Optional
from continuous_delivery_scripts.spdx_report.spdx_dependency import DependencySpdxDocumentRef
from continuous_delivery_scripts.spdx_report.spdx_helpers import determine_spdx_value, get_project_namespace
from continuous_delivery_scripts.spdx_report.spdx_package import SpdxPackage, PackageInfo
from continuous_delivery_scripts.utils.configuration import configuration, ConfigurationVariable
from continuous_delivery_scripts.utils.hash_helpers import generate_uuid_based_on_str
from continuous_delivery_scripts.utils.python.package_helpers import PackageMetadata
TOOL_NAME = "mbed-spdx-generator"
class SpdxDocument:
"""SPDX document.
See https://spdx.org/spdx-specification-21-web-version#h.4d34og8
"""
def __init__(
self,
package_metadata: PackageMetadata,
other_document_refs: List[DependencySpdxDocumentRef] = list(),
is_dependency: bool = False,
document_namespace: Optional[str] = None,
):
"""Constructor."""
self._project_root = Path(configuration.get_value(ConfigurationVariable.PROJECT_ROOT))
self._project_uuid = str(configuration.get_value(ConfigurationVariable.PROJECT_UUID))
self._project_config = Path(configuration.get_value(ConfigurationVariable.PROJECT_CONFIG))
self._project_source = self._project_root.joinpath(configuration.get_value(ConfigurationVariable.SOURCE_DIR))
self._package_metadata: PackageMetadata = package_metadata
self._is_dependency: bool = is_dependency
self._other_document_references: List[DependencySpdxDocumentRef] = other_document_refs
self._document_namespace = document_namespace
self._spdx_package: Optional[SpdxPackage] = None
@property
def document_name(self) -> str:
"""Gets document name.
See https://spdx.org/spdx-specification-21-web-version#h.wape5vaqknj2
Returns:
corresponding string
"""
return f"{self.name}-{self.version}"
@property
def document_namespace(self) -> str:
"""Gets document namespace.
See https://spdx.org/spdx-specification-21-web-version#h.1gdfkutofa90
Returns:
corresponding string
"""
if self._document_namespace:
return self._document_namespace
return self._generate_namespace()
def _generate_namespace(self) -> str:
"""Generates a document namespace."""
if self._is_dependency:
url_base = "http://spdx.org/spdxdocs"
uuid = generate_uuid_based_on_str(self.document_name)
return f"{url_base}/{self.document_name}-{uuid}"
return get_project_namespace(self._project_config, self.document_name)
@property
def name(self) -> str:
"""Gets package's name.
Returns:
corresponding string
"""
return f"{self._package_metadata.name}"
@property
def version(self) -> str:
"""Gets package version.
Returns:
package version
"""
return self._package_metadata.version
@property
def licence(self) -> str:
"""Gets the project's licence.
Returns:
project's licence
"""
return self._package_metadata.licence
@property
def author(self) -> str:
"""Gets the document's author.
Returns:
document's author
"""
return self._package_metadata.author
@property
def author_email(self) -> str:
"""Gets the document author's email.
Returns:
document author's email
"""
return self._package_metadata.author_email
@property
def organisation(self) -> str:
"""Gets the organisation.
Returns:
the organisation in charge
"""
return str(configuration.get_value(ConfigurationVariable.ORGANISATION))
@property
def organisation_email(self) -> str:
"""Gets the organisation's email.
Returns:
organisation's email
"""
return str(configuration.get_value(ConfigurationVariable.ORGANISATION_EMAIL))
@property
def tool_name(self) -> str:
"""Gets this generation tool's name.
Returns:
this tool's name
"""
return TOOL_NAME
@property
def reviewer(self) -> str:
"""Gets the document's reviewer.
Returns:
document's reviewer
"""
return str(configuration.get_value(ConfigurationVariable.BOT_USERNAME))
@property
def reviewer_email(self) -> str:
"""Gets the document reviewer's email.
Returns:
document reviewer's email
"""
return str(configuration.get_value(ConfigurationVariable.BOT_EMAIL))
@property
def external_refs(self) -> List[DependencySpdxDocumentRef]:
"""Gets the document external references.
Returns:
the list of external references
"""
return self._other_document_references
@external_refs.setter
def external_refs(self, external_refs: List[DependencySpdxDocumentRef]) -> None:
"""Sets the document external references."""
self._other_document_references = external_refs
def generate_spdx_package(self) -> SpdxPackage:
"""Generates the SPDX package for this package.
Returns:
corresponding SPDX package.
"""
if not self._spdx_package:
self._spdx_package = SpdxPackage(
PackageInfo(
metadata=self._package_metadata,
root_dir=self._project_root,
source_dir=self._project_source,
uuid=self._project_uuid,
),
is_dependency=self._is_dependency,
)
return self._spdx_package
def generate_spdx_document(self) -> Document:
"""Generates the SPDX document.
Example of SPDX document section.
SPDXVersion: SPDX-2.1
DataLicense: CC0-1.0
SPDXID: SPDXRef-DOCUMENT
DocumentName: mbed-targets
DocumentNamespace: http://spdx.org/spdxdocs/spdx-v2.1-3c4714e6-a7b1-4574-abb8-861149cbc590
Creator: Person: Anonymous ()
Creator: Organization: Anonymous ()
Creator: Tool: reuse-0.8.0
Created: 2020-01-20T17:53:41Z
CreatorComment: <text>
This document was created automatically using available reuse information consistent with REUSE.
</text>
Returns:
the corresponding document
"""
doc = Document()
doc.version = Version(1, 2)
doc.name = determine_spdx_value(self.document_name)
doc.namespace = determine_spdx_value(self.document_namespace)
doc.spdx_id = "SPDXRef-DOCUMENT"
doc.comment = determine_spdx_value(
"This document was created automatically using available information from python packages."
)
doc.data_license = License.from_identifier("CC0-1.0")
doc.creation_info.add_creator(Person(self.author, self.author_email))
if not self._is_dependency:
doc.creation_info.add_creator(Organization(self.organisation, self.organisation_email))
doc.creation_info.add_creator(Tool(self.tool_name))
doc.creation_info.set_created_now()
if not self._is_dependency:
review = Review(Person(determine_spdx_value(self.reviewer), determine_spdx_value(self.reviewer_email)))
review.set_review_date_now()
doc.add_review(review)
# FIXME with current tooling and specification, only one package can
# be described in a file and hence, all dependencies are described
# in separate files. Find out what to do with dependencies when new
# tools are released as it is not entirely clear in the specification
doc.package = self.generate_spdx_package().generate_spdx_package()
for external_reference in self.external_refs:
doc.add_ext_document_reference(external_reference.generate_external_reference())
return doc
Classes
class SpdxDocument (package_metadata: PackageMetadata, other_document_refs: List[DependencySpdxDocumentRef] = [], is_dependency: bool = False, document_namespace: Optional[str] = None)
-
Expand source code
class SpdxDocument: """SPDX document. See https://spdx.org/spdx-specification-21-web-version#h.4d34og8 """ def __init__( self, package_metadata: PackageMetadata, other_document_refs: List[DependencySpdxDocumentRef] = list(), is_dependency: bool = False, document_namespace: Optional[str] = None, ): """Constructor.""" self._project_root = Path(configuration.get_value(ConfigurationVariable.PROJECT_ROOT)) self._project_uuid = str(configuration.get_value(ConfigurationVariable.PROJECT_UUID)) self._project_config = Path(configuration.get_value(ConfigurationVariable.PROJECT_CONFIG)) self._project_source = self._project_root.joinpath(configuration.get_value(ConfigurationVariable.SOURCE_DIR)) self._package_metadata: PackageMetadata = package_metadata self._is_dependency: bool = is_dependency self._other_document_references: List[DependencySpdxDocumentRef] = other_document_refs self._document_namespace = document_namespace self._spdx_package: Optional[SpdxPackage] = None @property def document_name(self) -> str: """Gets document name. See https://spdx.org/spdx-specification-21-web-version#h.wape5vaqknj2 Returns: corresponding string """ return f"{self.name}-{self.version}" @property def document_namespace(self) -> str: """Gets document namespace. See https://spdx.org/spdx-specification-21-web-version#h.1gdfkutofa90 Returns: corresponding string """ if self._document_namespace: return self._document_namespace return self._generate_namespace() def _generate_namespace(self) -> str: """Generates a document namespace.""" if self._is_dependency: url_base = "http://spdx.org/spdxdocs" uuid = generate_uuid_based_on_str(self.document_name) return f"{url_base}/{self.document_name}-{uuid}" return get_project_namespace(self._project_config, self.document_name) @property def name(self) -> str: """Gets package's name. Returns: corresponding string """ return f"{self._package_metadata.name}" @property def version(self) -> str: """Gets package version. Returns: package version """ return self._package_metadata.version @property def licence(self) -> str: """Gets the project's licence. Returns: project's licence """ return self._package_metadata.licence @property def author(self) -> str: """Gets the document's author. Returns: document's author """ return self._package_metadata.author @property def author_email(self) -> str: """Gets the document author's email. Returns: document author's email """ return self._package_metadata.author_email @property def organisation(self) -> str: """Gets the organisation. Returns: the organisation in charge """ return str(configuration.get_value(ConfigurationVariable.ORGANISATION)) @property def organisation_email(self) -> str: """Gets the organisation's email. Returns: organisation's email """ return str(configuration.get_value(ConfigurationVariable.ORGANISATION_EMAIL)) @property def tool_name(self) -> str: """Gets this generation tool's name. Returns: this tool's name """ return TOOL_NAME @property def reviewer(self) -> str: """Gets the document's reviewer. Returns: document's reviewer """ return str(configuration.get_value(ConfigurationVariable.BOT_USERNAME)) @property def reviewer_email(self) -> str: """Gets the document reviewer's email. Returns: document reviewer's email """ return str(configuration.get_value(ConfigurationVariable.BOT_EMAIL)) @property def external_refs(self) -> List[DependencySpdxDocumentRef]: """Gets the document external references. Returns: the list of external references """ return self._other_document_references @external_refs.setter def external_refs(self, external_refs: List[DependencySpdxDocumentRef]) -> None: """Sets the document external references.""" self._other_document_references = external_refs def generate_spdx_package(self) -> SpdxPackage: """Generates the SPDX package for this package. Returns: corresponding SPDX package. """ if not self._spdx_package: self._spdx_package = SpdxPackage( PackageInfo( metadata=self._package_metadata, root_dir=self._project_root, source_dir=self._project_source, uuid=self._project_uuid, ), is_dependency=self._is_dependency, ) return self._spdx_package def generate_spdx_document(self) -> Document: """Generates the SPDX document. Example of SPDX document section. SPDXVersion: SPDX-2.1 DataLicense: CC0-1.0 SPDXID: SPDXRef-DOCUMENT DocumentName: mbed-targets DocumentNamespace: http://spdx.org/spdxdocs/spdx-v2.1-3c4714e6-a7b1-4574-abb8-861149cbc590 Creator: Person: Anonymous () Creator: Organization: Anonymous () Creator: Tool: reuse-0.8.0 Created: 2020-01-20T17:53:41Z CreatorComment: <text> This document was created automatically using available reuse information consistent with REUSE. </text> Returns: the corresponding document """ doc = Document() doc.version = Version(1, 2) doc.name = determine_spdx_value(self.document_name) doc.namespace = determine_spdx_value(self.document_namespace) doc.spdx_id = "SPDXRef-DOCUMENT" doc.comment = determine_spdx_value( "This document was created automatically using available information from python packages." ) doc.data_license = License.from_identifier("CC0-1.0") doc.creation_info.add_creator(Person(self.author, self.author_email)) if not self._is_dependency: doc.creation_info.add_creator(Organization(self.organisation, self.organisation_email)) doc.creation_info.add_creator(Tool(self.tool_name)) doc.creation_info.set_created_now() if not self._is_dependency: review = Review(Person(determine_spdx_value(self.reviewer), determine_spdx_value(self.reviewer_email))) review.set_review_date_now() doc.add_review(review) # FIXME with current tooling and specification, only one package can # be described in a file and hence, all dependencies are described # in separate files. Find out what to do with dependencies when new # tools are released as it is not entirely clear in the specification doc.package = self.generate_spdx_package().generate_spdx_package() for external_reference in self.external_refs: doc.add_ext_document_reference(external_reference.generate_external_reference()) return doc
Instance variables
-
Gets the document's author.
Returns
document's author
Expand source code
@property def author(self) -> str: """Gets the document's author. Returns: document's author """ return self._package_metadata.author
-
Gets the document author's email.
Returns
document author's email
Expand source code
@property def author_email(self) -> str: """Gets the document author's email. Returns: document author's email """ return self._package_metadata.author_email
var document_name : str
-
Gets document name.
See https://spdx.org/spdx-specification-21-web-version#h.wape5vaqknj2
Returns
corresponding string
Expand source code
@property def document_name(self) -> str: """Gets document name. See https://spdx.org/spdx-specification-21-web-version#h.wape5vaqknj2 Returns: corresponding string """ return f"{self.name}-{self.version}"
var document_namespace : str
-
Gets document namespace.
See https://spdx.org/spdx-specification-21-web-version#h.1gdfkutofa90
Returns
corresponding string
Expand source code
@property def document_namespace(self) -> str: """Gets document namespace. See https://spdx.org/spdx-specification-21-web-version#h.1gdfkutofa90 Returns: corresponding string """ if self._document_namespace: return self._document_namespace return self._generate_namespace()
var external_refs : List[DependencySpdxDocumentRef]
-
Gets the document external references.
Returns
the list of external references
Expand source code
@property def external_refs(self) -> List[DependencySpdxDocumentRef]: """Gets the document external references. Returns: the list of external references """ return self._other_document_references
var licence : str
-
Gets the project's licence.
Returns
project's licence
Expand source code
@property def licence(self) -> str: """Gets the project's licence. Returns: project's licence """ return self._package_metadata.licence
var name : str
-
Gets package's name.
Returns
corresponding string
Expand source code
@property def name(self) -> str: """Gets package's name. Returns: corresponding string """ return f"{self._package_metadata.name}"
var organisation : str
-
Gets the organisation.
Returns
the organisation in charge
Expand source code
@property def organisation(self) -> str: """Gets the organisation. Returns: the organisation in charge """ return str(configuration.get_value(ConfigurationVariable.ORGANISATION))
var organisation_email : str
-
Gets the organisation's email.
Returns
organisation's email
Expand source code
@property def organisation_email(self) -> str: """Gets the organisation's email. Returns: organisation's email """ return str(configuration.get_value(ConfigurationVariable.ORGANISATION_EMAIL))
var reviewer : str
-
Gets the document's reviewer.
Returns
document's reviewer
Expand source code
@property def reviewer(self) -> str: """Gets the document's reviewer. Returns: document's reviewer """ return str(configuration.get_value(ConfigurationVariable.BOT_USERNAME))
var reviewer_email : str
-
Gets the document reviewer's email.
Returns
document reviewer's email
Expand source code
@property def reviewer_email(self) -> str: """Gets the document reviewer's email. Returns: document reviewer's email """ return str(configuration.get_value(ConfigurationVariable.BOT_EMAIL))
var tool_name : str
-
Gets this generation tool's name.
Returns
this tool's name
Expand source code
@property def tool_name(self) -> str: """Gets this generation tool's name. Returns: this tool's name """ return TOOL_NAME
var version : str
-
Gets package version.
Returns
package version
Expand source code
@property def version(self) -> str: """Gets package version. Returns: package version """ return self._package_metadata.version
Methods
def generate_spdx_document(self) ‑> spdx.document.Document
-
Generates the SPDX document.
Example of SPDX document section. SPDXVersion: SPDX-2.1 DataLicense: CC0-1.0 SPDXID: SPDXRef-DOCUMENT DocumentName: mbed-targets DocumentNamespace: http://spdx.org/spdxdocs/spdx-v2.1-3c4714e6-a7b1-4574-abb8-861149cbc590 Creator: Person: Anonymous () Creator: Organization: Anonymous () Creator: Tool: reuse-0.8.0 Created: 2020-01-20T17:53:41Z CreatorComment:
This document was created automatically using available reuse information consistent with REUSE. Returns
the corresponding document
Expand source code
def generate_spdx_document(self) -> Document: """Generates the SPDX document. Example of SPDX document section. SPDXVersion: SPDX-2.1 DataLicense: CC0-1.0 SPDXID: SPDXRef-DOCUMENT DocumentName: mbed-targets DocumentNamespace: http://spdx.org/spdxdocs/spdx-v2.1-3c4714e6-a7b1-4574-abb8-861149cbc590 Creator: Person: Anonymous () Creator: Organization: Anonymous () Creator: Tool: reuse-0.8.0 Created: 2020-01-20T17:53:41Z CreatorComment: <text> This document was created automatically using available reuse information consistent with REUSE. </text> Returns: the corresponding document """ doc = Document() doc.version = Version(1, 2) doc.name = determine_spdx_value(self.document_name) doc.namespace = determine_spdx_value(self.document_namespace) doc.spdx_id = "SPDXRef-DOCUMENT" doc.comment = determine_spdx_value( "This document was created automatically using available information from python packages." ) doc.data_license = License.from_identifier("CC0-1.0") doc.creation_info.add_creator(Person(self.author, self.author_email)) if not self._is_dependency: doc.creation_info.add_creator(Organization(self.organisation, self.organisation_email)) doc.creation_info.add_creator(Tool(self.tool_name)) doc.creation_info.set_created_now() if not self._is_dependency: review = Review(Person(determine_spdx_value(self.reviewer), determine_spdx_value(self.reviewer_email))) review.set_review_date_now() doc.add_review(review) # FIXME with current tooling and specification, only one package can # be described in a file and hence, all dependencies are described # in separate files. Find out what to do with dependencies when new # tools are released as it is not entirely clear in the specification doc.package = self.generate_spdx_package().generate_spdx_package() for external_reference in self.external_refs: doc.add_ext_document_reference(external_reference.generate_external_reference()) return doc
def generate_spdx_package(self) ‑> SpdxPackage
-
Generates the SPDX package for this package.
Returns
corresponding SPDX package.
Expand source code
def generate_spdx_package(self) -> SpdxPackage: """Generates the SPDX package for this package. Returns: corresponding SPDX package. """ if not self._spdx_package: self._spdx_package = SpdxPackage( PackageInfo( metadata=self._package_metadata, root_dir=self._project_root, source_dir=self._project_source, uuid=self._project_uuid, ), is_dependency=self._is_dependency, ) return self._spdx_package
-