diff options
Diffstat (limited to 'meta/lib/oe/spdx.py')
-rw-r--r-- | meta/lib/oe/spdx.py | 92 |
1 files changed, 89 insertions, 3 deletions
diff --git a/meta/lib/oe/spdx.py b/meta/lib/oe/spdx.py index 9814fbfd66..7aaf2af5ed 100644 --- a/meta/lib/oe/spdx.py +++ b/meta/lib/oe/spdx.py @@ -1,7 +1,21 @@ # +# Copyright OpenEmbedded Contributors +# # SPDX-License-Identifier: GPL-2.0-only # +# +# This library is intended to capture the JSON SPDX specification in a type +# safe manner. It is not intended to encode any particular OE specific +# behaviors, see the sbom.py for that. +# +# The documented SPDX spec document doesn't cover the JSON syntax for +# particular configuration, which can make it hard to determine what the JSON +# syntax should be. I've found it is actually much simpler to read the official +# SPDX JSON schema which can be found here: https://github.com/spdx/spdx-spec +# in schemas/spdx-schema.json +# + import hashlib import itertools import json @@ -9,7 +23,16 @@ import json SPDX_VERSION = "2.2" +# +# The following are the support classes that are used to implement SPDX object +# + class _Property(object): + """ + A generic SPDX object property. The different types will derive from this + class + """ + def __init__(self, *, default=None): self.default = default @@ -19,6 +42,10 @@ class _Property(object): class _String(_Property): + """ + A scalar string property for an SPDX object + """ + def __init__(self, **kwargs): super().__init__(**kwargs) @@ -39,6 +66,10 @@ class _String(_Property): class _Object(_Property): + """ + A scalar SPDX object property of a SPDX object + """ + def __init__(self, cls, **kwargs): super().__init__(**kwargs) self.cls = cls @@ -62,6 +93,10 @@ class _Object(_Property): class _ListProperty(_Property): + """ + A list of SPDX properties + """ + def __init__(self, prop, **kwargs): super().__init__(**kwargs) self.prop = prop @@ -72,26 +107,41 @@ class _ListProperty(_Property): obj._spdx[name] = [] return obj._spdx[name] + def set_helper(obj, value): + obj._spdx[name] = list(value) + def del_helper(obj): del obj._spdx[name] - attrs[name] = property(get_helper, None, del_helper) + attrs[name] = property(get_helper, set_helper, del_helper) def init(self, source): return [self.prop.init(o) for o in source] class _StringList(_ListProperty): + """ + A list of strings as a property for an SPDX object + """ + def __init__(self, **kwargs): super().__init__(_String(), **kwargs) class _ObjectList(_ListProperty): + """ + A list of SPDX objects as a property for an SPDX object + """ + def __init__(self, cls, **kwargs): super().__init__(_Object(cls), **kwargs) class MetaSPDXObject(type): + """ + A metaclass that allows properties (anything derived from a _Property + class) to be defined for a SPDX object + """ def __new__(mcls, name, bases, attrs): attrs["_properties"] = {} @@ -105,6 +155,9 @@ class MetaSPDXObject(type): class SPDXObject(metaclass=MetaSPDXObject): + """ + The base SPDX object; all SPDX spec classes must derive from this class + """ def __init__(self, **d): self._spdx = {} @@ -122,6 +175,21 @@ class SPDXObject(metaclass=MetaSPDXObject): return raise KeyError("%r is not a valid SPDX property" % name) +# +# These are the SPDX objects implemented from the spec. The *only* properties +# that can be added to these objects are ones directly specified in the SPDX +# spec, however you may add helper functions to make operations easier. +# +# Defaults should *only* be specified if the SPDX spec says there is a certain +# required value for a field (e.g. dataLicense), or if the field is mandatory +# and has some sane "this field is unknown" (e.g. "NOASSERTION") +# + +class SPDXAnnotation(SPDXObject): + annotationDate = _String() + annotationType = _String() + annotator = _String() + comment = _String() class SPDXChecksum(SPDXObject): algorithm = _String() @@ -133,6 +201,7 @@ class SPDXRelationship(SPDXObject): relatedSpdxElement = _String() relationshipType = _String() comment = _String() + annotations = _ObjectList(SPDXAnnotation) class SPDXExternalReference(SPDXObject): @@ -147,11 +216,23 @@ class SPDXPackageVerificationCode(SPDXObject): class SPDXPackage(SPDXObject): + ALLOWED_CHECKSUMS = [ + "SHA1", + "SHA224", + "SHA256", + "SHA384", + "SHA512", + "MD2", + "MD4", + "MD5", + "MD6", + ] + name = _String() SPDXID = _String() versionInfo = _String() downloadLocation = _String(default="NOASSERTION") - packageSupplier = _String(default="NOASSERTION") + supplier = _String(default="NOASSERTION") homepage = _String() licenseConcluded = _String(default="NOASSERTION") licenseDeclared = _String(default="NOASSERTION") @@ -164,6 +245,8 @@ class SPDXPackage(SPDXObject): packageVerificationCode = _Object(SPDXPackageVerificationCode) hasFiles = _StringList() packageFileName = _String() + annotations = _ObjectList(SPDXAnnotation) + checksums = _ObjectList(SPDXChecksum) class SPDXFile(SPDXObject): @@ -236,7 +319,7 @@ class SPDXDocument(SPDXObject): def from_json(cls, f): return cls(**json.load(f)) - def add_relationship(self, _from, relationship, _to, *, comment=None): + def add_relationship(self, _from, relationship, _to, *, comment=None, annotation=None): if isinstance(_from, SPDXObject): from_spdxid = _from.SPDXID else: @@ -256,6 +339,9 @@ class SPDXDocument(SPDXObject): if comment is not None: r.comment = comment + if annotation is not None: + r.annotations.append(annotation) + self.relationships.append(r) def find_by_spdxid(self, spdxid): |