167 lines
5.7 KiB
Go
167 lines
5.7 KiB
Go
|
|
// Package spdxlib contains convenience and utility functions for working
|
||
|
|
// with an SPDX document that has already been created in memory.
|
||
|
|
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
|
||
|
|
package spdxlib
|
||
|
|
|
||
|
|
import (
|
||
|
|
"fmt"
|
||
|
|
|
||
|
|
"github.com/spdx/tools-golang/spdx/common"
|
||
|
|
"github.com/spdx/tools-golang/spdx/v2_1"
|
||
|
|
"github.com/spdx/tools-golang/spdx/v2_2"
|
||
|
|
"github.com/spdx/tools-golang/spdx/v2_3"
|
||
|
|
)
|
||
|
|
|
||
|
|
// GetDescribedPackageIDs2_1 returns a slice of ElementIDs for all Packages
|
||
|
|
// in this Document that it "describes," according to SPDX rules:
|
||
|
|
// - If the document has only one Package, its ID is returned.
|
||
|
|
// - If the document has 2+ Packages, it returns the IDs of those that have
|
||
|
|
// a DESCRIBES (or DESCRIBED_BY) relationship to this DOCUMENT.
|
||
|
|
func GetDescribedPackageIDs2_1(doc *v2_1.Document) ([]common.ElementID, error) {
|
||
|
|
// if nil Packages map or zero packages in it, return empty slice
|
||
|
|
if doc.Packages == nil {
|
||
|
|
return nil, fmt.Errorf("Packages map is nil")
|
||
|
|
}
|
||
|
|
if len(doc.Packages) == 0 {
|
||
|
|
return nil, fmt.Errorf("no Packages in Document")
|
||
|
|
}
|
||
|
|
if len(doc.Packages) == 1 {
|
||
|
|
// get first (only) one and return its ID
|
||
|
|
for _, pkg := range doc.Packages {
|
||
|
|
return []common.ElementID{pkg.PackageSPDXIdentifier}, nil
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// two or more packages, so we need to go through the relationships,
|
||
|
|
// find DESCRIBES or DESCRIBED_BY for this DOCUMENT, verify they are
|
||
|
|
// valid IDs in this document's packages, and return them
|
||
|
|
if doc.Relationships == nil {
|
||
|
|
return nil, fmt.Errorf("multiple Packages in Document but Relationships slice is nil")
|
||
|
|
}
|
||
|
|
|
||
|
|
eIDs, err := FilterRelationships2_1(doc, func(relationship *v2_1.Relationship) *common.ElementID {
|
||
|
|
refDocument := common.MakeDocElementID("", "DOCUMENT")
|
||
|
|
|
||
|
|
if relationship.Relationship == "DESCRIBES" && relationship.RefA == refDocument {
|
||
|
|
return &relationship.RefB.ElementRefID
|
||
|
|
} else if relationship.Relationship == "DESCRIBED_BY" && relationship.RefB == refDocument {
|
||
|
|
return &relationship.RefA.ElementRefID
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
})
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(eIDs) == 0 {
|
||
|
|
return nil, fmt.Errorf("no DESCRIBES or DESCRIBED_BY relationships found for this Document")
|
||
|
|
}
|
||
|
|
|
||
|
|
eIDs = SortElementIDs(eIDs)
|
||
|
|
|
||
|
|
return eIDs, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetDescribedPackageIDs2_2 returns a slice of ElementIDs for all Packages
|
||
|
|
// in this Document that it "describes," according to SPDX rules:
|
||
|
|
// - If the document has only one Package, its ID is returned.
|
||
|
|
// - If the document has 2+ Packages, it returns the IDs of those that have
|
||
|
|
// a DESCRIBES (or DESCRIBED_BY) relationship to this DOCUMENT.
|
||
|
|
func GetDescribedPackageIDs2_2(doc *v2_2.Document) ([]common.ElementID, error) {
|
||
|
|
// if nil Packages map or zero packages in it, return empty slice
|
||
|
|
if doc.Packages == nil {
|
||
|
|
return nil, fmt.Errorf("Packages map is nil")
|
||
|
|
}
|
||
|
|
if len(doc.Packages) == 0 {
|
||
|
|
return nil, fmt.Errorf("no Packages in Document")
|
||
|
|
}
|
||
|
|
if len(doc.Packages) == 1 {
|
||
|
|
// get first (only) one and return its ID
|
||
|
|
for _, pkg := range doc.Packages {
|
||
|
|
return []common.ElementID{pkg.PackageSPDXIdentifier}, nil
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// two or more packages, so we need to go through the relationships,
|
||
|
|
// find DESCRIBES or DESCRIBED_BY for this DOCUMENT, verify they are
|
||
|
|
// valid IDs in this document's packages, and return them
|
||
|
|
if doc.Relationships == nil {
|
||
|
|
return nil, fmt.Errorf("multiple Packages in Document but Relationships slice is nil")
|
||
|
|
}
|
||
|
|
|
||
|
|
eIDs, err := FilterRelationships2_2(doc, func(relationship *v2_2.Relationship) *common.ElementID {
|
||
|
|
refDocument := common.MakeDocElementID("", "DOCUMENT")
|
||
|
|
|
||
|
|
if relationship.Relationship == "DESCRIBES" && relationship.RefA == refDocument {
|
||
|
|
return &relationship.RefB.ElementRefID
|
||
|
|
} else if relationship.Relationship == "DESCRIBED_BY" && relationship.RefB == refDocument {
|
||
|
|
return &relationship.RefA.ElementRefID
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
})
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(eIDs) == 0 {
|
||
|
|
return nil, fmt.Errorf("no DESCRIBES or DESCRIBED_BY relationships found for this Document")
|
||
|
|
}
|
||
|
|
|
||
|
|
eIDs = SortElementIDs(eIDs)
|
||
|
|
|
||
|
|
return eIDs, nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// GetDescribedPackageIDs2_3 returns a slice of ElementIDs for all Packages
|
||
|
|
// in this Document that it "describes," according to SPDX rules:
|
||
|
|
// - If the document has only one Package, its ID is returned.
|
||
|
|
// - If the document has 2+ Packages, it returns the IDs of those that have
|
||
|
|
// a DESCRIBES (or DESCRIBED_BY) relationship to this DOCUMENT.
|
||
|
|
func GetDescribedPackageIDs2_3(doc *v2_3.Document) ([]common.ElementID, error) {
|
||
|
|
// if nil Packages map or zero packages in it, return empty slice
|
||
|
|
if doc.Packages == nil {
|
||
|
|
return nil, fmt.Errorf("Packages map is nil")
|
||
|
|
}
|
||
|
|
if len(doc.Packages) == 0 {
|
||
|
|
return nil, fmt.Errorf("no Packages in Document")
|
||
|
|
}
|
||
|
|
if len(doc.Packages) == 1 {
|
||
|
|
// get first (only) one and return its ID
|
||
|
|
for _, pkg := range doc.Packages {
|
||
|
|
return []common.ElementID{pkg.PackageSPDXIdentifier}, nil
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// two or more packages, so we need to go through the relationships,
|
||
|
|
// find DESCRIBES or DESCRIBED_BY for this DOCUMENT, verify they are
|
||
|
|
// valid IDs in this document's packages, and return them
|
||
|
|
if doc.Relationships == nil {
|
||
|
|
return nil, fmt.Errorf("multiple Packages in Document but Relationships slice is nil")
|
||
|
|
}
|
||
|
|
|
||
|
|
eIDs, err := FilterRelationships2_3(doc, func(relationship *v2_3.Relationship) *common.ElementID {
|
||
|
|
refDocument := common.MakeDocElementID("", "DOCUMENT")
|
||
|
|
|
||
|
|
if relationship.Relationship == "DESCRIBES" && relationship.RefA == refDocument {
|
||
|
|
return &relationship.RefB.ElementRefID
|
||
|
|
} else if relationship.Relationship == "DESCRIBED_BY" && relationship.RefB == refDocument {
|
||
|
|
return &relationship.RefA.ElementRefID
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
})
|
||
|
|
if err != nil {
|
||
|
|
return nil, err
|
||
|
|
}
|
||
|
|
|
||
|
|
if len(eIDs) == 0 {
|
||
|
|
return nil, fmt.Errorf("no DESCRIBES or DESCRIBED_BY relationships found for this Document")
|
||
|
|
}
|
||
|
|
|
||
|
|
eIDs = SortElementIDs(eIDs)
|
||
|
|
|
||
|
|
return eIDs, nil
|
||
|
|
}
|