123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- // Copyright 2023 The Gitea Authors. All rights reserved.
- // SPDX-License-Identifier: MIT
-
- package cran
-
- import (
- "compress/gzip"
- "errors"
- "fmt"
- "io"
- "net/http"
- "strings"
-
- packages_model "code.gitea.io/gitea/models/packages"
- cran_model "code.gitea.io/gitea/models/packages/cran"
- "code.gitea.io/gitea/modules/context"
- packages_module "code.gitea.io/gitea/modules/packages"
- cran_module "code.gitea.io/gitea/modules/packages/cran"
- "code.gitea.io/gitea/modules/util"
- "code.gitea.io/gitea/routers/api/packages/helper"
- packages_service "code.gitea.io/gitea/services/packages"
- )
-
- func apiError(ctx *context.Context, status int, obj any) {
- helper.LogAndProcessError(ctx, status, obj, func(message string) {
- ctx.PlainText(status, message)
- })
- }
-
- func EnumerateSourcePackages(ctx *context.Context) {
- enumeratePackages(ctx, ctx.Params("format"), &cran_model.SearchOptions{
- OwnerID: ctx.Package.Owner.ID,
- FileType: cran_module.TypeSource,
- })
- }
-
- func EnumerateBinaryPackages(ctx *context.Context) {
- enumeratePackages(ctx, ctx.Params("format"), &cran_model.SearchOptions{
- OwnerID: ctx.Package.Owner.ID,
- FileType: cran_module.TypeBinary,
- Platform: ctx.Params("platform"),
- RVersion: ctx.Params("rversion"),
- })
- }
-
- func enumeratePackages(ctx *context.Context, format string, opts *cran_model.SearchOptions) {
- if format != "" && format != ".gz" {
- apiError(ctx, http.StatusNotFound, nil)
- return
- }
-
- pvs, err := cran_model.SearchLatestVersions(ctx, opts)
- if err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- if len(pvs) == 0 {
- apiError(ctx, http.StatusNotFound, nil)
- return
- }
-
- pds, err := packages_model.GetPackageDescriptors(ctx, pvs)
- if err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
-
- var w io.Writer = ctx.Resp
-
- if format == ".gz" {
- ctx.Resp.Header().Set("Content-Type", "application/x-gzip")
-
- gzw := gzip.NewWriter(w)
- defer gzw.Close()
-
- w = gzw
- } else {
- ctx.Resp.Header().Set("Content-Type", "text/plain;charset=utf-8")
- }
- ctx.Resp.WriteHeader(http.StatusOK)
-
- for i, pd := range pds {
- if i > 0 {
- fmt.Fprintln(w)
- }
-
- var pfd *packages_model.PackageFileDescriptor
- for _, d := range pd.Files {
- if d.Properties.GetByName(cran_module.PropertyType) == opts.FileType &&
- d.Properties.GetByName(cran_module.PropertyPlatform) == opts.Platform &&
- d.Properties.GetByName(cran_module.PropertyRVersion) == opts.RVersion {
- pfd = d
- break
- }
- }
-
- metadata := pd.Metadata.(*cran_module.Metadata)
-
- fmt.Fprintln(w, "Package:", pd.Package.Name)
- fmt.Fprintln(w, "Version:", pd.Version.Version)
- if metadata.License != "" {
- fmt.Fprintln(w, "License:", metadata.License)
- }
- if len(metadata.Depends) > 0 {
- fmt.Fprintln(w, "Depends:", strings.Join(metadata.Depends, ", "))
- }
- if len(metadata.Imports) > 0 {
- fmt.Fprintln(w, "Imports:", strings.Join(metadata.Imports, ", "))
- }
- if len(metadata.LinkingTo) > 0 {
- fmt.Fprintln(w, "LinkingTo:", strings.Join(metadata.LinkingTo, ", "))
- }
- if len(metadata.Suggests) > 0 {
- fmt.Fprintln(w, "Suggests:", strings.Join(metadata.Suggests, ", "))
- }
- needsCompilation := "no"
- if metadata.NeedsCompilation {
- needsCompilation = "yes"
- }
- fmt.Fprintln(w, "NeedsCompilation:", needsCompilation)
- fmt.Fprintln(w, "MD5sum:", pfd.Blob.HashMD5)
- }
- }
-
- func UploadSourcePackageFile(ctx *context.Context) {
- uploadPackageFile(
- ctx,
- packages_model.EmptyFileKey,
- map[string]string{
- cran_module.PropertyType: cran_module.TypeSource,
- },
- )
- }
-
- func UploadBinaryPackageFile(ctx *context.Context) {
- platform, rversion := ctx.FormTrim("platform"), ctx.FormTrim("rversion")
- if platform == "" || rversion == "" {
- apiError(ctx, http.StatusBadRequest, nil)
- return
- }
-
- uploadPackageFile(
- ctx,
- platform+"|"+rversion,
- map[string]string{
- cran_module.PropertyType: cran_module.TypeBinary,
- cran_module.PropertyPlatform: platform,
- cran_module.PropertyRVersion: rversion,
- },
- )
- }
-
- func uploadPackageFile(ctx *context.Context, compositeKey string, properties map[string]string) {
- upload, close, err := ctx.UploadStream()
- if err != nil {
- apiError(ctx, http.StatusBadRequest, err)
- return
- }
- if close {
- defer upload.Close()
- }
-
- buf, err := packages_module.CreateHashedBufferFromReader(upload)
- if err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
- defer buf.Close()
-
- pck, err := cran_module.ParsePackage(buf, buf.Size())
- if err != nil {
- if errors.Is(err, util.ErrInvalidArgument) {
- apiError(ctx, http.StatusBadRequest, err)
- } else {
- apiError(ctx, http.StatusInternalServerError, err)
- }
- return
- }
-
- if _, err := buf.Seek(0, io.SeekStart); err != nil {
- apiError(ctx, http.StatusInternalServerError, err)
- return
- }
-
- _, _, err = packages_service.CreatePackageOrAddFileToExisting(
- ctx,
- &packages_service.PackageCreationInfo{
- PackageInfo: packages_service.PackageInfo{
- Owner: ctx.Package.Owner,
- PackageType: packages_model.TypeCran,
- Name: pck.Name,
- Version: pck.Version,
- },
- SemverCompatible: false,
- Creator: ctx.Doer,
- Metadata: pck.Metadata,
- },
- &packages_service.PackageFileCreationInfo{
- PackageFileInfo: packages_service.PackageFileInfo{
- Filename: fmt.Sprintf("%s_%s%s", pck.Name, pck.Version, pck.FileExtension),
- CompositeKey: compositeKey,
- },
- Creator: ctx.Doer,
- Data: buf,
- IsLead: true,
- Properties: properties,
- },
- )
- 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)
- }
-
- func DownloadSourcePackageFile(ctx *context.Context) {
- downloadPackageFile(ctx, &cran_model.SearchOptions{
- OwnerID: ctx.Package.Owner.ID,
- FileType: cran_module.TypeSource,
- Filename: ctx.Params("filename"),
- })
- }
-
- func DownloadBinaryPackageFile(ctx *context.Context) {
- downloadPackageFile(ctx, &cran_model.SearchOptions{
- OwnerID: ctx.Package.Owner.ID,
- FileType: cran_module.TypeBinary,
- Platform: ctx.Params("platform"),
- RVersion: ctx.Params("rversion"),
- Filename: ctx.Params("filename"),
- })
- }
-
- func downloadPackageFile(ctx *context.Context, opts *cran_model.SearchOptions) {
- pf, err := cran_model.SearchFile(ctx, opts)
- if err != nil {
- if errors.Is(err, util.ErrNotExist) {
- apiError(ctx, http.StatusNotFound, err)
- } else {
- apiError(ctx, http.StatusInternalServerError, err)
- }
- return
- }
-
- s, u, _, err := packages_service.GetPackageFileStream(ctx, pf)
- if err != nil {
- if errors.Is(err, util.ErrNotExist) {
- apiError(ctx, http.StatusNotFound, err)
- } else {
- apiError(ctx, http.StatusInternalServerError, err)
- }
- return
- }
-
- helper.ServePackageFile(ctx, s, u, pf)
- }
|