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