github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/pkg/cataloger/python/parse_setup.go (about) 1 package python 2 3 import ( 4 "bufio" 5 "context" 6 "regexp" 7 "strings" 8 9 "github.com/anchore/syft/internal/log" 10 "github.com/anchore/syft/syft/artifact" 11 "github.com/anchore/syft/syft/file" 12 "github.com/anchore/syft/syft/pkg" 13 "github.com/anchore/syft/syft/pkg/cataloger/generic" 14 ) 15 16 // integrity check 17 var _ generic.Parser = parseSetup 18 19 // match examples: 20 // 21 // 'pathlib3==2.2.0;python_version<"3.6"' --> match(name=pathlib3 version=2.2.0) 22 // "mypy==v0.770", --> match(name=mypy version=v0.770) 23 // " mypy2 == v0.770", ' mypy3== v0.770', --> match(name=mypy2 version=v0.770), match(name=mypy3, version=v0.770) 24 var pinnedDependency = regexp.MustCompile(`['"]\W?(\w+\W?==\W?[\w.]*)`) 25 26 func parseSetup(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { 27 var packages []pkg.Package 28 29 scanner := bufio.NewScanner(reader) 30 31 for scanner.Scan() { 32 line := scanner.Text() 33 line = strings.TrimRight(line, "\n") 34 35 for _, match := range pinnedDependency.FindAllString(line, -1) { 36 parts := strings.Split(match, "==") 37 if len(parts) != 2 { 38 continue 39 } 40 name := strings.Trim(parts[0], "'\"") 41 name = strings.TrimSpace(name) 42 name = strings.Trim(name, "'\"") 43 44 version := strings.TrimSpace(parts[len(parts)-1]) 45 version = strings.Trim(version, "'\"") 46 47 if hasTemplateDirective(name) || hasTemplateDirective(version) { 48 // this can happen in more dynamic setup.py where there is templating 49 continue 50 } 51 52 if name == "" || version == "" { 53 log.WithFields("path", reader.RealPath).Debugf("unable to parse package in setup.py line: %q", line) 54 continue 55 } 56 57 packages = append( 58 packages, 59 newPackageForIndex( 60 name, 61 version, 62 reader.Location.WithAnnotation(pkg.EvidenceAnnotationKey, pkg.PrimaryEvidenceAnnotation), 63 ), 64 ) 65 } 66 } 67 68 return packages, nil, nil 69 } 70 71 func hasTemplateDirective(s string) bool { 72 return strings.Contains(s, `%s`) || strings.Contains(s, `{`) || strings.Contains(s, `}`) 73 }