aboutsummaryrefslogtreecommitdiff
path: root/rdfloader/parser2v3/parse_package.go
diff options
context:
space:
mode:
authorSadaf Ebrahimi <sadafebrahimi@google.com>2023-01-26 18:29:15 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-01-26 18:29:15 +0000
commitb925feafab4bd54a2d608e4621a5210bc67d67c6 (patch)
tree6ea4841a079772cb06df5ec2cf99637f8d53805b /rdfloader/parser2v3/parse_package.go
parent5f73058e15df15ab2a35ca0c9d506b4fd0a83de7 (diff)
parent8dba382b59616b372f0ee6f95fe66c942bb790e0 (diff)
downloadspdx-tools-b925feafab4bd54a2d608e4621a5210bc67d67c6.tar.gz
Upgrade spdx-tools to v0.4.0 am: 75f88b4895 am: f12cf92582 am: 8dba382b59
Original change: https://android-review.googlesource.com/c/platform/external/spdx-tools/+/2401868 Change-Id: I14274d30850f3af3184815b3a3820b1f744d0a1f Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
Diffstat (limited to 'rdfloader/parser2v3/parse_package.go')
-rw-r--r--rdfloader/parser2v3/parse_package.go380
1 files changed, 380 insertions, 0 deletions
diff --git a/rdfloader/parser2v3/parse_package.go b/rdfloader/parser2v3/parse_package.go
new file mode 100644
index 0000000..0cdf68c
--- /dev/null
+++ b/rdfloader/parser2v3/parse_package.go
@@ -0,0 +1,380 @@
+// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
+
+package parser2v3
+
+import (
+ "fmt"
+ "strings"
+
+ gordfParser "github.com/spdx/gordf/rdfloader/parser"
+ "github.com/spdx/tools-golang/spdx/common"
+ "github.com/spdx/tools-golang/spdx/v2_3"
+)
+
+func (parser *rdfParser2_3) getPackageFromNode(packageNode *gordfParser.Node) (pkg *v2_3.Package, err error) {
+ pkg = &v2_3.Package{} // new package which will be returned
+
+ currState := parser.cache[packageNode.ID]
+ if currState == nil {
+ // there is no entry about the state of current package node.
+ // this is the first time we're seeing this node.
+ parser.cache[packageNode.ID] = &nodeState{
+ object: pkg,
+ Color: WHITE,
+ }
+ } else if currState.Color == GREY {
+ // we have already started parsing this package node and we needn't parse it again.
+ return currState.object.(*v2_3.Package), nil
+ }
+
+ // setting color of the state to grey to indicate that we've started to
+ // parse this node once.
+ parser.cache[packageNode.ID].Color = GREY
+
+ // setting state color to black to indicate when we're done parsing this node.
+ defer func() { parser.cache[packageNode.ID].Color = BLACK }()
+
+ // setting the SPDXIdentifier for the package.
+ eId, err := ExtractElementID(getLastPartOfURI(packageNode.ID))
+ if err != nil {
+ return nil, fmt.Errorf("error extracting elementID of a package identifier: %v", err)
+ }
+ pkg.PackageSPDXIdentifier = eId // 3.2
+
+ // check if we already have a package initialized for this ID
+ existingPackageIndex := -1
+ for ii, existingPkg := range parser.doc.Packages {
+ if existingPkg != nil && existingPkg.PackageSPDXIdentifier == eId {
+ existingPackageIndex = ii
+ pkg = existingPkg
+ break
+ }
+ }
+
+ // iterate over all the triples associated with the provided package packageNode.
+ for _, subTriple := range parser.nodeToTriples(packageNode) {
+ switch subTriple.Predicate.ID {
+ case RDF_TYPE:
+ // cardinality: exactly 1
+ continue
+ case SPDX_NAME: // 7.1
+ // cardinality: exactly 1
+ pkg.PackageName = subTriple.Object.ID
+ case SPDX_VERSION_INFO: // 7.3
+ // cardinality: max 1
+ pkg.PackageVersion = subTriple.Object.ID
+ case SPDX_PACKAGE_FILE_NAME: // 7.4
+ // cardinality: max 1
+ pkg.PackageFileName = subTriple.Object.ID
+ case SPDX_SUPPLIER: // 7.5
+ // cardinality: max 1
+ err = setPackageSupplier(pkg, subTriple.Object.ID)
+ case SPDX_ORIGINATOR: // 7.6
+ // cardinality: max 1
+ err = setPackageOriginator(pkg, subTriple.Object.ID)
+ case SPDX_DOWNLOAD_LOCATION: // 7.7
+ // cardinality: exactly 1
+ err = setDocumentLocationFromURI(pkg, subTriple.Object.ID)
+ case SPDX_FILES_ANALYZED: // 7.8
+ // cardinality: max 1
+ err = setFilesAnalyzed(pkg, subTriple.Object.ID)
+ case SPDX_PACKAGE_VERIFICATION_CODE: // 7.9
+ // cardinality: max 1
+ err = parser.setPackageVerificationCode(pkg, subTriple.Object)
+ case SPDX_CHECKSUM: // 7.10
+ // cardinality: min 0
+ err = parser.setPackageChecksum(pkg, subTriple.Object)
+ case DOAP_HOMEPAGE: // 7.11
+ // cardinality: max 1
+ // homepage must be a valid Uri
+ if !isUriValid(subTriple.Object.ID) {
+ return nil, fmt.Errorf("invalid uri %s while parsing doap_homepage in a package", subTriple.Object.ID)
+ }
+ pkg.PackageHomePage = subTriple.Object.ID
+ case SPDX_SOURCE_INFO: // 7.12
+ // cardinality: max 1
+ pkg.PackageSourceInfo = subTriple.Object.ID
+ case SPDX_LICENSE_CONCLUDED: // 7.13
+ // cardinality: exactly 1
+ anyLicenseInfo, err := parser.getAnyLicenseFromNode(subTriple.Object)
+ if err != nil {
+ return nil, err
+ }
+ pkg.PackageLicenseConcluded = anyLicenseInfo.ToLicenseString()
+ case SPDX_LICENSE_INFO_FROM_FILES: // 7.14
+ // cardinality: min 0
+ pkg.PackageLicenseInfoFromFiles = append(pkg.PackageLicenseInfoFromFiles, getLicenseStringFromURI(subTriple.Object.ID))
+ case SPDX_LICENSE_DECLARED: // 7.15
+ // cardinality: exactly 1
+ anyLicenseInfo, err := parser.getAnyLicenseFromNode(subTriple.Object)
+ if err != nil {
+ return nil, err
+ }
+ pkg.PackageLicenseDeclared = anyLicenseInfo.ToLicenseString()
+ case SPDX_LICENSE_COMMENTS: // 7.16
+ // cardinality: max 1
+ pkg.PackageLicenseComments = subTriple.Object.ID
+ case SPDX_COPYRIGHT_TEXT: // 7.17
+ // cardinality: exactly 1
+ pkg.PackageCopyrightText = subTriple.Object.ID
+ case SPDX_SUMMARY: // 7.18
+ // cardinality: max 1
+ pkg.PackageSummary = subTriple.Object.ID
+ case SPDX_DESCRIPTION: // 7.19
+ // cardinality: max 1
+ pkg.PackageDescription = subTriple.Object.ID
+ case RDFS_COMMENT: // 7.20
+ // cardinality: max 1
+ pkg.PackageComment = subTriple.Object.ID
+ case SPDX_EXTERNAL_REF: // 7.21
+ // cardinality: min 0
+ externalDocRef, err := parser.getPackageExternalRef(subTriple.Object)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing externalRef of a package: %v", err)
+ }
+ pkg.PackageExternalReferences = append(pkg.PackageExternalReferences, externalDocRef)
+ case SPDX_HAS_FILE: // 7.22
+ // cardinality: min 0
+ file, err := parser.getFileFromNode(subTriple.Object)
+ if err != nil {
+ return nil, fmt.Errorf("error setting file inside a package: %v", err)
+ }
+ parser.setFileToPackage(pkg, file)
+ case SPDX_PRIMARY_PACKAGE_PURPOSE: // 7.24
+ // cardinality: exactly 1
+ pkg.PrimaryPackagePurpose = getPrimaryPackagePurpose(subTriple.Object.ID)
+ case SPDX_RELEASE_DATE: // 7.25
+ // cardinality: exactly 1
+ pkg.ReleaseDate = subTriple.Object.ID
+ case SPDX_BUILT_DATE: // 7.26
+ // cardinality: exactly 1
+ pkg.BuiltDate = subTriple.Object.ID
+ case SPDX_VALID_UNTIL_DATE: // 7.27
+ // cardinality: exactly 1
+ pkg.ValidUntilDate = subTriple.Object.ID
+ case SPDX_RELATIONSHIP:
+ // cardinality: min 0
+ err = parser.parseRelationship(subTriple)
+ case SPDX_ATTRIBUTION_TEXT:
+ // cardinality: min 0
+ pkg.PackageAttributionTexts = append(pkg.PackageAttributionTexts, subTriple.Object.ID)
+ case SPDX_ANNOTATION:
+ // cardinality: min 0
+ err = parser.parseAnnotationFromNode(subTriple.Object)
+ default:
+ return nil, fmt.Errorf("unknown predicate id %s while parsing a package", subTriple.Predicate.ID)
+ }
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if existingPackageIndex != -1 {
+ parser.doc.Packages[existingPackageIndex] = pkg
+ } else {
+ parser.doc.Packages = append(parser.doc.Packages, pkg)
+ }
+
+ return pkg, nil
+}
+
+// parses externalReference found in the package by the associated triple.
+func (parser *rdfParser2_3) getPackageExternalRef(node *gordfParser.Node) (externalDocRef *v2_3.PackageExternalReference, err error) {
+ externalDocRef = &v2_3.PackageExternalReference{}
+ for _, triple := range parser.nodeToTriples(node) {
+ switch triple.Predicate.ID {
+ case SPDX_REFERENCE_CATEGORY:
+ // cardinality: exactly 1
+ switch triple.Object.ID {
+ case SPDX_REFERENCE_CATEGORY_SECURITY:
+ externalDocRef.Category = "SECURITY"
+ case SPDX_REFERENCE_CATEGORY_PACKAGE_MANAGER:
+ externalDocRef.Category = "PACKAGE-MANAGER"
+ case SPDX_REFERENCE_CATEGORY_OTHER:
+ externalDocRef.Category = "OTHER"
+ default:
+ return nil, fmt.Errorf("unknown packageManager uri %s", triple.Predicate.ID)
+ }
+ case RDF_TYPE:
+ continue
+ case SPDX_REFERENCE_TYPE:
+ // assumes: the reference type is associated with just the uri and
+ // other associated fields are ignored.
+ // other fields include:
+ // 1. contextualExample,
+ // 2. documentation and,
+ // 3. externalReferenceSite
+ externalDocRef.RefType = triple.Object.ID
+ case SPDX_REFERENCE_LOCATOR:
+ // cardinality: exactly 1
+ externalDocRef.Locator = triple.Object.ID
+ case RDFS_COMMENT:
+ // cardinality: max 1
+ externalDocRef.ExternalRefComment = triple.Object.ID
+ default:
+ return nil, fmt.Errorf("unknown package external reference predicate id %s", triple.Predicate.ID)
+ }
+ }
+ return
+}
+
+func getPrimaryPackagePurpose(purpose string) string {
+ value := strings.ReplaceAll(purpose, "packagePurpose_", "")
+ value = strings.ReplaceAll(value, "_", "-")
+ value = strings.ToUpper(value)
+ switch value {
+ case "APPLICATION", "FRAMEWORK", "LIBRARY", "CONTAINER", "OPERATING-SYSTEM", "DEVICE", "FIRMWARE", "SOURCE", "ARCHIVE", "FILE", "INSTALL", "OTHER":
+ return value
+ }
+ // invalid value
+ return ""
+}
+
+func (parser *rdfParser2_3) setPackageVerificationCode(pkg *v2_3.Package, node *gordfParser.Node) error {
+ if pkg.PackageVerificationCode == nil {
+ pkg.PackageVerificationCode = &common.PackageVerificationCode{}
+ }
+ for _, subTriple := range parser.nodeToTriples(node) {
+ switch subTriple.Predicate.ID {
+ case SPDX_PACKAGE_VERIFICATION_CODE_VALUE:
+ // cardinality: exactly 1
+ pkg.PackageVerificationCode.Value = subTriple.Object.ID
+ case SPDX_PACKAGE_VERIFICATION_CODE_EXCLUDED_FILE:
+ // cardinality: min 0
+ pkg.PackageVerificationCode.ExcludedFiles = append(pkg.PackageVerificationCode.ExcludedFiles, subTriple.Object.ID)
+ case RDF_TYPE:
+ // cardinality: exactly 1
+ continue
+ default:
+ return fmt.Errorf("unparsed predicate %s", subTriple.Predicate.ID)
+ }
+ }
+ return nil
+}
+
+// appends the file to the package and also sets the assocWithPackage for the
+// file to indicate the file is associated with a package
+func (parser *rdfParser2_3) setFileToPackage(pkg *v2_3.Package, file *v2_3.File) {
+ if pkg.Files == nil {
+ pkg.Files = []*v2_3.File{}
+ }
+ pkg.Files = append(pkg.Files, file)
+ parser.assocWithPackage[file.FileSPDXIdentifier] = true
+}
+
+// given a supplierObject, sets the PackageSupplier attribute of the pkg.
+// Args:
+//
+// value: [NOASSERTION | [Person | Organization]: string]
+func setPackageSupplier(pkg *v2_3.Package, value string) error {
+ value = strings.TrimSpace(value)
+ supplier := &common.Supplier{}
+ if strings.ToUpper(value) == "NOASSERTION" {
+ supplier.Supplier = "NOASSERTION"
+ pkg.PackageSupplier = supplier
+ return nil
+ }
+
+ subKey, subValue, err := ExtractSubs(value, ":")
+ if err != nil {
+ return fmt.Errorf("package supplier must be of the form NOASSERTION or [Person|Organization]: string. found: %s", value)
+ }
+ switch subKey {
+ case "Person", "Organization":
+ supplier.Supplier = subValue
+ supplier.SupplierType = subKey
+ default:
+ return fmt.Errorf("unknown supplier %s", subKey)
+ }
+
+ pkg.PackageSupplier = supplier
+
+ return nil
+}
+
+// given a OriginatorObject, sets the PackageOriginator attribute of the pkg.
+// Args:
+//
+// value: [NOASSERTION | [Person | Organization]: string]
+func setPackageOriginator(pkg *v2_3.Package, value string) error {
+ value = strings.TrimSpace(value)
+ originator := &common.Originator{}
+ if strings.ToUpper(value) == "NOASSERTION" {
+ originator.Originator = "NOASSERTION"
+ pkg.PackageOriginator = originator
+ return nil
+ }
+
+ subKey, subValue, err := ExtractSubs(value, ":")
+ if err != nil {
+ return fmt.Errorf("package Originator must be of the form NOASSERTION or [Person|Organization]: string. found: %s", value)
+ }
+ switch subKey {
+ case "Person", "Organization":
+ originator.Originator = subValue
+ originator.OriginatorType = subKey
+ default:
+ return fmt.Errorf("unknown Originator %s", subKey)
+ }
+
+ pkg.PackageOriginator = originator
+
+ return nil
+}
+
+// validates the uri and sets the location if it is valid
+func setDocumentLocationFromURI(pkg *v2_3.Package, locationURI string) error {
+ switch locationURI {
+ case SPDX_NOASSERTION_CAPS, SPDX_NOASSERTION_SMALL:
+ pkg.PackageDownloadLocation = "NOASSERTION"
+ case SPDX_NONE_CAPS, SPDX_NONE_SMALL:
+ pkg.PackageDownloadLocation = "NONE"
+ default:
+ if !isUriValid(locationURI) {
+ return fmt.Errorf("%s is not a valid uri", locationURI)
+ }
+ pkg.PackageDownloadLocation = locationURI
+ }
+ return nil
+}
+
+// sets the FilesAnalyzed attribute to the given package
+// boolValue is a string of type "true" or "false"
+func setFilesAnalyzed(pkg *v2_3.Package, boolValue string) (err error) {
+ pkg.IsFilesAnalyzedTagPresent = true
+ pkg.FilesAnalyzed, err = boolFromString(boolValue)
+ return err
+}
+
+func (parser *rdfParser2_3) setPackageChecksum(pkg *v2_3.Package, node *gordfParser.Node) error {
+ checksumAlgorithm, checksumValue, err := parser.getChecksumFromNode(node)
+ if err != nil {
+ return fmt.Errorf("error getting checksum algorithm and value from %v", node)
+ }
+ if pkg.PackageChecksums == nil {
+ pkg.PackageChecksums = make([]common.Checksum, 0, 1)
+ }
+ switch checksumAlgorithm {
+ case common.SHA1,
+ common.SHA224,
+ common.SHA256,
+ common.SHA384,
+ common.SHA512,
+ common.MD2,
+ common.MD4,
+ common.MD5,
+ common.MD6,
+ common.SHA3_256,
+ common.SHA3_384,
+ common.SHA3_512,
+ common.BLAKE2b_256,
+ common.BLAKE2b_384,
+ common.BLAKE2b_512,
+ common.BLAKE3,
+ common.ADLER32:
+ pkg.PackageChecksums = append(pkg.PackageChecksums, common.Checksum{Algorithm: checksumAlgorithm, Value: checksumValue})
+ default:
+ return fmt.Errorf("unknown checksumAlgorithm %s while parsing a package", checksumAlgorithm)
+ }
+ return nil
+}