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