github.com/kastenhq/syft@v0.0.0-20230821225854-0710af25cdbe/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  }