code.gitea.io/gitea@v1.21.7/routers/api/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 "net/http" 8 "strings" 9 10 conan_model "code.gitea.io/gitea/models/packages/conan" 11 user_model "code.gitea.io/gitea/models/user" 12 "code.gitea.io/gitea/modules/context" 13 "code.gitea.io/gitea/modules/json" 14 conan_module "code.gitea.io/gitea/modules/packages/conan" 15 ) 16 17 // SearchResult contains the found recipe names 18 type SearchResult struct { 19 Results []string `json:"results"` 20 } 21 22 // SearchRecipes searches all recipes matching the query 23 func SearchRecipes(ctx *context.Context) { 24 q := ctx.FormTrim("q") 25 26 opts := parseQuery(ctx.Package.Owner, q) 27 28 results, err := conan_model.SearchRecipes(ctx, opts) 29 if err != nil { 30 apiError(ctx, http.StatusInternalServerError, err) 31 return 32 } 33 34 jsonResponse(ctx, http.StatusOK, &SearchResult{ 35 Results: results, 36 }) 37 } 38 39 // parseQuery creates search options for the given query 40 func parseQuery(owner *user_model.User, query string) *conan_model.RecipeSearchOptions { 41 opts := &conan_model.RecipeSearchOptions{ 42 OwnerID: owner.ID, 43 } 44 45 if query != "" { 46 parts := strings.Split(strings.ReplaceAll(query, "@", "/"), "/") 47 48 opts.Name = parts[0] 49 if len(parts) > 1 && parts[1] != "*" { 50 opts.Version = parts[1] 51 } 52 if len(parts) > 2 && parts[2] != "*" { 53 opts.User = parts[2] 54 } 55 if len(parts) > 3 && parts[3] != "*" { 56 opts.Channel = parts[3] 57 } 58 } 59 60 return opts 61 } 62 63 // SearchPackagesV1 searches all packages of a recipe (Conan v1 endpoint) 64 func SearchPackagesV1(ctx *context.Context) { 65 searchPackages(ctx, true) 66 } 67 68 // SearchPackagesV2 searches all packages of a recipe (Conan v2 endpoint) 69 func SearchPackagesV2(ctx *context.Context) { 70 searchPackages(ctx, false) 71 } 72 73 func searchPackages(ctx *context.Context, searchAllRevisions bool) { 74 rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference) 75 76 if !searchAllRevisions && rref.Revision == "" { 77 lastRevision, err := conan_model.GetLastRecipeRevision(ctx, ctx.Package.Owner.ID, rref) 78 if err != nil { 79 if err == conan_model.ErrRecipeReferenceNotExist { 80 apiError(ctx, http.StatusNotFound, err) 81 } else { 82 apiError(ctx, http.StatusInternalServerError, err) 83 } 84 return 85 } 86 rref = rref.WithRevision(lastRevision.Value) 87 } else { 88 has, err := conan_model.RecipeExists(ctx, ctx.Package.Owner.ID, rref) 89 if err != nil { 90 if err == conan_model.ErrRecipeReferenceNotExist { 91 apiError(ctx, http.StatusNotFound, err) 92 } else { 93 apiError(ctx, http.StatusInternalServerError, err) 94 } 95 return 96 } 97 if !has { 98 apiError(ctx, http.StatusNotFound, nil) 99 return 100 } 101 } 102 103 recipeRevisions := []*conan_model.PropertyValue{{Value: rref.Revision}} 104 if searchAllRevisions { 105 var err error 106 recipeRevisions, err = conan_model.GetRecipeRevisions(ctx, ctx.Package.Owner.ID, rref) 107 if err != nil { 108 apiError(ctx, http.StatusInternalServerError, err) 109 return 110 } 111 } 112 113 result := make(map[string]*conan_module.Conaninfo) 114 115 for _, recipeRevision := range recipeRevisions { 116 currentRef := rref 117 if recipeRevision.Value != "" { 118 currentRef = rref.WithRevision(recipeRevision.Value) 119 } 120 packageReferences, err := conan_model.GetPackageReferences(ctx, ctx.Package.Owner.ID, currentRef) 121 if err != nil { 122 if err == conan_model.ErrRecipeReferenceNotExist { 123 apiError(ctx, http.StatusNotFound, err) 124 } else { 125 apiError(ctx, http.StatusInternalServerError, err) 126 } 127 return 128 } 129 for _, packageReference := range packageReferences { 130 if _, ok := result[packageReference.Value]; ok { 131 continue 132 } 133 pref, _ := conan_module.NewPackageReference(currentRef, packageReference.Value, "") 134 lastPackageRevision, err := conan_model.GetLastPackageRevision(ctx, ctx.Package.Owner.ID, pref) 135 if err != nil { 136 if err == conan_model.ErrPackageReferenceNotExist { 137 apiError(ctx, http.StatusNotFound, err) 138 } else { 139 apiError(ctx, http.StatusInternalServerError, err) 140 } 141 return 142 } 143 pref = pref.WithRevision(lastPackageRevision.Value) 144 infoRaw, err := conan_model.GetPackageInfo(ctx, ctx.Package.Owner.ID, pref) 145 if err != nil { 146 if err == conan_model.ErrPackageReferenceNotExist { 147 apiError(ctx, http.StatusNotFound, err) 148 } else { 149 apiError(ctx, http.StatusInternalServerError, err) 150 } 151 return 152 } 153 var info *conan_module.Conaninfo 154 if err := json.Unmarshal([]byte(infoRaw), &info); err != nil { 155 apiError(ctx, http.StatusInternalServerError, err) 156 return 157 } 158 result[pref.Reference] = info 159 } 160 } 161 162 jsonResponse(ctx, http.StatusOK, result) 163 }