github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/internal/spdxlicense/generate/license.go (about) 1 package main 2 3 import ( 4 "strings" 5 6 "github.com/scylladb/go-set/strset" 7 ) 8 9 type LicenseList struct { 10 Version string `json:"licenseListVersion"` 11 Licenses []License `json:"licenses"` 12 } 13 14 type License struct { 15 ID string `json:"licenseId"` 16 Name string `json:"name"` 17 Text string `json:"licenseText"` 18 Deprecated bool `json:"isDeprecatedLicenseId"` 19 OSIApproved bool `json:"isOsiApproved"` 20 SeeAlso []string `json:"seeAlso"` 21 } 22 23 // findReplacementLicense returns a replacement license for a deprecated license 24 func (ll LicenseList) findReplacementLicense(deprecated License) *License { 25 for _, l := range ll.Licenses { 26 if l.canReplace(deprecated) { 27 return &l 28 } 29 } 30 31 return nil 32 } 33 34 func (l License) canReplace(deprecated License) bool { 35 // don't replace a license with a deprecated license 36 if l.Deprecated { 37 return false 38 } 39 40 // We want to replace deprecated licenses with non-deprecated counterparts 41 // For more information, see: https://github.com/spdx/license-list-XML/issues/1676 42 switch { 43 case strings.ReplaceAll(l.ID, "-only", "") == deprecated.ID: 44 return true 45 case strings.ReplaceAll(l.ID, "-or-later", "+") == deprecated.ID: 46 return true 47 case l.ID == "BSD-2-Clause" && deprecated.ID == "BSD-2-Clause-NetBSD": 48 return true 49 case l.ID == "BSD-2-Clause-Views" && deprecated.ID == "BSD-2-Clause-FreeBSD": 50 return true 51 case l.ID == "bzip2-1.0.6" && deprecated.ID == "bzip2-1.0.5": 52 return true 53 case l.ID == "SMLNJ" && deprecated.ID == "StandardML-NJ": 54 return true 55 } 56 57 if l.Name != deprecated.Name { 58 return false 59 } 60 61 if l.OSIApproved != deprecated.OSIApproved { 62 return false 63 } 64 65 if len(l.SeeAlso) != len(deprecated.SeeAlso) { 66 return false 67 } 68 69 for i, sa := range l.SeeAlso { 70 if sa != deprecated.SeeAlso[i] { 71 return false 72 } 73 } 74 75 return l.ID == deprecated.ID 76 } 77 78 func buildLicenseIDPermutations(cleanID string) (perms []string) { 79 lv := findLicenseVersion(cleanID) 80 addPlusPermutation := strings.HasSuffix(cleanID, "orlater") 81 vp := versionPermutations(lv) 82 permSet := strset.New() 83 version := strings.Join(lv, ".") 84 for _, p := range vp { 85 if addPlusPermutation { 86 base := strings.TrimSuffix(cleanID, "orlater") 87 plus := p + "+" 88 permSet.Add(strings.Replace(base, version, plus, 1)) 89 } 90 permSet.Add(strings.Replace(cleanID, version, p, 1)) 91 } 92 93 permSet.Add(cleanID) 94 return permSet.List() 95 } 96 97 func findLicenseVersion(license string) (version []string) { 98 versionList := versionMatch.FindAllStringSubmatch(license, -1) 99 100 if len(versionList) == 0 { 101 return version 102 } 103 104 for i, v := range versionList[0] { 105 if v != "" && i != 0 { 106 version = append(version, v) 107 } 108 } 109 110 return version 111 } 112 113 func versionPermutations(version []string) []string { 114 ver := append([]string(nil), version...) 115 perms := strset.New() 116 for i := 1; i <= 3; i++ { 117 if len(ver) < i+1 { 118 ver = append(ver, "0") 119 } 120 121 perm := strings.Join(ver[:i], ".") 122 badCount := strings.Count(perm, "0") + strings.Count(perm, ".") 123 124 if badCount != len(perm) { 125 perms.Add(perm) 126 } 127 } 128 129 return perms.List() 130 }