Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[issue-593] add spdx2_document_from_scratch example
Signed-off-by: Armin Tänzer <armin.taenzer@tngtech.com>
- Loading branch information
1 parent
8d7d7b7
commit c1f0b1f
Showing
2 changed files
with
150 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
# SPDX-FileCopyrightText: 2023 spdx contributors | ||
# | ||
# SPDX-License-Identifier: Apache-2.0 | ||
import logging | ||
from datetime import datetime | ||
from typing import List | ||
|
||
from license_expression import get_spdx_licensing | ||
|
||
from spdx_tools.spdx.model import ( | ||
Actor, | ||
ActorType, | ||
Checksum, | ||
ChecksumAlgorithm, | ||
CreationInfo, | ||
Document, | ||
ExternalPackageRef, | ||
ExternalPackageRefCategory, | ||
File, | ||
FileType, | ||
Package, | ||
PackagePurpose, | ||
PackageVerificationCode, | ||
Relationship, | ||
RelationshipType, | ||
) | ||
from spdx_tools.spdx.validation.document_validator import validate_full_spdx_document | ||
from spdx_tools.spdx.validation.validation_message import ValidationMessage | ||
from spdx_tools.spdx.writer.write_anything import write_file | ||
|
||
# This example shows how to use the spdx-tools to create an SPDX document from scratch, | ||
# validate it and write it to a file. | ||
|
||
# First up, we need general information about the creation of the document, summarised by the CreationInfo class. | ||
creation_info = CreationInfo( | ||
spdx_version="SPDX-2.3", | ||
spdx_id="SPDXRef-DOCUMENT", | ||
name="document name", | ||
data_license="CC0-1.0", | ||
document_namespace="https://some.namespace", | ||
creators=[Actor(ActorType.PERSON, "Jane Doe", "jane.doe@example.com")], | ||
created=datetime(2022, 1, 1), | ||
) | ||
|
||
# creation_info is the only required property of the Document class (have a look there!), the rest are optional lists. | ||
# So, we are set up to create a new document instance. | ||
document = Document(creation_info) | ||
|
||
# The document currently does not describe anything. Let's create a package that we can add to it. | ||
# The Package class has quite a few properties (have a look there!), | ||
# but only name, spdx_id and download_location are mandatory in SPDX v2.3. | ||
package = Package( | ||
name="package name", | ||
spdx_id="SPDXRef-Package", | ||
download_location="https://download.com", | ||
version="2.2.1", | ||
file_name="./foo.bar", | ||
supplier=Actor(ActorType.PERSON, "Jane Doe", "jane.doe@example.com"), | ||
originator=Actor(ActorType.ORGANIZATION, "some organization", "contact@example.com"), | ||
files_analyzed=True, | ||
verification_code=PackageVerificationCode( | ||
value="d6a770ba38583ed4bb4525bd96e50461655d2758", excluded_files=["./some.file"] | ||
), | ||
checksums=[ | ||
Checksum(ChecksumAlgorithm.SHA1, "d6a770ba38583ed4bb4525bd96e50461655d2758"), | ||
Checksum(ChecksumAlgorithm.MD5, "624c1abb3664f4b35547e7c73864ad24"), | ||
], | ||
license_concluded=get_spdx_licensing().parse("GPL-2.0-only OR MIT"), | ||
license_info_from_files=[get_spdx_licensing().parse("GPL-2.0-only"), get_spdx_licensing().parse("MIT")], | ||
license_declared=get_spdx_licensing().parse("GPL-2.0-only AND MIT"), | ||
license_comment="license comment", | ||
copyright_text="Copyright 2022 Jane Doe", | ||
description="package description", | ||
attribution_texts=["package attribution"], | ||
primary_package_purpose=PackagePurpose.LIBRARY, | ||
release_date=datetime(2015, 1, 1), | ||
external_references=[ | ||
ExternalPackageRef( | ||
category=ExternalPackageRefCategory.OTHER, | ||
reference_type="http://reference.type", | ||
locator="reference/locator", | ||
comment="external reference comment", | ||
) | ||
], | ||
) | ||
|
||
# Now that we have a package defined, we can add it to the document's package property. | ||
document.packages = [package] | ||
|
||
# A DESCRIBES relationship asserts that the document indeed describes the package. | ||
describes_relationship = Relationship("SPDXRef-Document", RelationshipType.DESCRIBES, "SPDXRef-Package") | ||
document.relationships = [describes_relationship] | ||
|
||
# Let's add two files. Have a look at the file class for all possible properties a file can have. | ||
file1 = File( | ||
name="./package/file1.py", | ||
spdx_id="SPDXRef-File1", | ||
file_types=[FileType.SOURCE], | ||
checksums=[ | ||
Checksum(ChecksumAlgorithm.SHA1, "d6a770ba38583ed4bb4525bd96e50461655d2758"), | ||
Checksum(ChecksumAlgorithm.MD5, "624c1abb3664f4b35547e7c73864ad24"), | ||
], | ||
license_concluded=get_spdx_licensing().parse("MIT"), | ||
license_info_in_file=[get_spdx_licensing().parse("MIT")], | ||
copyright_text="Copyright 2022 Jane Doe", | ||
) | ||
file2 = File( | ||
name="./package/file2.py", | ||
spdx_id="SPDXRef-File2", | ||
checksums=[ | ||
Checksum(ChecksumAlgorithm.SHA1, "d6a770ba38583ed4bb4525bd96e50461655d2759"), | ||
], | ||
license_concluded=get_spdx_licensing().parse("GPL-2.0-only"), | ||
) | ||
|
||
# Assuming the package contains those two files, we create two CONTAINS relationships. | ||
contains_relationship1 = Relationship("SPDXRef-Package", RelationshipType.CONTAINS, "SPDXRef-File1") | ||
contains_relationship2 = Relationship("SPDXRef-Package", RelationshipType.CONTAINS, "SPDXRef-File2") | ||
|
||
# This library uses run-time type checks when assigning properties. | ||
# Because in-place alterations like .append() circumvent these checks, we don't use them here. | ||
document.relationships += [contains_relationship1, contains_relationship2] | ||
|
||
# We now have created a document with basic creation information, describing a package that contains two files. | ||
# You can also add Annotations, Snippets and ExtractedLicensingInfo to the document in an analogous manner to the above. | ||
# Have a look at their respective classes if you are unsure about their properties. | ||
|
||
|
||
# This library provides comprehensive validation against the SPDX specification. | ||
# Note that details of the validation depend on the SPDX version of the document. | ||
validation_messages: List[ValidationMessage] = validate_full_spdx_document(document) | ||
|
||
# You can have a look at each entry's message and context (like spdx_id, parent_id, full_element) | ||
# which will help you pinpoint the location of the invalidity. | ||
for message in validation_messages: | ||
logging.warning(message.validation_message) | ||
logging.warning(message.context) | ||
|
||
# If the document is valid, validation_messages will be empty. | ||
assert validation_messages == [] | ||
|
||
# Finally, we can serialize the document to any of the five supported formats. | ||
# Using the write_file() method from the write_anything module, | ||
# the format will be determined by the file ending: .spdx (tag-value), .json, .xml, .yaml. or .rdf (or .rdf.xml) | ||
write_file(document, "my_spdx_document.spdx.json") |