aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--v0/spdx/file.go34
-rw-r--r--v0/tvloader/parser2v1/parse_file.go20
-rw-r--r--v0/tvloader/parser2v1/parse_file_test.go202
-rw-r--r--v0/tvloader/parser2v1/types.go1
-rw-r--r--v0/tvsaver/saver2v1/save_document.go4
-rw-r--r--v0/tvsaver/saver2v1/save_file.go20
-rw-r--r--v0/tvsaver/saver2v1/save_file_test.go40
7 files changed, 202 insertions, 119 deletions
diff --git a/v0/spdx/file.go b/v0/spdx/file.go
index a61fc4e..3732107 100644
--- a/v0/spdx/file.go
+++ b/v0/spdx/file.go
@@ -40,19 +40,9 @@ type File2_1 struct {
FileCopyrightText string
// DEPRECATED in version 2.1 of spec
- // 4.9: Artifact of Project Name
- // Cardinality: optional, one or many
- ArtifactOfProjectName []string
-
- // DEPRECATED in version 2.1 of spec
- // 4.10: Artifact of Project Homepage: URL or "UNKNOWN"
+ // 4.9-4.11: Artifact of Project variables (defined below)
// Cardinality: optional, one or many
- ArtifactOfProjectHomePage []string
-
- // DEPRECATED in version 2.1 of spec
- // 4.11: Artifact of Project Uniform Resource Identifier
- // Cardinality: optional, one or many
- ArtifactOfProjectURI []string
+ ArtifactOfProjects []*ArtifactOfProject2_1
// 4.12: File Comment
// Cardinality: optional, one
@@ -74,3 +64,23 @@ type File2_1 struct {
// Snippets contained in this File
Snippets []*Snippet2_1
}
+
+// ArtifactOfProject2_1 is a DEPRECATED collection of data regarding
+// a Package, as defined in sections 4.9-4.11 in version 2.1 of the spec.
+type ArtifactOfProject2_1 struct {
+
+ // DEPRECATED in version 2.1 of spec
+ // 4.9: Artifact of Project Name
+ // Cardinality: conditional, required if present, one per AOP
+ Name string
+
+ // DEPRECATED in version 2.1 of spec
+ // 4.10: Artifact of Project Homepage: URL or "UNKNOWN"
+ // Cardinality: optional, one per AOP
+ HomePage string
+
+ // DEPRECATED in version 2.1 of spec
+ // 4.11: Artifact of Project Uniform Resource Identifier
+ // Cardinality: optional, one per AOP
+ URI string
+}
diff --git a/v0/tvloader/parser2v1/parse_file.go b/v0/tvloader/parser2v1/parse_file.go
index bb846fb..60d3030 100644
--- a/v0/tvloader/parser2v1/parse_file.go
+++ b/v0/tvloader/parser2v1/parse_file.go
@@ -9,6 +9,12 @@ import (
)
func (parser *tvParser2_1) parsePairFromFile2_1(tag string, value string) error {
+ // expire fileAOP for anything other than an AOPHomePage or AOPURI
+ // (we'll actually handle the HomePage and URI further below)
+ if tag != "ArtifactOfProjectHomePage" && tag != "ArtifactOfProjectURI" {
+ parser.fileAOP = nil
+ }
+
switch tag {
// tag for creating new file section
case "FileName":
@@ -57,11 +63,19 @@ func (parser *tvParser2_1) parsePairFromFile2_1(tag string, value string) error
case "FileCopyrightText":
parser.file.FileCopyrightText = value
case "ArtifactOfProjectName":
- parser.file.ArtifactOfProjectName = append(parser.file.ArtifactOfProjectName, value)
+ parser.fileAOP = &spdx.ArtifactOfProject2_1{}
+ parser.file.ArtifactOfProjects = append(parser.file.ArtifactOfProjects, parser.fileAOP)
+ parser.fileAOP.Name = value
case "ArtifactOfProjectHomePage":
- parser.file.ArtifactOfProjectHomePage = append(parser.file.ArtifactOfProjectHomePage, value)
+ if parser.fileAOP == nil {
+ return fmt.Errorf("no current ArtifactOfProject found")
+ }
+ parser.fileAOP.HomePage = value
case "ArtifactOfProjectURI":
- parser.file.ArtifactOfProjectURI = append(parser.file.ArtifactOfProjectURI, value)
+ if parser.fileAOP == nil {
+ return fmt.Errorf("no current ArtifactOfProject found")
+ }
+ parser.fileAOP.URI = value
case "FileComment":
parser.file.FileComment = value
case "FileNotice":
diff --git a/v0/tvloader/parser2v1/parse_file_test.go b/v0/tvloader/parser2v1/parse_file_test.go
index d4b24f7..087de8c 100644
--- a/v0/tvloader/parser2v1/parse_file_test.go
+++ b/v0/tvloader/parser2v1/parse_file_test.go
@@ -422,91 +422,90 @@ func TestParser2_1CanParseFileTags(t *testing.T) {
t.Errorf("got %v for FileCopyrightText", parser.file.FileCopyrightText)
}
- // Artifact of Project Name
- prjNames := []string{
- "project1",
- "project2",
- "project3",
- "project4",
- }
- for _, pn := range prjNames {
- err = parser.parsePairFromFile2_1("ArtifactOfProjectName", pn)
- if err != nil {
- t.Errorf("expected nil error, got %v", err)
- }
+ // Artifact of Projects: Name, HomePage and URI
+ // Artifact set 1
+ err = parser.parsePairFromFile2_1("ArtifactOfProjectName", "project1")
+ if err != nil {
+ t.Errorf("expected nil error, got %v", err)
}
- for _, pnWant := range prjNames {
- flagFound := false
- for _, pnCheck := range parser.file.ArtifactOfProjectName {
- if pnWant == pnCheck {
- flagFound = true
- }
- }
- if flagFound == false {
- t.Errorf("didn't find %s in ArtifactOfProjectName", pnWant)
- }
+ err = parser.parsePairFromFile2_1("ArtifactOfProjectHomePage", "http://example.com/1/")
+ if err != nil {
+ t.Errorf("expected nil error, got %v", err)
+ }
+ err = parser.parsePairFromFile2_1("ArtifactOfProjectURI", "http://example.com/1/uri.whatever")
+ if err != nil {
+ t.Errorf("expected nil error, got %v", err)
+ }
+ // Artifact set 2 -- just name
+ err = parser.parsePairFromFile2_1("ArtifactOfProjectName", "project2")
+ if err != nil {
+ t.Errorf("expected nil error, got %v", err)
+ }
+ // Artifact set 3 -- just name and home page
+ err = parser.parsePairFromFile2_1("ArtifactOfProjectName", "project3")
+ if err != nil {
+ t.Errorf("expected nil error, got %v", err)
+ }
+ err = parser.parsePairFromFile2_1("ArtifactOfProjectHomePage", "http://example.com/3/")
+ if err != nil {
+ t.Errorf("expected nil error, got %v", err)
+ }
+ // Artifact set 4 -- just name and URI
+ err = parser.parsePairFromFile2_1("ArtifactOfProjectName", "project4")
+ if err != nil {
+ t.Errorf("expected nil error, got %v", err)
}
- if len(prjNames) != len(parser.file.ArtifactOfProjectName) {
- t.Errorf("expected %d types in ArtifactOfProjectName, got %d", len(prjNames),
- len(parser.file.ArtifactOfProjectName))
+ err = parser.parsePairFromFile2_1("ArtifactOfProjectURI", "http://example.com/4/uri.whatever")
+ if err != nil {
+ t.Errorf("expected nil error, got %v", err)
}
- // Artifact of Project Home Page
- prjPages := []string{
- "http://example.com/1/",
- "http://example.com/2/",
- "http://example.com/3/",
+ if len(parser.file.ArtifactOfProjects) != 4 {
+ t.Fatalf("expected len %d, got %d", 4, len(parser.file.ArtifactOfProjects))
}
- for _, pg := range prjPages {
- err = parser.parsePairFromFile2_1("ArtifactOfProjectHomePage", pg)
- if err != nil {
- t.Errorf("expected nil error, got %v", err)
- }
+
+ aop := parser.file.ArtifactOfProjects[0]
+ if aop.Name != "project1" {
+ t.Errorf("expected %v, got %v", "project1", aop.Name)
}
- for _, pgWant := range prjPages {
- flagFound := false
- for _, pgCheck := range parser.file.ArtifactOfProjectHomePage {
- if pgWant == pgCheck {
- flagFound = true
- }
- }
- if flagFound == false {
- t.Errorf("didn't find %s in ArtifactOfProjectHomePage", pgWant)
- }
+ if aop.HomePage != "http://example.com/1/" {
+ t.Errorf("expected %v, got %v", "http://example.com/1/", aop.HomePage)
}
- if len(prjPages) != len(parser.file.ArtifactOfProjectHomePage) {
- t.Errorf("expected %d types in ArtifactOfProjectHomePage, got %d", len(prjPages),
- len(parser.file.ArtifactOfProjectHomePage))
+ if aop.URI != "http://example.com/1/uri.whatever" {
+ t.Errorf("expected %v, got %v", "http://example.com/1/uri.whatever", aop.URI)
}
- // Artifact of Project URI
- prjURIs := []string{
- "http://example.com/1/uri.whatever",
- "http://example.com/2/uri.whatever",
- "http://example.com/3/uri.whatever",
- "http://example.com/4/uri.whatever",
- "http://example.com/5/uri.whatever",
+ aop = parser.file.ArtifactOfProjects[1]
+ if aop.Name != "project2" {
+ t.Errorf("expected %v, got %v", "project2", aop.Name)
}
- for _, pu := range prjURIs {
- err = parser.parsePairFromFile2_1("ArtifactOfProjectURI", pu)
- if err != nil {
- t.Errorf("expected nil error, got %v", err)
- }
+ if aop.HomePage != "" {
+ t.Errorf("expected %v, got %v", "", aop.HomePage)
}
- for _, puWant := range prjURIs {
- flagFound := false
- for _, puCheck := range parser.file.ArtifactOfProjectURI {
- if puWant == puCheck {
- flagFound = true
- }
- }
- if flagFound == false {
- t.Errorf("didn't find %s in ArtifactOfProjectURI", puWant)
- }
+ if aop.URI != "" {
+ t.Errorf("expected %v, got %v", "", aop.URI)
+ }
+
+ aop = parser.file.ArtifactOfProjects[2]
+ if aop.Name != "project3" {
+ t.Errorf("expected %v, got %v", "project3", aop.Name)
+ }
+ if aop.HomePage != "http://example.com/3/" {
+ t.Errorf("expected %v, got %v", "http://example.com/3/", aop.HomePage)
}
- if len(prjURIs) != len(parser.file.ArtifactOfProjectURI) {
- t.Errorf("expected %d types in ArtifactOfProjectURI, got %d", len(prjURIs),
- len(parser.file.ArtifactOfProjectURI))
+ if aop.URI != "" {
+ t.Errorf("expected %v, got %v", "", aop.URI)
+ }
+
+ aop = parser.file.ArtifactOfProjects[3]
+ if aop.Name != "project4" {
+ t.Errorf("expected %v, got %v", "project4", aop.Name)
+ }
+ if aop.HomePage != "" {
+ t.Errorf("expected %v, got %v", "", aop.HomePage)
+ }
+ if aop.URI != "http://example.com/4/uri.whatever" {
+ t.Errorf("expected %v, got %v", "http://example.com/4/uri.whatever", aop.URI)
}
// File Comment
@@ -642,3 +641,60 @@ func TestParser2_1FileUnknownTagFails(t *testing.T) {
t.Errorf("expected error from parsing unknown tag")
}
}
+
+func TestFileAOPPointerChangesAfterTags(t *testing.T) {
+ parser := tvParser2_1{
+ doc: &spdx.Document2_1{},
+ st: psFile2_1,
+ pkg: &spdx.Package2_1{PackageName: "test"},
+ file: &spdx.File2_1{FileName: "f1.txt"},
+ }
+ parser.doc.Packages = append(parser.doc.Packages, parser.pkg)
+ parser.pkg.Files = append(parser.pkg.Files, parser.file)
+
+ err := parser.parsePairFromFile2_1("ArtifactOfProjectName", "project1")
+ if err != nil {
+ t.Errorf("expected nil error, got %v", err)
+ }
+ if parser.fileAOP == nil {
+ t.Errorf("expected non-nil AOP pointer, got nil")
+ }
+ curPtr := parser.fileAOP
+
+ // now, a home page; pointer should stay
+ err = parser.parsePairFromFile2_1("ArtifactOfProjectHomePage", "http://example.com/1/")
+ if err != nil {
+ t.Errorf("expected nil error, got %v", err)
+ }
+ if parser.fileAOP != curPtr {
+ t.Errorf("expected no change in AOP pointer, was %v, got %v", curPtr, parser.fileAOP)
+ }
+
+ // a URI; pointer should stay
+ err = parser.parsePairFromFile2_1("ArtifactOfProjectURI", "http://example.com/1/uri.whatever")
+ if err != nil {
+ t.Errorf("expected nil error, got %v", err)
+ }
+ if parser.fileAOP != curPtr {
+ t.Errorf("expected no change in AOP pointer, was %v, got %v", curPtr, parser.fileAOP)
+ }
+
+ // now, another artifact name; pointer should change but be non-nil
+ // now, a home page; pointer should stay
+ err = parser.parsePairFromFile2_1("ArtifactOfProjectName", "project2")
+ if err != nil {
+ t.Errorf("expected nil error, got %v", err)
+ }
+ if parser.fileAOP == curPtr {
+ t.Errorf("expected change in AOP pointer, got no change")
+ }
+
+ // finally, an unrelated tag; pointer should go away
+ err = parser.parsePairFromFile2_1("FileComment", "whatever")
+ if err != nil {
+ t.Errorf("expected nil error, got %v", err)
+ }
+ if parser.fileAOP != nil {
+ t.Errorf("expected nil AOP pointer, got %v", parser.fileAOP)
+ }
+}
diff --git a/v0/tvloader/parser2v1/types.go b/v0/tvloader/parser2v1/types.go
index 9d0f14a..779cf96 100644
--- a/v0/tvloader/parser2v1/types.go
+++ b/v0/tvloader/parser2v1/types.go
@@ -17,6 +17,7 @@ type tvParser2_1 struct {
pkg *spdx.Package2_1
pkgExtRef *spdx.PackageExternalReference2_1
file *spdx.File2_1
+ fileAOP *spdx.ArtifactOfProject2_1
snippet *spdx.Snippet2_1
otherLic *spdx.OtherLicense2_1
rln *spdx.Relationship2_1
diff --git a/v0/tvsaver/saver2v1/save_document.go b/v0/tvsaver/saver2v1/save_document.go
index 47b6b15..41e5558 100644
--- a/v0/tvsaver/saver2v1/save_document.go
+++ b/v0/tvsaver/saver2v1/save_document.go
@@ -11,6 +11,10 @@ import (
"github.com/swinslow/spdx-go/v0/spdx"
)
+// RenderDocument2_1 is the main entry point to take an SPDX in-memory
+// Document (version 2.1), and render it to the received io.Writer.
+// It is only exported in order to be available to the tvsaver package,
+// and typically does not need to be called by client code.
func RenderDocument2_1(doc *spdx.Document2_1, w io.Writer) error {
if doc.CreationInfo == nil {
return fmt.Errorf("Document had nil CreationInfo section")
diff --git a/v0/tvsaver/saver2v1/save_file.go b/v0/tvsaver/saver2v1/save_file.go
index a82770a..4094432 100644
--- a/v0/tvsaver/saver2v1/save_file.go
+++ b/v0/tvsaver/saver2v1/save_file.go
@@ -40,18 +40,14 @@ func renderFile2_1(f *spdx.File2_1, w io.Writer) error {
if f.FileCopyrightText != "" {
fmt.Fprintf(w, "FileCopyrightText: %s\n", f.FileCopyrightText)
}
- // FIXME THIS IS NOT COMPLIANT WITH SPEC
- // needs to be restructured so that ArtifactOfProjectHomePage and
- // ArtifactOfProjectUI are associated with a particular
- // ArtifactOfProjectName, and are rendered interleaved with it
- for _, s := range f.ArtifactOfProjectName {
- fmt.Fprintf(w, "ArtifactOfProjectName: %s\n", s)
- }
- for _, s := range f.ArtifactOfProjectHomePage {
- fmt.Fprintf(w, "ArtifactOfProjectHomePage: %s\n", s)
- }
- for _, s := range f.ArtifactOfProjectURI {
- fmt.Fprintf(w, "ArtifactOfProjectURI: %s\n", s)
+ for _, aop := range f.ArtifactOfProjects {
+ fmt.Fprintf(w, "ArtifactOfProjectName: %s\n", aop.Name)
+ if aop.HomePage != "" {
+ fmt.Fprintf(w, "ArtifactOfProjectHomePage: %s\n", aop.HomePage)
+ }
+ if aop.URI != "" {
+ fmt.Fprintf(w, "ArtifactOfProjectURI: %s\n", aop.URI)
+ }
}
if f.FileComment != "" {
fmt.Fprintf(w, "FileComment: %s\n", f.FileComment)
diff --git a/v0/tvsaver/saver2v1/save_file_test.go b/v0/tvsaver/saver2v1/save_file_test.go
index 354a729..2386b87 100644
--- a/v0/tvsaver/saver2v1/save_file_test.go
+++ b/v0/tvsaver/saver2v1/save_file_test.go
@@ -28,20 +28,23 @@ func TestSaver2_1FileSavesText(t *testing.T) {
},
LicenseComments: "this is a license comment(s)",
FileCopyrightText: "Copyright (c) Jane Doe",
- ArtifactOfProjectName: []string{
- "project1",
- "project2",
- "project3",
- "project4",
- },
- ArtifactOfProjectHomePage: []string{
- "http://example.com/1/",
- "http://example.com/2/",
- "http://example.com/3/",
- },
- ArtifactOfProjectURI: []string{
- "http://example.com/1/uri.whatever",
- "http://example.com/2/uri.whatever",
+ ArtifactOfProjects: []*spdx.ArtifactOfProject2_1{
+ &spdx.ArtifactOfProject2_1{
+ Name: "project1",
+ HomePage: "http://example.com/1/",
+ URI: "http://example.com/1/uri.whatever",
+ },
+ &spdx.ArtifactOfProject2_1{
+ Name: "project2",
+ },
+ &spdx.ArtifactOfProject2_1{
+ Name: "project3",
+ HomePage: "http://example.com/3/",
+ },
+ &spdx.ArtifactOfProject2_1{
+ Name: "project4",
+ URI: "http://example.com/4/uri.whatever",
+ },
},
FileComment: "this is a file comment",
FileNotice: "This file may be used under either Apache-2.0 or Apache-1.1.",
@@ -69,14 +72,13 @@ LicenseInfoInFile: Apache-1.1
LicenseComments: this is a license comment(s)
FileCopyrightText: Copyright (c) Jane Doe
ArtifactOfProjectName: project1
+ArtifactOfProjectHomePage: http://example.com/1/
+ArtifactOfProjectURI: http://example.com/1/uri.whatever
ArtifactOfProjectName: project2
ArtifactOfProjectName: project3
-ArtifactOfProjectName: project4
-ArtifactOfProjectHomePage: http://example.com/1/
-ArtifactOfProjectHomePage: http://example.com/2/
ArtifactOfProjectHomePage: http://example.com/3/
-ArtifactOfProjectURI: http://example.com/1/uri.whatever
-ArtifactOfProjectURI: http://example.com/2/uri.whatever
+ArtifactOfProjectName: project4
+ArtifactOfProjectURI: http://example.com/4/uri.whatever
FileComment: this is a file comment
FileNotice: This file may be used under either Apache-2.0 or Apache-1.1.
FileContributor: John Doe jdoe@example.com