github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/syft/pkg/cataloger/cpp/package.go (about)

     1  package cpp
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/anchore/packageurl-go"
     7  	"github.com/anchore/syft/syft/file"
     8  	"github.com/anchore/syft/syft/pkg"
     9  )
    10  
    11  type conanRef struct {
    12  	Name      string
    13  	Version   string
    14  	User      string
    15  	Channel   string
    16  	Revision  string
    17  	PackageID string
    18  	Timestamp string
    19  }
    20  
    21  func splitConanRef(ref string) *conanRef {
    22  	// ConanfileEntry ref format is:
    23  	// pkg/0.1@user/channel#rrev%timestamp
    24  	// This method is based on conan's ref.loads method:
    25  	// https://github.com/conan-io/conan/blob/release/2.0/conans/model/recipe_ref.py#L93C21-L93C21
    26  
    27  	var cref conanRef
    28  
    29  	// timestamp
    30  	tokens := strings.Split(ref, "%")
    31  	text := tokens[0]
    32  	if len(tokens) == 2 {
    33  		cref.Timestamp = tokens[1]
    34  	}
    35  
    36  	// package_id
    37  	tokens = strings.Split(text, ":")
    38  	text = tokens[0]
    39  	if len(tokens) == 2 {
    40  		cref.PackageID = tokens[1]
    41  	}
    42  
    43  	// revision
    44  	tokens = strings.Split(text, "#")
    45  	ref = tokens[0]
    46  	if len(tokens) == 2 {
    47  		cref.Revision = tokens[1]
    48  	}
    49  
    50  	// name and version are always given
    51  	tokens = strings.Split(ref, "@")
    52  	nameAndVersion := strings.Split(tokens[0], "/")
    53  	if len(nameAndVersion) < 2 || nameAndVersion[0] == "" || nameAndVersion[1] == "" {
    54  		return nil
    55  	}
    56  	cref.Name = nameAndVersion[0]
    57  	cref.Version = nameAndVersion[1]
    58  	// user and channel
    59  	if len(tokens) == 2 && tokens[1] != "" {
    60  		tokens = strings.Split(tokens[1], "/")
    61  		if len(tokens) == 2 {
    62  			cref.User = tokens[0]
    63  			cref.Channel = tokens[1]
    64  		}
    65  	}
    66  	return &cref
    67  }
    68  
    69  func newConanfilePackage(m pkg.ConanfileEntry, locations ...file.Location) *pkg.Package {
    70  	return newConanPackage(m.Ref, m, locations...)
    71  }
    72  
    73  func newConanlockPackage(m pkg.ConanLockEntry, locations ...file.Location) *pkg.Package {
    74  	return newConanPackage(m.Ref, m, locations...)
    75  }
    76  
    77  func newConaninfoPackage(m pkg.ConaninfoEntry, locations ...file.Location) *pkg.Package {
    78  	return newConanPackage(m.Ref, m, locations...)
    79  }
    80  
    81  func newConanPackage(refStr string, metadata any, locations ...file.Location) *pkg.Package {
    82  	ref := splitConanRef(refStr)
    83  	if ref == nil {
    84  		return nil
    85  	}
    86  
    87  	p := pkg.Package{
    88  		Name:      ref.Name,
    89  		Version:   ref.Version,
    90  		Locations: file.NewLocationSet(locations...),
    91  		PURL:      packageURL(ref),
    92  		Language:  pkg.CPP,
    93  		Type:      pkg.ConanPkg,
    94  		Metadata:  metadata,
    95  	}
    96  
    97  	p.SetID()
    98  
    99  	return &p
   100  }
   101  
   102  func packageURL(ref *conanRef) string {
   103  	qualifiers := packageurl.Qualifiers{}
   104  	if ref.Channel != "" {
   105  		qualifiers = append(qualifiers, packageurl.Qualifier{
   106  			Key:   "channel",
   107  			Value: ref.Channel,
   108  		})
   109  	}
   110  	return packageurl.NewPackageURL(
   111  		packageurl.TypeConan,
   112  		ref.User,
   113  		ref.Name,
   114  		ref.Version,
   115  		qualifiers,
   116  		"",
   117  	).ToString()
   118  }