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  }