github.com/anchore/syft@v1.38.2/syft/pkg/cataloger/python/package.go (about) 1 package python 2 3 import ( 4 "context" 5 "fmt" 6 "regexp" 7 "strings" 8 9 "github.com/anchore/packageurl-go" 10 "github.com/anchore/syft/syft/file" 11 "github.com/anchore/syft/syft/pkg" 12 ) 13 14 func normalize(name string) string { 15 // https://packaging.python.org/en/latest/specifications/name-normalization/ 16 re := regexp.MustCompile(`[-_.]+`) 17 normalized := re.ReplaceAllString(name, "-") 18 return strings.ToLower(normalized) 19 } 20 21 func newPackageForIndex(ctx context.Context, lr pythonLicenseResolver, name, version string, locations ...file.Location) pkg.Package { 22 name = normalize(name) 23 licenseSet := lr.getLicenses(ctx, name, version) 24 25 p := pkg.Package{ 26 Name: name, 27 Version: version, 28 Licenses: licenseSet, 29 Locations: file.NewLocationSet(locations...), 30 PURL: packageURL(name, version, nil), 31 Language: pkg.Python, 32 Type: pkg.PythonPkg, 33 } 34 35 p.SetID() 36 37 return p 38 } 39 40 func newPackageForIndexWithMetadata(ctx context.Context, lr pythonLicenseResolver, name, version string, metadata interface{}, locations ...file.Location) pkg.Package { 41 name = normalize(name) 42 licenseSet := lr.getLicenses(ctx, name, version) 43 44 p := pkg.Package{ 45 Name: name, 46 Version: version, 47 Licenses: licenseSet, 48 Locations: file.NewLocationSet(locations...), 49 PURL: packageURL(name, version, nil), 50 Language: pkg.Python, 51 Type: pkg.PythonPkg, 52 Metadata: metadata, 53 } 54 55 p.SetID() 56 57 return p 58 } 59 60 func newPackageForRequirementsWithMetadata(ctx context.Context, lr pythonLicenseResolver, name, version string, metadata pkg.PythonRequirementsEntry, locations ...file.Location) pkg.Package { 61 name = normalize(name) 62 licenseSet := lr.getLicenses(ctx, name, version) 63 64 p := pkg.Package{ 65 Name: name, 66 Version: version, 67 Licenses: licenseSet, 68 Locations: file.NewLocationSet(locations...), 69 PURL: packageURL(name, version, nil), 70 Language: pkg.Python, 71 Type: pkg.PythonPkg, 72 Metadata: metadata, 73 } 74 75 p.SetID() 76 77 return p 78 } 79 80 func newPackageForPackage(m parsedData, licenses pkg.LicenseSet, sources ...file.Location) pkg.Package { 81 name := normalize(m.Name) 82 83 p := pkg.Package{ 84 Name: name, 85 Version: m.Version, 86 PURL: packageURL(name, m.Version, &m.PythonPackage), 87 Locations: file.NewLocationSet(sources...), 88 Licenses: licenses, 89 Language: pkg.Python, 90 Type: pkg.PythonPkg, 91 Metadata: m.PythonPackage, 92 } 93 94 p.SetID() 95 96 return p 97 } 98 99 func packageURL(name, version string, m *pkg.PythonPackage) string { 100 // generate a purl from the package data 101 pURL := packageurl.NewPackageURL( 102 packageurl.TypePyPi, 103 "", 104 name, 105 version, 106 purlQualifiersForPackage(m), 107 "") 108 109 return pURL.ToString() 110 } 111 112 func purlQualifiersForPackage(m *pkg.PythonPackage) packageurl.Qualifiers { 113 q := packageurl.Qualifiers{} 114 if m == nil { 115 return q 116 } 117 if m.DirectURLOrigin != nil { 118 q = append(q, vcsURLQualifierForPackage(m.DirectURLOrigin)...) 119 } 120 return q 121 } 122 123 func vcsURLQualifierForPackage(p *pkg.PythonDirectURLOriginInfo) packageurl.Qualifiers { 124 if p == nil || p.VCS == "" { 125 return nil 126 } 127 // Taken from https://github.com/package-url/purl-spec/blob/master/PURL-SPECIFICATION.rst#known-qualifiers-keyvalue-pairs 128 // packageurl-go still doesn't support all qualifier names 129 return packageurl.Qualifiers{ 130 {Key: pkg.PURLQualifierVCSURL, Value: fmt.Sprintf("%s+%s@%s", p.VCS, p.URL, p.CommitID)}, 131 } 132 }