1*ba677afaSXin Li// Package spdxlib contains convenience and utility functions for working 2*ba677afaSXin Li// with an SPDX document that has already been created in memory. 3*ba677afaSXin Li// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 4*ba677afaSXin Lipackage spdxlib 5*ba677afaSXin Li 6*ba677afaSXin Liimport ( 7*ba677afaSXin Li "fmt" 8*ba677afaSXin Li 9*ba677afaSXin Li "github.com/spdx/tools-golang/spdx/common" 10*ba677afaSXin Li "github.com/spdx/tools-golang/spdx/v2_1" 11*ba677afaSXin Li "github.com/spdx/tools-golang/spdx/v2_2" 12*ba677afaSXin Li "github.com/spdx/tools-golang/spdx/v2_3" 13*ba677afaSXin Li) 14*ba677afaSXin Li 15*ba677afaSXin Li// GetDescribedPackageIDs2_1 returns a slice of ElementIDs for all Packages 16*ba677afaSXin Li// in this Document that it "describes," according to SPDX rules: 17*ba677afaSXin Li// - If the document has only one Package, its ID is returned. 18*ba677afaSXin Li// - If the document has 2+ Packages, it returns the IDs of those that have 19*ba677afaSXin Li// a DESCRIBES (or DESCRIBED_BY) relationship to this DOCUMENT. 20*ba677afaSXin Lifunc GetDescribedPackageIDs2_1(doc *v2_1.Document) ([]common.ElementID, error) { 21*ba677afaSXin Li // if nil Packages map or zero packages in it, return empty slice 22*ba677afaSXin Li if doc.Packages == nil { 23*ba677afaSXin Li return nil, fmt.Errorf("Packages map is nil") 24*ba677afaSXin Li } 25*ba677afaSXin Li if len(doc.Packages) == 0 { 26*ba677afaSXin Li return nil, fmt.Errorf("no Packages in Document") 27*ba677afaSXin Li } 28*ba677afaSXin Li if len(doc.Packages) == 1 { 29*ba677afaSXin Li // get first (only) one and return its ID 30*ba677afaSXin Li for _, pkg := range doc.Packages { 31*ba677afaSXin Li return []common.ElementID{pkg.PackageSPDXIdentifier}, nil 32*ba677afaSXin Li } 33*ba677afaSXin Li } 34*ba677afaSXin Li 35*ba677afaSXin Li // two or more packages, so we need to go through the relationships, 36*ba677afaSXin Li // find DESCRIBES or DESCRIBED_BY for this DOCUMENT, verify they are 37*ba677afaSXin Li // valid IDs in this document's packages, and return them 38*ba677afaSXin Li if doc.Relationships == nil { 39*ba677afaSXin Li return nil, fmt.Errorf("multiple Packages in Document but Relationships slice is nil") 40*ba677afaSXin Li } 41*ba677afaSXin Li 42*ba677afaSXin Li eIDs, err := FilterRelationships2_1(doc, func(relationship *v2_1.Relationship) *common.ElementID { 43*ba677afaSXin Li refDocument := common.MakeDocElementID("", "DOCUMENT") 44*ba677afaSXin Li 45*ba677afaSXin Li if relationship.Relationship == "DESCRIBES" && relationship.RefA == refDocument { 46*ba677afaSXin Li return &relationship.RefB.ElementRefID 47*ba677afaSXin Li } else if relationship.Relationship == "DESCRIBED_BY" && relationship.RefB == refDocument { 48*ba677afaSXin Li return &relationship.RefA.ElementRefID 49*ba677afaSXin Li } 50*ba677afaSXin Li 51*ba677afaSXin Li return nil 52*ba677afaSXin Li }) 53*ba677afaSXin Li if err != nil { 54*ba677afaSXin Li return nil, err 55*ba677afaSXin Li } 56*ba677afaSXin Li 57*ba677afaSXin Li if len(eIDs) == 0 { 58*ba677afaSXin Li return nil, fmt.Errorf("no DESCRIBES or DESCRIBED_BY relationships found for this Document") 59*ba677afaSXin Li } 60*ba677afaSXin Li 61*ba677afaSXin Li eIDs = SortElementIDs(eIDs) 62*ba677afaSXin Li 63*ba677afaSXin Li return eIDs, nil 64*ba677afaSXin Li} 65*ba677afaSXin Li 66*ba677afaSXin Li// GetDescribedPackageIDs2_2 returns a slice of ElementIDs for all Packages 67*ba677afaSXin Li// in this Document that it "describes," according to SPDX rules: 68*ba677afaSXin Li// - If the document has only one Package, its ID is returned. 69*ba677afaSXin Li// - If the document has 2+ Packages, it returns the IDs of those that have 70*ba677afaSXin Li// a DESCRIBES (or DESCRIBED_BY) relationship to this DOCUMENT. 71*ba677afaSXin Lifunc GetDescribedPackageIDs2_2(doc *v2_2.Document) ([]common.ElementID, error) { 72*ba677afaSXin Li // if nil Packages map or zero packages in it, return empty slice 73*ba677afaSXin Li if doc.Packages == nil { 74*ba677afaSXin Li return nil, fmt.Errorf("Packages map is nil") 75*ba677afaSXin Li } 76*ba677afaSXin Li if len(doc.Packages) == 0 { 77*ba677afaSXin Li return nil, fmt.Errorf("no Packages in Document") 78*ba677afaSXin Li } 79*ba677afaSXin Li if len(doc.Packages) == 1 { 80*ba677afaSXin Li // get first (only) one and return its ID 81*ba677afaSXin Li for _, pkg := range doc.Packages { 82*ba677afaSXin Li return []common.ElementID{pkg.PackageSPDXIdentifier}, nil 83*ba677afaSXin Li } 84*ba677afaSXin Li } 85*ba677afaSXin Li 86*ba677afaSXin Li // two or more packages, so we need to go through the relationships, 87*ba677afaSXin Li // find DESCRIBES or DESCRIBED_BY for this DOCUMENT, verify they are 88*ba677afaSXin Li // valid IDs in this document's packages, and return them 89*ba677afaSXin Li if doc.Relationships == nil { 90*ba677afaSXin Li return nil, fmt.Errorf("multiple Packages in Document but Relationships slice is nil") 91*ba677afaSXin Li } 92*ba677afaSXin Li 93*ba677afaSXin Li eIDs, err := FilterRelationships2_2(doc, func(relationship *v2_2.Relationship) *common.ElementID { 94*ba677afaSXin Li refDocument := common.MakeDocElementID("", "DOCUMENT") 95*ba677afaSXin Li 96*ba677afaSXin Li if relationship.Relationship == "DESCRIBES" && relationship.RefA == refDocument { 97*ba677afaSXin Li return &relationship.RefB.ElementRefID 98*ba677afaSXin Li } else if relationship.Relationship == "DESCRIBED_BY" && relationship.RefB == refDocument { 99*ba677afaSXin Li return &relationship.RefA.ElementRefID 100*ba677afaSXin Li } 101*ba677afaSXin Li 102*ba677afaSXin Li return nil 103*ba677afaSXin Li }) 104*ba677afaSXin Li if err != nil { 105*ba677afaSXin Li return nil, err 106*ba677afaSXin Li } 107*ba677afaSXin Li 108*ba677afaSXin Li if len(eIDs) == 0 { 109*ba677afaSXin Li return nil, fmt.Errorf("no DESCRIBES or DESCRIBED_BY relationships found for this Document") 110*ba677afaSXin Li } 111*ba677afaSXin Li 112*ba677afaSXin Li eIDs = SortElementIDs(eIDs) 113*ba677afaSXin Li 114*ba677afaSXin Li return eIDs, nil 115*ba677afaSXin Li} 116*ba677afaSXin Li 117*ba677afaSXin Li// GetDescribedPackageIDs2_3 returns a slice of ElementIDs for all Packages 118*ba677afaSXin Li// in this Document that it "describes," according to SPDX rules: 119*ba677afaSXin Li// - If the document has only one Package, its ID is returned. 120*ba677afaSXin Li// - If the document has 2+ Packages, it returns the IDs of those that have 121*ba677afaSXin Li// a DESCRIBES (or DESCRIBED_BY) relationship to this DOCUMENT. 122*ba677afaSXin Lifunc GetDescribedPackageIDs2_3(doc *v2_3.Document) ([]common.ElementID, error) { 123*ba677afaSXin Li // if nil Packages map or zero packages in it, return empty slice 124*ba677afaSXin Li if doc.Packages == nil { 125*ba677afaSXin Li return nil, fmt.Errorf("Packages map is nil") 126*ba677afaSXin Li } 127*ba677afaSXin Li if len(doc.Packages) == 0 { 128*ba677afaSXin Li return nil, fmt.Errorf("no Packages in Document") 129*ba677afaSXin Li } 130*ba677afaSXin Li if len(doc.Packages) == 1 { 131*ba677afaSXin Li // get first (only) one and return its ID 132*ba677afaSXin Li for _, pkg := range doc.Packages { 133*ba677afaSXin Li return []common.ElementID{pkg.PackageSPDXIdentifier}, nil 134*ba677afaSXin Li } 135*ba677afaSXin Li } 136*ba677afaSXin Li 137*ba677afaSXin Li // two or more packages, so we need to go through the relationships, 138*ba677afaSXin Li // find DESCRIBES or DESCRIBED_BY for this DOCUMENT, verify they are 139*ba677afaSXin Li // valid IDs in this document's packages, and return them 140*ba677afaSXin Li if doc.Relationships == nil { 141*ba677afaSXin Li return nil, fmt.Errorf("multiple Packages in Document but Relationships slice is nil") 142*ba677afaSXin Li } 143*ba677afaSXin Li 144*ba677afaSXin Li eIDs, err := FilterRelationships2_3(doc, func(relationship *v2_3.Relationship) *common.ElementID { 145*ba677afaSXin Li refDocument := common.MakeDocElementID("", "DOCUMENT") 146*ba677afaSXin Li 147*ba677afaSXin Li if relationship.Relationship == "DESCRIBES" && relationship.RefA == refDocument { 148*ba677afaSXin Li return &relationship.RefB.ElementRefID 149*ba677afaSXin Li } else if relationship.Relationship == "DESCRIBED_BY" && relationship.RefB == refDocument { 150*ba677afaSXin Li return &relationship.RefA.ElementRefID 151*ba677afaSXin Li } 152*ba677afaSXin Li 153*ba677afaSXin Li return nil 154*ba677afaSXin Li }) 155*ba677afaSXin Li if err != nil { 156*ba677afaSXin Li return nil, err 157*ba677afaSXin Li } 158*ba677afaSXin Li 159*ba677afaSXin Li if len(eIDs) == 0 { 160*ba677afaSXin Li return nil, fmt.Errorf("no DESCRIBES or DESCRIBED_BY relationships found for this Document") 161*ba677afaSXin Li } 162*ba677afaSXin Li 163*ba677afaSXin Li eIDs = SortElementIDs(eIDs) 164*ba677afaSXin Li 165*ba677afaSXin Li return eIDs, nil 166*ba677afaSXin Li} 167