Skip to content

Commit

Permalink
Merge pull request #40 from RishabhBhatnagar/gordf
Browse files Browse the repository at this point in the history
Add Support For RDFLoader Including Licenses
  • Loading branch information
swinslow committed Aug 22, 2020
2 parents 5a270f9 + d8eb2d8 commit 35fc7e0
Show file tree
Hide file tree
Showing 16 changed files with 2,192 additions and 0 deletions.
41 changes: 41 additions & 0 deletions examples/7-rdfloader/exampleRDFLoader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package main

import (
"fmt"
"github.com/spdx/tools-golang/rdfloader"
"os"
"strings"
)

func getFilePathFromUser() string {
if len(os.Args) == 1 {
// user hasn't specified the rdf file path
panic("kindly provide path of the rdf file to be loaded as a spdx-document while running this file")
}
return os.Args[1]
}

func main() {
// example to use the rdfLoader.
filePath := getFilePathFromUser()
file, err := os.Open(filePath)
if err != nil {
panic(fmt.Errorf("error opening File: %s", err))
}

// loading the spdx-document
doc, err := rdfloader.Load2_2(file)
if err != nil {
fmt.Println(fmt.Errorf("error parsing given spdx document: %s", err))
os.Exit(1)
}

// Printing some of the document Information
fmt.Println(strings.Repeat("=", 80))
fmt.Println("Some Attributes of the Document:")
fmt.Printf("Document Name: %s\n", doc.CreationInfo.DocumentName)
fmt.Printf("DataLicense: %s\n", doc.CreationInfo.DataLicense)
fmt.Printf("Document NameSpace: %s\n", doc.CreationInfo.DocumentNamespace)
fmt.Printf("SPDX Document Version: %s\n", doc.CreationInfo.SPDXVersion)
fmt.Println(strings.Repeat("=", 80))
}
260 changes: 260 additions & 0 deletions rdfloader/parser2v2/constants.go

Large diffs are not rendered by default.

77 changes: 77 additions & 0 deletions rdfloader/parser2v2/parse_annotation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later

package parser2v2

import (
"fmt"
gordfParser "github.com/RishabhBhatnagar/gordf/rdfloader/parser"
"github.com/spdx/tools-golang/spdx"
)

// creates a new instance of annotation and sets the annotation attributes
// associated with the given node.
// The newly created annotation is appended to the doc.
func (parser *rdfParser2_2) parseAnnotationFromNode(node *gordfParser.Node) (err error) {
ann := &spdx.Annotation2_2{}
for _, subTriple := range parser.nodeToTriples(node) {
switch subTriple.Predicate.ID {
case SPDX_ANNOTATOR:
// cardinality: exactly 1
err = setAnnotatorFromString(subTriple.Object.ID, ann)
case SPDX_ANNOTATION_DATE:
// cardinality: exactly 1
ann.AnnotationDate = subTriple.Object.ID
case RDFS_COMMENT:
// cardinality: exactly 1
ann.AnnotationComment = subTriple.Object.ID
case SPDX_ANNOTATION_TYPE:
// cardinality: exactly 1
err = setAnnotationType(subTriple.Object.ID, ann)
case RDF_TYPE:
// cardinality: exactly 1
continue
default:
err = fmt.Errorf("unknown predicate %s while parsing annotation", subTriple.Predicate.ID)
}
if err != nil {
return err
}
}
return setAnnotationToParser(parser, ann)
}

func setAnnotationToParser(parser *rdfParser2_2, annotation *spdx.Annotation2_2) error {
if parser.doc == nil {
return fmt.Errorf("uninitialized spdx document")
}
if parser.doc.Annotations == nil {
parser.doc.Annotations = []*spdx.Annotation2_2{}
}
parser.doc.Annotations = append(parser.doc.Annotations, annotation)
return nil
}

func setAnnotatorFromString(annotatorString string, ann *spdx.Annotation2_2) error {
subkey, subvalue, err := ExtractSubs(annotatorString, ":")
if err != nil {
return err
}
if subkey == "Person" || subkey == "Organization" || subkey == "Tool" {
ann.AnnotatorType = subkey
ann.Annotator = subvalue
return nil
}
return fmt.Errorf("unrecognized Annotator type %v while parsing annotation", subkey)
}

func setAnnotationType(annType string, ann *spdx.Annotation2_2) error {
switch annType {
case SPDX_ANNOTATION_TYPE_OTHER:
ann.AnnotationType = "OTHER"
case SPDX_ANNOTATION_TYPE_REVIEW:
ann.AnnotationType = "REVIEW"
default:
return fmt.Errorf("unknown annotation type %s", annType)
}
return nil
}
54 changes: 54 additions & 0 deletions rdfloader/parser2v2/parse_creation_info.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later

package parser2v2

import (
"fmt"
gordfParser "github.com/RishabhBhatnagar/gordf/rdfloader/parser"
"github.com/spdx/tools-golang/spdx"
)

// Cardinality: Mandatory, one.
func (parser *rdfParser2_2) parseCreationInfoFromNode(ci *spdx.CreationInfo2_2, node *gordfParser.Node) error {
for _, triple := range parser.nodeToTriples(node) {
switch triple.Predicate.ID {
case SPDX_LICENSE_LIST_VERSION: // 2.7
// cardinality: max 1
ci.LicenseListVersion = triple.Object.ID
case SPDX_CREATOR: // 2.8
// cardinality: min 1
err := setCreator(triple.Object.ID, ci)
if err != nil {
return err
}
case SPDX_CREATED: // 2.9
// cardinality: exactly 1
ci.Created = triple.Object.ID
case RDFS_COMMENT: // 2.10
ci.CreatorComment = triple.Object.ID
case RDF_TYPE:
continue
default:
return fmt.Errorf("unknown predicate %v while parsing a creation info", triple.Predicate)
}
}
return nil
}

func setCreator(creator string, ci *spdx.CreationInfo2_2) error {
entityType, entity, err := ExtractSubs(creator, ":")
if err != nil {
return fmt.Errorf("error setting creator of a creation info: %s", err)
}
switch entityType {
case "Person":
ci.CreatorPersons = append(ci.CreatorPersons, entity)
case "Organization":
ci.CreatorOrganizations = append(ci.CreatorOrganizations, entity)
case "Tool":
ci.CreatorTools = append(ci.CreatorTools, entity)
default:
return fmt.Errorf("unknown creatorType %v in a creation info", entityType)
}
return nil
}
166 changes: 166 additions & 0 deletions rdfloader/parser2v2/parse_file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later

package parser2v2

import (
"fmt"
gordfParser "github.com/RishabhBhatnagar/gordf/rdfloader/parser"
"github.com/spdx/tools-golang/spdx"
"strings"
)

// returns a file instance and the error if any encountered.
func (parser *rdfParser2_2) getFileFromNode(fileNode *gordfParser.Node) (file *spdx.File2_2, err error) {
file = &spdx.File2_2{}

err = setFileIdentifier(fileNode.ID, file, parser) // 4.2
if err != nil {
return nil, err
}

for _, subTriple := range parser.nodeToTriples(fileNode) {
switch subTriple.Predicate.ID {
case SPDX_FILE_NAME: // 4.1
// cardinality: exactly 1
file.FileName = subTriple.Object.ID
case SPDX_NAME:
// cardinality: exactly 1
// todo: check where it will be set in the golang-tools spdx-data-model
case RDF_TYPE:
// cardinality: exactly 1
case SPDX_FILE_TYPE: // 4.3
// cardinality: min 0
fileType := ""
fileType, err = parser.getFileTypeFromUri(subTriple.Object.ID)
file.FileType = append(file.FileType, fileType)
case SPDX_CHECKSUM: // 4.4
// cardinality: min 1
err = parser.setFileChecksumFromNode(file, subTriple.Object)
case SPDX_LICENSE_CONCLUDED: // 4.5
// cardinality: (exactly 1 anyLicenseInfo) or (None) or (Noassertion)
anyLicense, err := parser.getAnyLicenseFromNode(subTriple.Object)
if err != nil {
return nil, fmt.Errorf("error parsing licenseConcluded: %v", err)
}
file.LicenseConcluded = anyLicense.ToLicenseString()
case SPDX_LICENSE_INFO_IN_FILE: // 4.6
// cardinality: min 1
lastPart := getLastPartOfURI(subTriple.Object.ID)
file.LicenseInfoInFile = append(file.LicenseInfoInFile, lastPart)
case SPDX_LICENSE_COMMENTS: // 4.7
// cardinality: max 1
file.LicenseComments = subTriple.Object.ID
case SPDX_COPYRIGHT_TEXT: // 4.8
// cardinality: exactly 1
file.FileCopyrightText = subTriple.Object.ID
case SPDX_LICENSE_INFO_FROM_FILES:
// todo: implement it. It is not defined in the tools-golang model.
// deprecated artifactOf (see sections 4.9, 4.10, 4.11)
case SPDX_ARTIFACT_OF:
// cardinality: min 0
var artifactOf *spdx.ArtifactOfProject2_2
artifactOf, err = parser.getArtifactFromNode(subTriple.Object)
file.ArtifactOfProjects = append(file.ArtifactOfProjects, artifactOf)
case RDFS_COMMENT: // 4.12
// cardinality: max 1
file.FileComment = subTriple.Object.ID
case SPDX_NOTICE_TEXT: // 4.13
// cardinality: max 1
file.FileNotice = subTriple.Object.ID
case SPDX_FILE_CONTRIBUTOR: // 4.14
// cardinality: min 0
file.FileContributor = append(file.FileContributor, subTriple.Object.ID)
case SPDX_FILE_DEPENDENCY:
// cardinality: min 0
file, err := parser.getFileFromNode(subTriple.Object)
if err != nil {
return nil, fmt.Errorf("error setting a file dependency in a file: %v", err)
}
parser.files[file.FileSPDXIdentifier] = file
case SPDX_ATTRIBUTION_TEXT:
// cardinality: min 0
file.FileAttributionTexts = append(file.FileAttributionTexts, subTriple.Object.ID)
case SPDX_ANNOTATION: // unknown section
err = parser.parseAnnotationFromNode(subTriple.Object)
case SPDX_RELATIONSHIP: // unknown section
err = parser.parseRelationship(subTriple)
default:
return nil, fmt.Errorf("unknown triple predicate id %s", subTriple.Predicate.ID)
}
if err != nil {
return nil, err
}
}
return file, nil
}

func (parser *rdfParser2_2) setFileChecksumFromNode(file *spdx.File2_2, checksumNode *gordfParser.Node) error {
checksumAlgorithm, checksumValue, err := parser.getChecksumFromNode(checksumNode)
if err != nil {
return nil
}
switch checksumAlgorithm {
case "MD5":
file.FileChecksumMD5 = checksumValue
case "SHA1":
file.FileChecksumSHA1 = checksumValue
case "SHA256":
file.FileChecksumSHA256 = checksumValue
case "":
return fmt.Errorf("empty checksum algorithm and value")
default:
return fmt.Errorf("unknown checksumAlgorithm %s while parsing a file", checksumAlgorithm)
}
return nil
}

func (parser *rdfParser2_2) getArtifactFromNode(node *gordfParser.Node) (*spdx.ArtifactOfProject2_2, error) {
artifactOf := &spdx.ArtifactOfProject2_2{}
// setting artifactOfProjectURI attribute (which is optional)
if node.NodeType == gordfParser.IRI {
artifactOf.URI = node.ID
}
// parsing rest triples and attributes of the artifact.
for _, triple := range parser.nodeToTriples(node) {
switch triple.Predicate.ID {
case RDF_TYPE:
case DOAP_HOMEPAGE:
artifactOf.HomePage = triple.Object.ID
case DOAP_NAME:
artifactOf.Name = triple.Object.ID
default:
return nil, fmt.Errorf("error parsing artifactOf predicate %s", triple.Predicate.ID)
}
}
return artifactOf, nil
}

func (parser *rdfParser2_2) getFileTypeFromUri(uri string) (string, error) {
// fileType is given as a uri. for example: http://spdx.org/rdf/terms#fileType_text
lastPart := getLastPartOfURI(uri)
if !strings.HasPrefix(lastPart, "fileType_") {
return "", fmt.Errorf("fileType Uri must begin with fileTYpe_. found: %s", lastPart)
}
return strings.TrimPrefix(lastPart, "fileType_"), nil
}

// populates parser.doc.UnpackagedFiles by a list of files which are not
// associated with a package by the hasFile attribute
// assumes: all the packages are already parsed.
func (parser *rdfParser2_2) setUnpackagedFiles() {
for fileID := range parser.files {
if !parser.assocWithPackage[fileID] {
parser.doc.UnpackagedFiles[fileID] = parser.files[fileID]
}
}
}

func setFileIdentifier(idURI string, file *spdx.File2_2, parser *rdfParser2_2) (err error) {
idURI = strings.TrimSpace(idURI)
uriFragment := getLastPartOfURI(idURI)
file.FileSPDXIdentifier, err = ExtractElementID(uriFragment)
if err != nil {
return fmt.Errorf("error setting file identifier: %s", err)
}
return nil
}

0 comments on commit 35fc7e0

Please sign in to comment.