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 }