// 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 }