123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803 |
- // Copyright 2022 The Gitea Authors. All rights reserved.
- // SPDX-License-Identifier: MIT
-
- package conan
-
- import (
- std_ctx "context"
- "fmt"
- "io"
- "net/http"
- "strings"
- "time"
-
- "code.gitea.io/gitea/models/db"
- packages_model "code.gitea.io/gitea/models/packages"
- conan_model "code.gitea.io/gitea/models/packages/conan"
- "code.gitea.io/gitea/modules/container"
- "code.gitea.io/gitea/modules/json"
- "code.gitea.io/gitea/modules/log"
- packages_module "code.gitea.io/gitea/modules/packages"
- conan_module "code.gitea.io/gitea/modules/packages/conan"
- "code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/routers/api/packages/helper"
- "code.gitea.io/gitea/services/context"
- notify_service "code.gitea.io/gitea/services/notify"
- packages_service "code.gitea.io/gitea/services/packages"
- )
-
- const (
- conanfileFile = "conanfile.py"
- conaninfoFile = "conaninfo.txt"
-
- recipeReferenceKey = "RecipeReference"
- packageReferenceKey = "PackageReference"
- )
-
- var (
- recipeFileList = container.SetOf(
- conanfileFile,
- "conanmanifest.txt",
- "conan_sources.tgz",
- "conan_export.tgz",
- )
- packageFileList = container.SetOf(
- conaninfoFile,
- "conanmanifest.txt",
- "conan_package.tgz",
- )
- )
-
- func jsonResponse(ctx *context.Context, status int, obj any) {
- // https://github.com/conan-io/conan/issues/6613
- ctx.Resp.Header().Set("Content-Type", "application/json")
- ctx.Status(status)
- if err := json.NewEncoder(ctx.Resp).Encode(obj); err != nil {
- log.Error("JSON encode: %v", err)
- }
- }
-
- func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- jsonResponse(ctx, status, map[string]string{
- "message": message,
- })
- })
- }
-
- func baseURL(ctx *context.Context) string {
- return setting.AppURL + "api/packages/" + ctx.Package.Owner.Name + "/conan"
- }
-
- // ExtractPathParameters is a middleware to extract common parameters from path
- func ExtractPathParameters(ctx *context.Context) {
- rref, err := conan_module.NewRecipeReference(
- ctx.Params("name"),
- ctx.Params("version"),
- ctx.Params("user"),
- ctx.Params("channel"),
- ctx.Params("recipe_revision"),
- )
- if err != nil {
- apiError(ctx, http.StatusBadRequest, err)
- return
- }
-
- ctx.Data[recipeReferenceKey] = rref
-
- reference := ctx.Params("package_reference")
-
- var pref *conan_module.PackageReference
- if reference != "" {
- pref, err = conan_module.NewPackageReference(
- rref,
- reference,
- ctx.Params("package_revision"),
- )
- if err != nil {
- apiError(ctx, http.StatusBadRequest, err)
- return
- }
- }
-
- ctx.Data[packageReferenceKey] = pref
- }
-
- // Ping reports the server capabilities
- func Ping(ctx *context.Context) {
- ctx.RespHeader().Add("X-Conan-Server-Capabilities", "revisions") // complex_search,checksum_deploy,matrix_params
-
- ctx.Status(http.StatusOK)
- }
-
- // Authenticate creates an authentication token for the user
- func Authenticate(ctx *context.Context) {
- if ctx.Doer == nil {
- apiError(ctx, http.StatusBadRequest, nil)
- return
- }
-
- token, err := packages_service.CreateAuthorizationToken(ctx.Doer)
- if err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
-
- ctx.PlainText(http.StatusOK, token)
- }
-
- // CheckCredentials tests if the provided authentication token is valid
- func CheckCredentials(ctx *context.Context) {
- if ctx.Doer == nil {
- ctx.Status(http.StatusUnauthorized)
- } else {
- ctx.Status(http.StatusOK)
- }
- }
-
- // RecipeSnapshot displays the recipe files with their md5 hash
- func RecipeSnapshot(ctx *context.Context) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
-
- serveSnapshot(ctx, rref.AsKey())
- }
-
- // RecipeSnapshot displays the package files with their md5 hash
- func PackageSnapshot(ctx *context.Context) {
- pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
-
- serveSnapshot(ctx, pref.AsKey())
- }
-
- func serveSnapshot(ctx *context.Context, fileKey string) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
-
- pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version)
- if err != nil {
- if err == packages_model.ErrPackageNotExist {
- apiError(ctx, http.StatusNotFound, err)
- } else {
- apiError(ctx, http.StatusInternalServerError, err)
- }
- return
- }
-
- pfs, _, err := packages_model.SearchFiles(ctx, &packages_model.PackageFileSearchOptions{
- VersionID: pv.ID,
- CompositeKey: fileKey,
- })
- if err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- if len(pfs) == 0 {
- apiError(ctx, http.StatusNotFound, nil)
- return
- }
-
- files := make(map[string]string)
- for _, pf := range pfs {
- pb, err := packages_model.GetBlobByID(ctx, pf.BlobID)
- if err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- files[pf.Name] = pb.HashMD5
- }
-
- jsonResponse(ctx, http.StatusOK, files)
- }
-
- // RecipeDownloadURLs displays the recipe files with their download url
- func RecipeDownloadURLs(ctx *context.Context) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
-
- serveDownloadURLs(
- ctx,
- rref.AsKey(),
- fmt.Sprintf(baseURL(ctx)+"/v1/files/%s/recipe", rref.LinkName()),
- )
- }
-
- // PackageDownloadURLs displays the package files with their download url
- func PackageDownloadURLs(ctx *context.Context) {
- pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
-
- serveDownloadURLs(
- ctx,
- pref.AsKey(),
- fmt.Sprintf(baseURL(ctx)+"/v1/files/%s/package/%s", pref.Recipe.LinkName(), pref.LinkName()),
- )
- }
-
- func serveDownloadURLs(ctx *context.Context, fileKey, downloadURL string) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
-
- pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version)
- if err != nil {
- if err == packages_model.ErrPackageNotExist {
- apiError(ctx, http.StatusNotFound, err)
- } else {
- apiError(ctx, http.StatusInternalServerError, err)
- }
- return
- }
-
- pfs, _, err := packages_model.SearchFiles(ctx, &packages_model.PackageFileSearchOptions{
- VersionID: pv.ID,
- CompositeKey: fileKey,
- })
- if err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
-
- if len(pfs) == 0 {
- apiError(ctx, http.StatusNotFound, nil)
- return
- }
-
- urls := make(map[string]string)
- for _, pf := range pfs {
- urls[pf.Name] = fmt.Sprintf("%s/%s", downloadURL, pf.Name)
- }
-
- jsonResponse(ctx, http.StatusOK, urls)
- }
-
- // RecipeUploadURLs displays the upload urls for the provided recipe files
- func RecipeUploadURLs(ctx *context.Context) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
-
- serveUploadURLs(
- ctx,
- recipeFileList,
- fmt.Sprintf(baseURL(ctx)+"/v1/files/%s/recipe", rref.LinkName()),
- )
- }
-
- // PackageUploadURLs displays the upload urls for the provided package files
- func PackageUploadURLs(ctx *context.Context) {
- pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
-
- serveUploadURLs(
- ctx,
- packageFileList,
- fmt.Sprintf(baseURL(ctx)+"/v1/files/%s/package/%s", pref.Recipe.LinkName(), pref.LinkName()),
- )
- }
-
- func serveUploadURLs(ctx *context.Context, fileFilter container.Set[string], uploadURL string) {
- defer ctx.Req.Body.Close()
-
- var files map[string]int64
- if err := json.NewDecoder(ctx.Req.Body).Decode(&files); err != nil {
- apiError(ctx, http.StatusBadRequest, err)
- return
- }
-
- urls := make(map[string]string)
- for file := range files {
- if fileFilter.Contains(file) {
- urls[file] = fmt.Sprintf("%s/%s", uploadURL, file)
- }
- }
-
- jsonResponse(ctx, http.StatusOK, urls)
- }
-
- // UploadRecipeFile handles the upload of a recipe file
- func UploadRecipeFile(ctx *context.Context) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
-
- uploadFile(ctx, recipeFileList, rref.AsKey())
- }
-
- // UploadPackageFile handles the upload of a package file
- func UploadPackageFile(ctx *context.Context) {
- pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
-
- uploadFile(ctx, packageFileList, pref.AsKey())
- }
-
- func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey string) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
- pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
-
- filename := ctx.Params("filename")
- if !fileFilter.Contains(filename) {
- apiError(ctx, http.StatusBadRequest, nil)
- return
- }
-
- upload, needToClose, err := ctx.UploadStream()
- if err != nil {
- apiError(ctx, http.StatusBadRequest, err)
- return
- }
- if needToClose {
- defer upload.Close()
- }
-
- buf, err := packages_module.CreateHashedBufferFromReader(upload)
- if err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- defer buf.Close()
-
- isConanfileFile := filename == conanfileFile
- isConaninfoFile := filename == conaninfoFile
-
- pci := &packages_service.PackageCreationInfo{
- PackageInfo: packages_service.PackageInfo{
- Owner: ctx.Package.Owner,
- PackageType: packages_model.TypeConan,
- Name: rref.Name,
- Version: rref.Version,
- },
- Creator: ctx.Doer,
- }
- pfci := &packages_service.PackageFileCreationInfo{
- PackageFileInfo: packages_service.PackageFileInfo{
- Filename: strings.ToLower(filename),
- CompositeKey: fileKey,
- },
- Creator: ctx.Doer,
- Data: buf,
- IsLead: isConanfileFile,
- Properties: map[string]string{
- conan_module.PropertyRecipeUser: rref.User,
- conan_module.PropertyRecipeChannel: rref.Channel,
- conan_module.PropertyRecipeRevision: rref.RevisionOrDefault(),
- },
- OverwriteExisting: true,
- }
-
- if pref != nil {
- pfci.Properties[conan_module.PropertyPackageReference] = pref.Reference
- pfci.Properties[conan_module.PropertyPackageRevision] = pref.RevisionOrDefault()
- }
-
- if isConanfileFile || isConaninfoFile {
- if isConanfileFile {
- metadata, err := conan_module.ParseConanfile(buf)
- if err != nil {
- log.Error("Error parsing package metadata: %v", err)
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- pv, err := packages_model.GetVersionByNameAndVersion(ctx, pci.Owner.ID, pci.PackageType, pci.Name, pci.Version)
- if err != nil && err != packages_model.ErrPackageNotExist {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- if pv != nil {
- raw, err := json.Marshal(metadata)
- if err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- pv.MetadataJSON = string(raw)
- if err := packages_model.UpdateVersion(ctx, pv); err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- } else {
- pci.Metadata = metadata
- }
- } else {
- info, err := conan_module.ParseConaninfo(buf)
- if err != nil {
- log.Error("Error parsing conan info: %v", err)
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- raw, err := json.Marshal(info)
- if err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- pfci.Properties[conan_module.PropertyPackageInfo] = string(raw)
- }
-
- if _, err := buf.Seek(0, io.SeekStart); err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- }
-
- _, _, err = packages_service.CreatePackageOrAddFileToExisting(
- ctx,
- pci,
- pfci,
- )
- if err != nil {
- switch err {
- case packages_model.ErrDuplicatePackageFile:
- apiError(ctx, http.StatusConflict, err)
- case packages_service.ErrQuotaTotalCount, packages_service.ErrQuotaTypeSize, packages_service.ErrQuotaTotalSize:
- apiError(ctx, http.StatusForbidden, err)
- default:
- apiError(ctx, http.StatusInternalServerError, err)
- }
- return
- }
-
- ctx.Status(http.StatusCreated)
- }
-
- // DownloadRecipeFile serves the content of the requested recipe file
- func DownloadRecipeFile(ctx *context.Context) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
-
- downloadFile(ctx, recipeFileList, rref.AsKey())
- }
-
- // DownloadPackageFile serves the content of the requested package file
- func DownloadPackageFile(ctx *context.Context) {
- pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
-
- downloadFile(ctx, packageFileList, pref.AsKey())
- }
-
- func downloadFile(ctx *context.Context, fileFilter container.Set[string], fileKey string) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
-
- filename := ctx.Params("filename")
- if !fileFilter.Contains(filename) {
- apiError(ctx, http.StatusBadRequest, nil)
- return
- }
-
- s, u, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
- ctx,
- &packages_service.PackageInfo{
- Owner: ctx.Package.Owner,
- PackageType: packages_model.TypeConan,
- Name: rref.Name,
- Version: rref.Version,
- },
- &packages_service.PackageFileInfo{
- Filename: filename,
- CompositeKey: fileKey,
- },
- )
- if err != nil {
- if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
- apiError(ctx, http.StatusNotFound, err)
- return
- }
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
-
- helper.ServePackageFile(ctx, s, u, pf)
- }
-
- // DeleteRecipeV1 deletes the requested recipe(s)
- func DeleteRecipeV1(ctx *context.Context) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
-
- if err := deleteRecipeOrPackage(ctx, rref, true, nil, false); err != nil {
- if err == packages_model.ErrPackageNotExist || err == conan_model.ErrPackageReferenceNotExist {
- apiError(ctx, http.StatusNotFound, err)
- } else {
- apiError(ctx, http.StatusInternalServerError, err)
- }
- return
- }
- ctx.Status(http.StatusOK)
- }
-
- // DeleteRecipeV2 deletes the requested recipe(s) respecting its revisions
- func DeleteRecipeV2(ctx *context.Context) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
-
- if err := deleteRecipeOrPackage(ctx, rref, rref.Revision == "", nil, false); err != nil {
- if err == packages_model.ErrPackageNotExist || err == conan_model.ErrPackageReferenceNotExist {
- apiError(ctx, http.StatusNotFound, err)
- } else {
- apiError(ctx, http.StatusInternalServerError, err)
- }
- return
- }
- ctx.Status(http.StatusOK)
- }
-
- // DeletePackageV1 deletes the requested package(s)
- func DeletePackageV1(ctx *context.Context) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
-
- type PackageReferences struct {
- References []string `json:"package_ids"`
- }
-
- var ids *PackageReferences
- if err := json.NewDecoder(ctx.Req.Body).Decode(&ids); err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
-
- revisions, err := conan_model.GetRecipeRevisions(ctx, ctx.Package.Owner.ID, rref)
- if err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- for _, revision := range revisions {
- currentRref := rref.WithRevision(revision.Value)
-
- var references []*conan_model.PropertyValue
- if len(ids.References) == 0 {
- if references, err = conan_model.GetPackageReferences(ctx, ctx.Package.Owner.ID, currentRref); err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- } else {
- for _, reference := range ids.References {
- references = append(references, &conan_model.PropertyValue{Value: reference})
- }
- }
-
- for _, reference := range references {
- pref, _ := conan_module.NewPackageReference(currentRref, reference.Value, conan_module.DefaultRevision)
- if err := deleteRecipeOrPackage(ctx, currentRref, true, pref, true); err != nil {
- if err == packages_model.ErrPackageNotExist || err == conan_model.ErrPackageReferenceNotExist {
- apiError(ctx, http.StatusNotFound, err)
- } else {
- apiError(ctx, http.StatusInternalServerError, err)
- }
- return
- }
- }
- }
- ctx.Status(http.StatusOK)
- }
-
- // DeletePackageV2 deletes the requested package(s) respecting its revisions
- func DeletePackageV2(ctx *context.Context) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
- pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
-
- if pref != nil { // has package reference
- if err := deleteRecipeOrPackage(ctx, rref, false, pref, pref.Revision == ""); err != nil {
- if err == packages_model.ErrPackageNotExist || err == conan_model.ErrPackageReferenceNotExist {
- apiError(ctx, http.StatusNotFound, err)
- } else {
- apiError(ctx, http.StatusInternalServerError, err)
- }
- } else {
- ctx.Status(http.StatusOK)
- }
- return
- }
-
- references, err := conan_model.GetPackageReferences(ctx, ctx.Package.Owner.ID, rref)
- if err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- if len(references) == 0 {
- apiError(ctx, http.StatusNotFound, conan_model.ErrPackageReferenceNotExist)
- return
- }
-
- for _, reference := range references {
- pref, _ := conan_module.NewPackageReference(rref, reference.Value, conan_module.DefaultRevision)
-
- if err := deleteRecipeOrPackage(ctx, rref, false, pref, true); err != nil {
- if err == packages_model.ErrPackageNotExist || err == conan_model.ErrPackageReferenceNotExist {
- apiError(ctx, http.StatusNotFound, err)
- } else {
- apiError(ctx, http.StatusInternalServerError, err)
- }
- return
- }
- }
-
- ctx.Status(http.StatusOK)
- }
-
- func deleteRecipeOrPackage(apictx *context.Context, rref *conan_module.RecipeReference, ignoreRecipeRevision bool, pref *conan_module.PackageReference, ignorePackageRevision bool) error {
- var pd *packages_model.PackageDescriptor
- versionDeleted := false
-
- err := db.WithTx(apictx, func(ctx std_ctx.Context) error {
- pv, err := packages_model.GetVersionByNameAndVersion(ctx, apictx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version)
- if err != nil {
- return err
- }
-
- pd, err = packages_model.GetPackageDescriptor(ctx, pv)
- if err != nil {
- return err
- }
-
- filter := map[string]string{
- conan_module.PropertyRecipeUser: rref.User,
- conan_module.PropertyRecipeChannel: rref.Channel,
- }
- if !ignoreRecipeRevision {
- filter[conan_module.PropertyRecipeRevision] = rref.RevisionOrDefault()
- }
- if pref != nil {
- filter[conan_module.PropertyPackageReference] = pref.Reference
- if !ignorePackageRevision {
- filter[conan_module.PropertyPackageRevision] = pref.RevisionOrDefault()
- }
- }
-
- pfs, _, err := packages_model.SearchFiles(ctx, &packages_model.PackageFileSearchOptions{
- VersionID: pv.ID,
- Properties: filter,
- })
- if err != nil {
- return err
- }
- if len(pfs) == 0 {
- return conan_model.ErrPackageReferenceNotExist
- }
-
- for _, pf := range pfs {
- if err := packages_service.DeletePackageFile(ctx, pf); err != nil {
- return err
- }
- }
- has, err := packages_model.HasVersionFileReferences(ctx, pv.ID)
- if err != nil {
- return err
- }
- if !has {
- versionDeleted = true
-
- return packages_service.DeletePackageVersionAndReferences(ctx, pv)
- }
- return nil
- })
- if err != nil {
- return err
- }
-
- if versionDeleted {
- notify_service.PackageDelete(apictx, apictx.Doer, pd)
- }
-
- return nil
- }
-
- // ListRecipeRevisions gets a list of all recipe revisions
- func ListRecipeRevisions(ctx *context.Context) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
-
- revisions, err := conan_model.GetRecipeRevisions(ctx, ctx.Package.Owner.ID, rref)
- if err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
-
- listRevisions(ctx, revisions)
- }
-
- // ListPackageRevisions gets a list of all package revisions
- func ListPackageRevisions(ctx *context.Context) {
- pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
-
- revisions, err := conan_model.GetPackageRevisions(ctx, ctx.Package.Owner.ID, pref)
- if err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
-
- listRevisions(ctx, revisions)
- }
-
- type revisionInfo struct {
- Revision string `json:"revision"`
- Time time.Time `json:"time"`
- }
-
- func listRevisions(ctx *context.Context, revisions []*conan_model.PropertyValue) {
- if len(revisions) == 0 {
- apiError(ctx, http.StatusNotFound, conan_model.ErrRecipeReferenceNotExist)
- return
- }
-
- type RevisionList struct {
- Revisions []*revisionInfo `json:"revisions"`
- }
-
- revs := make([]*revisionInfo, 0, len(revisions))
- for _, rev := range revisions {
- revs = append(revs, &revisionInfo{Revision: rev.Value, Time: rev.CreatedUnix.AsLocalTime()})
- }
-
- jsonResponse(ctx, http.StatusOK, &RevisionList{revs})
- }
-
- // LatestRecipeRevision gets the latest recipe revision
- func LatestRecipeRevision(ctx *context.Context) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
-
- revision, err := conan_model.GetLastRecipeRevision(ctx, ctx.Package.Owner.ID, rref)
- if err != nil {
- if err == conan_model.ErrRecipeReferenceNotExist || err == conan_model.ErrPackageReferenceNotExist {
- apiError(ctx, http.StatusNotFound, err)
- } else {
- apiError(ctx, http.StatusInternalServerError, err)
- }
- return
- }
-
- jsonResponse(ctx, http.StatusOK, &revisionInfo{Revision: revision.Value, Time: revision.CreatedUnix.AsLocalTime()})
- }
-
- // LatestPackageRevision gets the latest package revision
- func LatestPackageRevision(ctx *context.Context) {
- pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
-
- revision, err := conan_model.GetLastPackageRevision(ctx, ctx.Package.Owner.ID, pref)
- if err != nil {
- if err == conan_model.ErrRecipeReferenceNotExist || err == conan_model.ErrPackageReferenceNotExist {
- apiError(ctx, http.StatusNotFound, err)
- } else {
- apiError(ctx, http.StatusInternalServerError, err)
- }
- return
- }
-
- jsonResponse(ctx, http.StatusOK, &revisionInfo{Revision: revision.Value, Time: revision.CreatedUnix.AsLocalTime()})
- }
-
- // ListRecipeRevisionFiles gets a list of all recipe revision files
- func ListRecipeRevisionFiles(ctx *context.Context) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
-
- listRevisionFiles(ctx, rref.AsKey())
- }
-
- // ListPackageRevisionFiles gets a list of all package revision files
- func ListPackageRevisionFiles(ctx *context.Context) {
- pref := ctx.Data[packageReferenceKey].(*conan_module.PackageReference)
-
- listRevisionFiles(ctx, pref.AsKey())
- }
-
- func listRevisionFiles(ctx *context.Context, fileKey string) {
- rref := ctx.Data[recipeReferenceKey].(*conan_module.RecipeReference)
-
- pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeConan, rref.Name, rref.Version)
- if err != nil {
- if err == packages_model.ErrPackageNotExist {
- apiError(ctx, http.StatusNotFound, err)
- } else {
- apiError(ctx, http.StatusInternalServerError, err)
- }
- return
- }
-
- pfs, _, err := packages_model.SearchFiles(ctx, &packages_model.PackageFileSearchOptions{
- VersionID: pv.ID,
- CompositeKey: fileKey,
- })
- if err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- if len(pfs) == 0 {
- apiError(ctx, http.StatusNotFound, nil)
- return
- }
-
- files := make(map[string]any)
- for _, pf := range pfs {
- files[pf.Name] = nil
- }
-
- type FileList struct {
- Files map[string]any `json:"files"`
- }
-
- jsonResponse(ctx, http.StatusOK, &FileList{
- Files: files,
- })
- }
|