1*ba677afaSXin Li// SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 2*ba677afaSXin Li 3*ba677afaSXin Li// Example for: *licensediff*, *tvloader* 4*ba677afaSXin Li 5*ba677afaSXin Li// This example demonstrates loading two SPDX tag-value files from disk into 6*ba677afaSXin Li// memory, and generating a diff of the concluded licenses for Files in 7*ba677afaSXin Li// Packages with matching IDs in each document. 8*ba677afaSXin Li// This is generally only useful when run with two SPDX documents that 9*ba677afaSXin Li// describe licenses for subsequent versions of the same set of files, AND if 10*ba677afaSXin Li// they have the same identifier in both documents. 11*ba677afaSXin Li// Run project: go run example_licensediff.go ../sample-docs/tv/hello.spdx ../sample-docs/tv/hello-modified.spdx 12*ba677afaSXin Lipackage main 13*ba677afaSXin Li 14*ba677afaSXin Liimport ( 15*ba677afaSXin Li "fmt" 16*ba677afaSXin Li "os" 17*ba677afaSXin Li 18*ba677afaSXin Li "github.com/spdx/tools-golang/licensediff" 19*ba677afaSXin Li "github.com/spdx/tools-golang/spdx/v2_2" 20*ba677afaSXin Li "github.com/spdx/tools-golang/spdxlib" 21*ba677afaSXin Li "github.com/spdx/tools-golang/tvloader" 22*ba677afaSXin Li) 23*ba677afaSXin Li 24*ba677afaSXin Lifunc main() { 25*ba677afaSXin Li 26*ba677afaSXin Li // check that we've received the right number of arguments 27*ba677afaSXin Li args := os.Args 28*ba677afaSXin Li if len(args) != 3 { 29*ba677afaSXin Li fmt.Printf("Usage: %v <spdx-file-first> <spdx-file-second>\n", args[0]) 30*ba677afaSXin Li fmt.Printf(" Load SPDX 2.2 tag-value files <spdx-file-first> and <spdx-file-second>,\n") 31*ba677afaSXin Li fmt.Printf(" run a diff between their concluded licenses, and print basic results.\n") 32*ba677afaSXin Li return 33*ba677afaSXin Li } 34*ba677afaSXin Li 35*ba677afaSXin Li // open the first SPDX file 36*ba677afaSXin Li filenameFirst := args[1] 37*ba677afaSXin Li r, err := os.Open(filenameFirst) 38*ba677afaSXin Li if err != nil { 39*ba677afaSXin Li fmt.Printf("Error while opening %v for reading: %v", filenameFirst, err) 40*ba677afaSXin Li return 41*ba677afaSXin Li } 42*ba677afaSXin Li defer r.Close() 43*ba677afaSXin Li 44*ba677afaSXin Li // try to load the first SPDX file's contents as a tag-value file, version 2.2 45*ba677afaSXin Li docFirst, err := tvloader.Load2_2(r) 46*ba677afaSXin Li if err != nil { 47*ba677afaSXin Li fmt.Printf("Error while parsing %v: %v", filenameFirst, err) 48*ba677afaSXin Li return 49*ba677afaSXin Li } 50*ba677afaSXin Li // check whether the SPDX file has at least one package that it describes 51*ba677afaSXin Li pkgIDsFirst, err := spdxlib.GetDescribedPackageIDs2_2(docFirst) 52*ba677afaSXin Li if err != nil { 53*ba677afaSXin Li fmt.Printf("Unable to get describe packages from first SPDX document: %v\n", err) 54*ba677afaSXin Li return 55*ba677afaSXin Li } 56*ba677afaSXin Li 57*ba677afaSXin Li // if we got here, the file is now loaded into memory. 58*ba677afaSXin Li fmt.Printf("Successfully loaded first SPDX file %s\n", filenameFirst) 59*ba677afaSXin Li 60*ba677afaSXin Li // open the second SPDX file 61*ba677afaSXin Li filenameSecond := args[2] 62*ba677afaSXin Li r, err = os.Open(filenameSecond) 63*ba677afaSXin Li if err != nil { 64*ba677afaSXin Li fmt.Printf("Error while opening %v for reading: %v", filenameSecond, err) 65*ba677afaSXin Li return 66*ba677afaSXin Li } 67*ba677afaSXin Li defer r.Close() 68*ba677afaSXin Li 69*ba677afaSXin Li // try to load the second SPDX file's contents as a tag-value file, version 2.2 70*ba677afaSXin Li docSecond, err := tvloader.Load2_2(r) 71*ba677afaSXin Li if err != nil { 72*ba677afaSXin Li fmt.Printf("Error while parsing %v: %v", filenameSecond, err) 73*ba677afaSXin Li return 74*ba677afaSXin Li } 75*ba677afaSXin Li // check whether the SPDX file has at least one package that it describes 76*ba677afaSXin Li pkgIDsSecond, err := spdxlib.GetDescribedPackageIDs2_2(docSecond) 77*ba677afaSXin Li if err != nil { 78*ba677afaSXin Li fmt.Printf("Unable to get describe packages from second SPDX document: %v\n", err) 79*ba677afaSXin Li return 80*ba677afaSXin Li } 81*ba677afaSXin Li 82*ba677afaSXin Li // if we got here, the file is now loaded into memory. 83*ba677afaSXin Li fmt.Printf("Successfully loaded second SPDX file %s\n\n", filenameSecond) 84*ba677afaSXin Li 85*ba677afaSXin Li // compare the described packages from each Document, by SPDX ID 86*ba677afaSXin Li // go through the first set first, report if they aren't in the second set 87*ba677afaSXin Li for _, pkgID := range pkgIDsFirst { 88*ba677afaSXin Li fmt.Printf("================================\n") 89*ba677afaSXin Li 90*ba677afaSXin Li var p1, p2 *v2_2.Package 91*ba677afaSXin Li var okFirst, okSecond bool 92*ba677afaSXin Li for _, pkg := range docFirst.Packages { 93*ba677afaSXin Li if pkg.PackageSPDXIdentifier == pkgID { 94*ba677afaSXin Li okFirst = true 95*ba677afaSXin Li p1 = pkg 96*ba677afaSXin Li break 97*ba677afaSXin Li } 98*ba677afaSXin Li } 99*ba677afaSXin Li if !okFirst { 100*ba677afaSXin Li fmt.Printf("Package %s has described relationship in first document but ID not found\n", string(pkgID)) 101*ba677afaSXin Li continue 102*ba677afaSXin Li } 103*ba677afaSXin Li 104*ba677afaSXin Li fmt.Printf("Package %s (%s)\n", string(pkgID), p1.PackageName) 105*ba677afaSXin Li 106*ba677afaSXin Li for _, pkg := range docSecond.Packages { 107*ba677afaSXin Li if pkg.PackageSPDXIdentifier == pkgID { 108*ba677afaSXin Li okSecond = true 109*ba677afaSXin Li p2 = pkg 110*ba677afaSXin Li break 111*ba677afaSXin Li } 112*ba677afaSXin Li } 113*ba677afaSXin Li if !okSecond { 114*ba677afaSXin Li fmt.Printf(" Found in first document, not found in second\n") 115*ba677afaSXin Li continue 116*ba677afaSXin Li } 117*ba677afaSXin Li 118*ba677afaSXin Li // now, run a diff between the two 119*ba677afaSXin Li pairs, err := licensediff.MakePairs2_2(p1, p2) 120*ba677afaSXin Li if err != nil { 121*ba677afaSXin Li fmt.Printf(" Error generating licensediff pairs: %v\n", err) 122*ba677afaSXin Li continue 123*ba677afaSXin Li } 124*ba677afaSXin Li 125*ba677afaSXin Li // take the pairs and turn them into a more structured results set 126*ba677afaSXin Li resultSet, err := licensediff.MakeResults(pairs) 127*ba677afaSXin Li if err != nil { 128*ba677afaSXin Li fmt.Printf(" Error generating licensediff results set: %v\n", err) 129*ba677afaSXin Li continue 130*ba677afaSXin Li } 131*ba677afaSXin Li 132*ba677afaSXin Li // print some information about the results 133*ba677afaSXin Li fmt.Printf(" Files in first only: %d\n", len(resultSet.InFirstOnly)) 134*ba677afaSXin Li fmt.Printf(" Files in second only: %d\n", len(resultSet.InSecondOnly)) 135*ba677afaSXin Li fmt.Printf(" Files in both with different licenses: %d\n", len(resultSet.InBothChanged)) 136*ba677afaSXin Li fmt.Printf(" Files in both with same licenses: %d\n", len(resultSet.InBothSame)) 137*ba677afaSXin Li } 138*ba677afaSXin Li 139*ba677afaSXin Li // now report if there are any package IDs in the second set that aren't 140*ba677afaSXin Li // in the first 141*ba677afaSXin Li for _, pkgID := range pkgIDsSecond { 142*ba677afaSXin Li var p2 *v2_2.Package 143*ba677afaSXin Li var okFirst, okSecond bool 144*ba677afaSXin Li for _, pkg := range docSecond.Packages { 145*ba677afaSXin Li if pkg.PackageSPDXIdentifier == pkgID { 146*ba677afaSXin Li okSecond = true 147*ba677afaSXin Li p2 = pkg 148*ba677afaSXin Li break 149*ba677afaSXin Li } 150*ba677afaSXin Li } 151*ba677afaSXin Li if !okSecond { 152*ba677afaSXin Li fmt.Printf("================================\n") 153*ba677afaSXin Li fmt.Printf("Package %s has described relationship in second document but ID not found\n", string(pkgID)) 154*ba677afaSXin Li continue 155*ba677afaSXin Li } 156*ba677afaSXin Li 157*ba677afaSXin Li for _, pkg := range docFirst.Packages { 158*ba677afaSXin Li if pkg.PackageSPDXIdentifier == pkgID { 159*ba677afaSXin Li okFirst = true 160*ba677afaSXin Li break 161*ba677afaSXin Li } 162*ba677afaSXin Li } 163*ba677afaSXin Li if !okFirst { 164*ba677afaSXin Li fmt.Printf("================================\n") 165*ba677afaSXin Li fmt.Printf("Package %s (%s)\n", string(pkgID), p2.PackageName) 166*ba677afaSXin Li fmt.Printf(" Found in second document, not found in first\n") 167*ba677afaSXin Li } 168*ba677afaSXin Li } 169*ba677afaSXin Li} 170