forked from spdx/tools-python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathspdx2_document_from_scratch.py
145 lines (129 loc) · 6.04 KB
/
spdx2_document_from_scratch.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# SPDX-FileCopyrightText: 2023 spdx contributors
#
# SPDX-License-Identifier: Apache-2.0
import logging
from datetime import datetime
from typing import List
from spdx_tools.common.spdx_licensing import 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", "[email protected]")],
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", "[email protected]"),
originator=Actor(ActorType.ORGANIZATION, "some organization", "[email protected]"),
files_analyzed=True,
verification_code=PackageVerificationCode(
value="d6a770ba38583ed4bb4525bd96e50461655d2758", excluded_files=["./some.file"]
),
checksums=[
Checksum(ChecksumAlgorithm.SHA1, "d6a770ba38583ed4bb4525bd96e50461655d2758"),
Checksum(ChecksumAlgorithm.MD5, "624c1abb3664f4b35547e7c73864ad24"),
],
license_concluded=spdx_licensing.parse("GPL-2.0-only OR MIT"),
license_info_from_files=[spdx_licensing.parse("GPL-2.0-only"), spdx_licensing.parse("MIT")],
license_declared=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=spdx_licensing.parse("MIT"),
license_info_in_file=[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=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]
document.files += [file1, file2]
# 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")