code.gitea.io/gitea@v1.21.7/models/packages/conan/search.go (about) 1 // Copyright 2022 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package conan 5 6 import ( 7 "context" 8 "fmt" 9 "strconv" 10 "strings" 11 12 "code.gitea.io/gitea/models/db" 13 "code.gitea.io/gitea/models/packages" 14 "code.gitea.io/gitea/modules/container" 15 conan_module "code.gitea.io/gitea/modules/packages/conan" 16 17 "xorm.io/builder" 18 ) 19 20 // buildCondition creates a Like condition if a wildcard is present. Otherwise Eq is used. 21 func buildCondition(name, value string) builder.Cond { 22 if strings.Contains(value, "*") { 23 return builder.Like{name, strings.ReplaceAll(strings.ReplaceAll(value, "_", "\\_"), "*", "%")} 24 } 25 return builder.Eq{name: value} 26 } 27 28 type RecipeSearchOptions struct { 29 OwnerID int64 30 Name string 31 Version string 32 User string 33 Channel string 34 } 35 36 // SearchRecipes gets all recipes matching the search options 37 func SearchRecipes(ctx context.Context, opts *RecipeSearchOptions) ([]string, error) { 38 var cond builder.Cond = builder.Eq{ 39 "package_file.is_lead": true, 40 "package.type": packages.TypeConan, 41 "package.owner_id": opts.OwnerID, 42 "package_version.is_internal": false, 43 } 44 45 if opts.Name != "" { 46 cond = cond.And(buildCondition("package.lower_name", strings.ToLower(opts.Name))) 47 } 48 if opts.Version != "" { 49 cond = cond.And(buildCondition("package_version.lower_version", strings.ToLower(opts.Version))) 50 } 51 if opts.User != "" || opts.Channel != "" { 52 var propsCond builder.Cond = builder.Eq{ 53 "package_property.ref_type": packages.PropertyTypeFile, 54 } 55 propsCond = propsCond.And(builder.Expr("package_property.ref_id = package_file.id")) 56 57 count := 0 58 propsCondBlock := builder.NewCond() 59 if opts.User != "" { 60 count++ 61 propsCondBlock = propsCondBlock.Or(builder.Eq{"package_property.name": conan_module.PropertyRecipeUser}.And(buildCondition("package_property.value", opts.User))) 62 } 63 if opts.Channel != "" { 64 count++ 65 propsCondBlock = propsCondBlock.Or(builder.Eq{"package_property.name": conan_module.PropertyRecipeChannel}.And(buildCondition("package_property.value", opts.Channel))) 66 } 67 propsCond = propsCond.And(propsCondBlock) 68 69 cond = cond.And(builder.Eq{ 70 strconv.Itoa(count): builder.Select("COUNT(*)").Where(propsCond).From("package_property"), 71 }) 72 } 73 74 query := builder. 75 Select("package.name, package_version.version, package_file.id"). 76 From("package_file"). 77 InnerJoin("package_version", "package_version.id = package_file.version_id"). 78 InnerJoin("package", "package.id = package_version.package_id"). 79 Where(cond) 80 81 results := make([]struct { 82 Name string 83 Version string 84 ID int64 85 }, 0, 5) 86 err := db.GetEngine(ctx).SQL(query).Find(&results) 87 if err != nil { 88 return nil, err 89 } 90 91 unique := make(container.Set[string]) 92 for _, info := range results { 93 recipe := fmt.Sprintf("%s/%s", info.Name, info.Version) 94 95 props, _ := packages.GetProperties(ctx, packages.PropertyTypeFile, info.ID) 96 if len(props) > 0 { 97 var ( 98 user = "" 99 channel = "" 100 ) 101 for _, prop := range props { 102 if prop.Name == conan_module.PropertyRecipeUser { 103 user = prop.Value 104 } 105 if prop.Name == conan_module.PropertyRecipeChannel { 106 channel = prop.Value 107 } 108 } 109 if user != "" && channel != "" { 110 recipe = fmt.Sprintf("%s@%s/%s", recipe, user, channel) 111 } 112 } 113 114 unique.Add(recipe) 115 } 116 117 recipes := make([]string, 0, len(unique)) 118 for recipe := range unique { 119 recipes = append(recipes, recipe) 120 } 121 return recipes, nil 122 } 123 124 // GetPackageInfo gets the Conaninfo for a package 125 func GetPackageInfo(ctx context.Context, ownerID int64, ref *conan_module.PackageReference) (string, error) { 126 values, err := findPropertyValues( 127 ctx, 128 conan_module.PropertyPackageInfo, 129 ownerID, 130 ref.Recipe.Name, 131 ref.Recipe.Version, 132 map[string]string{ 133 conan_module.PropertyRecipeUser: ref.Recipe.User, 134 conan_module.PropertyRecipeChannel: ref.Recipe.Channel, 135 conan_module.PropertyRecipeRevision: ref.Recipe.Revision, 136 conan_module.PropertyPackageReference: ref.Reference, 137 conan_module.PropertyPackageRevision: ref.Revision, 138 }, 139 ) 140 if err != nil { 141 return "", err 142 } 143 144 if len(values) == 0 { 145 return "", ErrPackageReferenceNotExist 146 } 147 148 return values[0].Value, nil 149 }