1// Package saver2v3 contains functions to render and write a tag-value 2// formatted version of an in-memory SPDX document and its sections 3// (version 2.2). 4// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 5package saver2v3 6 7import ( 8 "fmt" 9 "io" 10 "sort" 11 12 "github.com/spdx/tools-golang/spdx/common" 13 "github.com/spdx/tools-golang/spdx/v2_3" 14) 15 16// RenderDocument2_3 is the main entry point to take an SPDX in-memory 17// Document (version 2.2), and render it to the received io.Writer. 18// It is only exported in order to be available to the tvsaver package, 19// and typically does not need to be called by client code. 20func RenderDocument2_3(doc *v2_3.Document, w io.Writer) error { 21 if doc.CreationInfo == nil { 22 return fmt.Errorf("Document had nil CreationInfo section") 23 } 24 25 if doc.SPDXVersion != "" { 26 fmt.Fprintf(w, "SPDXVersion: %s\n", doc.SPDXVersion) 27 } 28 if doc.DataLicense != "" { 29 fmt.Fprintf(w, "DataLicense: %s\n", doc.DataLicense) 30 } 31 if doc.SPDXIdentifier != "" { 32 fmt.Fprintf(w, "SPDXID: %s\n", common.RenderElementID(doc.SPDXIdentifier)) 33 } 34 if doc.DocumentName != "" { 35 fmt.Fprintf(w, "DocumentName: %s\n", doc.DocumentName) 36 } 37 if doc.DocumentNamespace != "" { 38 fmt.Fprintf(w, "DocumentNamespace: %s\n", doc.DocumentNamespace) 39 } 40 // print EDRs in order sorted by identifier 41 sort.Slice(doc.ExternalDocumentReferences, func(i, j int) bool { 42 return doc.ExternalDocumentReferences[i].DocumentRefID < doc.ExternalDocumentReferences[j].DocumentRefID 43 }) 44 for _, edr := range doc.ExternalDocumentReferences { 45 fmt.Fprintf(w, "ExternalDocumentRef: DocumentRef-%s %s %s:%s\n", 46 edr.DocumentRefID, edr.URI, edr.Checksum.Algorithm, edr.Checksum.Value) 47 } 48 if doc.DocumentComment != "" { 49 fmt.Fprintf(w, "DocumentComment: %s\n", textify(doc.DocumentComment)) 50 } 51 52 renderCreationInfo2_3(doc.CreationInfo, w) 53 54 if len(doc.Files) > 0 { 55 fmt.Fprintf(w, "##### Unpackaged files\n\n") 56 sort.Slice(doc.Files, func(i, j int) bool { 57 return doc.Files[i].FileSPDXIdentifier < doc.Files[j].FileSPDXIdentifier 58 }) 59 for _, fi := range doc.Files { 60 renderFile2_3(fi, w) 61 } 62 } 63 64 // sort Packages by identifier 65 sort.Slice(doc.Packages, func(i, j int) bool { 66 return doc.Packages[i].PackageSPDXIdentifier < doc.Packages[j].PackageSPDXIdentifier 67 }) 68 for _, pkg := range doc.Packages { 69 fmt.Fprintf(w, "##### Package: %s\n\n", pkg.PackageName) 70 renderPackage2_3(pkg, w) 71 } 72 73 if len(doc.OtherLicenses) > 0 { 74 fmt.Fprintf(w, "##### Other Licenses\n\n") 75 for _, ol := range doc.OtherLicenses { 76 renderOtherLicense2_3(ol, w) 77 } 78 } 79 80 if len(doc.Relationships) > 0 { 81 fmt.Fprintf(w, "##### Relationships\n\n") 82 for _, rln := range doc.Relationships { 83 renderRelationship2_3(rln, w) 84 } 85 fmt.Fprintf(w, "\n") 86 } 87 88 if len(doc.Annotations) > 0 { 89 fmt.Fprintf(w, "##### Annotations\n\n") 90 for _, ann := range doc.Annotations { 91 renderAnnotation2_3(ann, w) 92 fmt.Fprintf(w, "\n") 93 } 94 } 95 96 if len(doc.Reviews) > 0 { 97 fmt.Fprintf(w, "##### Reviews\n\n") 98 for _, rev := range doc.Reviews { 99 renderReview2_3(rev, w) 100 } 101 } 102 103 return nil 104} 105