blob: a41471eda9cd711b4ea72af51651939afdf9b253 [file] [log] [blame]
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
package v2_2
import (
"encoding/json"
"strings"
"github.com/spdx/tools-golang/json/marshal"
"github.com/spdx/tools-golang/spdx/v2/common"
)
// Package is a Package section of an SPDX Document for version 2.2 of the spec.
type Package struct {
// NOT PART OF SPEC
// flag: does this "package" contain files that were in fact "unpackaged",
// e.g. included directly in the Document without being in a Package?
IsUnpackaged bool `json:"-"`
// 7.1: Package Name
// Cardinality: mandatory, one
PackageName string `json:"name"`
// 7.2: Package SPDX Identifier: "SPDXRef-[idstring]"
// Cardinality: mandatory, one
PackageSPDXIdentifier common.ElementID `json:"SPDXID"`
// 7.3: Package Version
// Cardinality: optional, one
PackageVersion string `json:"versionInfo,omitempty"`
// 7.4: Package File Name
// Cardinality: optional, one
PackageFileName string `json:"packageFileName,omitempty"`
// 7.5: Package Supplier: may have single result for either Person or Organization,
// or NOASSERTION
// Cardinality: optional, one
PackageSupplier *common.Supplier `json:"supplier,omitempty"`
// 7.6: Package Originator: may have single result for either Person or Organization,
// or NOASSERTION
// Cardinality: optional, one
PackageOriginator *common.Originator `json:"originator,omitempty"`
// 7.7: Package Download Location
// Cardinality: mandatory, one
PackageDownloadLocation string `json:"downloadLocation"`
// 7.8: FilesAnalyzed
// Cardinality: optional, one; default value is "true" if omitted
FilesAnalyzed bool `json:"filesAnalyzed"`
// NOT PART OF SPEC: did FilesAnalyzed tag appear?
IsFilesAnalyzedTagPresent bool `json:"-"`
// 7.9: Package Verification Code
PackageVerificationCode common.PackageVerificationCode `json:"packageVerificationCode,omitempty"`
// 7.10: Package Checksum: may have keys for SHA1, SHA256, SHA512 and/or MD5
// Cardinality: optional, one or many
PackageChecksums []common.Checksum `json:"checksums,omitempty"`
// 7.11: Package Home Page
// Cardinality: optional, one
PackageHomePage string `json:"homepage,omitempty"`
// 7.12: Source Information
// Cardinality: optional, one
PackageSourceInfo string `json:"sourceInfo,omitempty"`
// 7.13: Concluded License: SPDX License Expression, "NONE" or "NOASSERTION"
// Cardinality: mandatory, one
PackageLicenseConcluded string `json:"licenseConcluded"`
// 7.14: All Licenses Info from Files: SPDX License Expression, "NONE" or "NOASSERTION"
// Cardinality: mandatory, one or many if filesAnalyzed is true / omitted;
// zero (must be omitted) if filesAnalyzed is false
PackageLicenseInfoFromFiles []string `json:"licenseInfoFromFiles,omitempty"`
// 7.15: Declared License: SPDX License Expression, "NONE" or "NOASSERTION"
// Cardinality: mandatory, one
PackageLicenseDeclared string `json:"licenseDeclared"`
// 7.16: Comments on License
// Cardinality: optional, one
PackageLicenseComments string `json:"licenseComments,omitempty"`
// 7.17: Copyright Text: copyright notice(s) text, "NONE" or "NOASSERTION"
// Cardinality: mandatory, one
PackageCopyrightText string `json:"copyrightText"`
// 7.18: Package Summary Description
// Cardinality: optional, one
PackageSummary string `json:"summary,omitempty"`
// 7.19: Package Detailed Description
// Cardinality: optional, one
PackageDescription string `json:"description,omitempty"`
// 7.20: Package Comment
// Cardinality: optional, one
PackageComment string `json:"comment,omitempty"`
// 7.21: Package External Reference
// Cardinality: optional, one or many
PackageExternalReferences []*PackageExternalReference `json:"externalRefs,omitempty"`
// 7.22: Package External Reference Comment
// Cardinality: conditional (optional, one) for each External Reference
// contained within PackageExternalReference struct, if present
// 7.23: Package Attribution Text
// Cardinality: optional, one or many
PackageAttributionTexts []string `json:"attributionTexts,omitempty"`
// Files contained in this Package
Files []*File `json:"files,omitempty"`
Annotations []Annotation `json:"annotations,omitempty"`
// this field is only used when decoding JSON to translate the hasFiles
// property to relationships
hasFiles []common.DocElementID
}
func (p Package) MarshalJSON() ([]byte, error) {
type pkg Package
p2 := pkg(p)
data, err := marshal.JSON(p2)
if err != nil {
return nil, err
}
// remove empty packageVerificationCode entries -- required by SPDX 2.2 but
// omitempty has no effect since it is a non-comparable struct and not a pointer, so we
// manually check to determine if there is a valid value to output and omit the field if not
// see: https://spdx.github.io/spdx-spec/v2.2.2/package-information/#79-package-verification-code-field
if p.PackageVerificationCode.Value == "" && p.PackageVerificationCode.ExcludedFiles == nil {
var values map[string]interface{}
err = json.Unmarshal(data, &values)
if err != nil {
return nil, err
}
delete(values, "packageVerificationCode")
return marshal.JSON(values)
}
return data, nil
}
func (p *Package) UnmarshalJSON(b []byte) error {
type pkg Package
type extras struct {
HasFiles []common.DocElementID `json:"hasFiles"`
FilesAnalyzed *bool `json:"filesAnalyzed"`
}
var p2 pkg
if err := json.Unmarshal(b, &p2); err != nil {
return err
}
var e extras
if err := json.Unmarshal(b, &e); err != nil {
return err
}
*p = Package(p2)
p.hasFiles = e.HasFiles
// FilesAnalyzed defaults to true if omitted
if e.FilesAnalyzed == nil {
p.FilesAnalyzed = true
} else {
p.IsFilesAnalyzedTagPresent = true
}
return nil
}
var _ json.Unmarshaler = (*Package)(nil)
var _ json.Marshaler = (*Package)(nil)
// PackageExternalReference is an External Reference to additional info
// about a Package, as defined in section 7.21 in version 2.2 of the spec.
type PackageExternalReference struct {
// category is "SECURITY", "PACKAGE-MANAGER" or "OTHER"
Category string `json:"referenceCategory"`
// type is an [idstring] as defined in Appendix VI;
// called RefType here due to "type" being a Golang keyword
RefType string `json:"referenceType"`
// locator is a unique string to access the package-specific
// info, metadata or content within the target location
Locator string `json:"referenceLocator"`
// 7.22: Package External Reference Comment
// Cardinality: conditional (optional, one) for each External Reference
ExternalRefComment string `json:"comment,omitempty"`
}
var _ json.Unmarshaler = (*PackageExternalReference)(nil)
func (r *PackageExternalReference) UnmarshalJSON(b []byte) error {
type ref PackageExternalReference
var rr ref
if err := json.Unmarshal(b, &rr); err != nil {
return err
}
*r = PackageExternalReference(rr)
r.Category = strings.ReplaceAll(r.Category, "_", "-")
return nil
}
var _ json.Marshaler = (*PackageExternalReference)(nil)
// We output as the JSON type enums since in v2.2.0 the JSON schema
// spec only had enums with _ (e.g. PACKAGE_MANAGER)
func (r *PackageExternalReference) MarshalJSON() ([]byte, error) {
type ref PackageExternalReference
var rr ref
rr = ref(*r)
rr.Category = strings.ReplaceAll(rr.Category, "-", "_")
return marshal.JSON(&rr)
}