github.com/noqcks/syft@v0.0.0-20230920222752-a9e2c4e288e5/syft/pkg/cataloger/deb/parse_copyright.go (about) 1 package deb 2 3 import ( 4 "bufio" 5 "io" 6 "regexp" 7 "sort" 8 "strings" 9 10 "github.com/anchore/syft/internal" 11 ) 12 13 // For more information see: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/#license-syntax 14 15 var ( 16 licensePattern = regexp.MustCompile(`^License: (?P<license>\S*)`) 17 commonLicensePathPattern = regexp.MustCompile(`/usr/share/common-licenses/(?P<license>[0-9A-Za-z_.\-]+)`) 18 ) 19 20 func parseLicensesFromCopyright(reader io.Reader) []string { 21 findings := internal.NewStringSet() 22 scanner := bufio.NewScanner(reader) 23 24 for scanner.Scan() { 25 line := scanner.Text() 26 if value := findLicenseClause(licensePattern, "license", line); value != "" { 27 findings.Add(value) 28 } 29 if value := findLicenseClause(commonLicensePathPattern, "license", line); value != "" { 30 findings.Add(value) 31 } 32 } 33 34 results := findings.ToSlice() 35 36 sort.Strings(results) 37 38 return results 39 } 40 41 func findLicenseClause(pattern *regexp.Regexp, valueGroup, line string) string { 42 matchesByGroup := internal.MatchNamedCaptureGroups(pattern, line) 43 44 candidate, ok := matchesByGroup[valueGroup] 45 if !ok { 46 return "" 47 } 48 49 return ensureIsSingleLicense(candidate) 50 } 51 52 func ensureIsSingleLicense(candidate string) (license string) { 53 candidate = strings.TrimSpace(candidate) 54 if strings.Contains(candidate, " or ") || strings.Contains(candidate, " and ") { 55 // this is a multi-license summary, ignore this as other recurrent license lines should cover this 56 return 57 } 58 if candidate != "" && strings.ToLower(candidate) != "none" { 59 // the license may be at the end of a sentence, clean . characters 60 license = strings.TrimSuffix(candidate, ".") 61 } 62 return license 63 }