github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/pkg/cataloger/python/package.go (about) 1 package python 2 3 import ( 4 "fmt" 5 6 "github.com/anchore/packageurl-go" 7 "github.com/anchore/syft/internal/licenses" 8 "github.com/anchore/syft/internal/log" 9 "github.com/anchore/syft/syft/file" 10 "github.com/anchore/syft/syft/pkg" 11 ) 12 13 func newPackageForIndex(name, version string, locations ...file.Location) pkg.Package { 14 p := pkg.Package{ 15 Name: name, 16 Version: version, 17 Locations: file.NewLocationSet(locations...), 18 PURL: packageURL(name, version, nil), 19 Language: pkg.Python, 20 Type: pkg.PythonPkg, 21 } 22 23 p.SetID() 24 25 return p 26 } 27 28 func newPackageForIndexWithMetadata(name, version string, metadata interface{}, locations ...file.Location) pkg.Package { 29 p := pkg.Package{ 30 Name: name, 31 Version: version, 32 Locations: file.NewLocationSet(locations...), 33 PURL: packageURL(name, version, nil), 34 Language: pkg.Python, 35 Type: pkg.PythonPkg, 36 Metadata: metadata, 37 } 38 39 p.SetID() 40 41 return p 42 } 43 44 func newPackageForRequirementsWithMetadata(name, version string, metadata pkg.PythonRequirementsEntry, locations ...file.Location) pkg.Package { 45 p := pkg.Package{ 46 Name: name, 47 Version: version, 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 newPackageForPackage(resolver file.Resolver, m parsedData, sources ...file.Location) pkg.Package { 61 var licenseSet pkg.LicenseSet 62 63 switch { 64 case m.LicenseExpression != "": 65 licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromLocation(m.LicenseLocation, m.LicenseExpression)...) 66 case m.Licenses != "": 67 licenseSet = pkg.NewLicenseSet(pkg.NewLicensesFromLocation(m.LicenseLocation, m.Licenses)...) 68 case m.LicenseLocation.Path() != "": 69 // If we have a license file then resolve and parse it 70 found, err := resolver.FilesByPath(m.LicenseLocation.Path()) 71 if err != nil { 72 log.WithFields("error", err).Tracef("unable to resolve python license path %s", m.LicenseLocation.Path()) 73 } 74 if len(found) > 0 { 75 metadataContents, err := resolver.FileContentsByLocation(found[0]) 76 if err == nil { 77 parsed, err := licenses.Parse(metadataContents, m.LicenseLocation) 78 if err != nil { 79 log.WithFields("error", err).Tracef("unable to parse a license from the file in %s", m.LicenseLocation.Path()) 80 } 81 if len(parsed) > 0 { 82 licenseSet = pkg.NewLicenseSet(parsed...) 83 } 84 } else { 85 log.WithFields("error", err).Tracef("unable to read file contents at %s", m.LicenseLocation.Path()) 86 } 87 } 88 } 89 90 p := pkg.Package{ 91 Name: m.Name, 92 Version: m.Version, 93 PURL: packageURL(m.Name, m.Version, &m.PythonPackage), 94 Locations: file.NewLocationSet(sources...), 95 Licenses: licenseSet, 96 Language: pkg.Python, 97 Type: pkg.PythonPkg, 98 Metadata: m.PythonPackage, 99 } 100 101 p.SetID() 102 103 return p 104 } 105 106 func packageURL(name, version string, m *pkg.PythonPackage) string { 107 // generate a purl from the package data 108 pURL := packageurl.NewPackageURL( 109 packageurl.TypePyPi, 110 "", 111 name, 112 version, 113 purlQualifiersForPackage(m), 114 "") 115 116 return pURL.ToString() 117 } 118 119 func purlQualifiersForPackage(m *pkg.PythonPackage) packageurl.Qualifiers { 120 q := packageurl.Qualifiers{} 121 if m == nil { 122 return q 123 } 124 if m.DirectURLOrigin != nil { 125 q = append(q, vcsURLQualifierForPackage(m.DirectURLOrigin)...) 126 } 127 return q 128 } 129 130 func vcsURLQualifierForPackage(p *pkg.PythonDirectURLOriginInfo) packageurl.Qualifiers { 131 if p == nil || p.VCS == "" { 132 return nil 133 } 134 // Taken from https://github.com/package-url/purl-spec/blob/master/PURL-SPECIFICATION.rst#known-qualifiers-keyvalue-pairs 135 // packageurl-go still doesn't support all qualifier names 136 return packageurl.Qualifiers{ 137 {Key: pkg.PURLQualifierVCSURL, Value: fmt.Sprintf("%s+%s@%s", p.VCS, p.URL, p.CommitID)}, 138 } 139 }