| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281 |
- // Copyright 2021 The Gitea Authors. All rights reserved.
- // SPDX-License-Identifier: MIT
-
- package packages
-
- import (
- "context"
- "errors"
- "fmt"
- "net/url"
-
- repo_model "code.gitea.io/gitea/models/repo"
- user_model "code.gitea.io/gitea/models/user"
- "code.gitea.io/gitea/modules/cache"
- "code.gitea.io/gitea/modules/json"
- "code.gitea.io/gitea/modules/packages/alpine"
- "code.gitea.io/gitea/modules/packages/arch"
- "code.gitea.io/gitea/modules/packages/cargo"
- "code.gitea.io/gitea/modules/packages/chef"
- "code.gitea.io/gitea/modules/packages/composer"
- "code.gitea.io/gitea/modules/packages/conan"
- "code.gitea.io/gitea/modules/packages/conda"
- "code.gitea.io/gitea/modules/packages/container"
- "code.gitea.io/gitea/modules/packages/cran"
- "code.gitea.io/gitea/modules/packages/debian"
- "code.gitea.io/gitea/modules/packages/helm"
- "code.gitea.io/gitea/modules/packages/maven"
- "code.gitea.io/gitea/modules/packages/npm"
- "code.gitea.io/gitea/modules/packages/nuget"
- "code.gitea.io/gitea/modules/packages/pub"
- "code.gitea.io/gitea/modules/packages/pypi"
- "code.gitea.io/gitea/modules/packages/rpm"
- "code.gitea.io/gitea/modules/packages/rubygems"
- "code.gitea.io/gitea/modules/packages/swift"
- "code.gitea.io/gitea/modules/packages/vagrant"
- "code.gitea.io/gitea/modules/util"
-
- "github.com/hashicorp/go-version"
- )
-
- // PackagePropertyList is a list of package properties
- type PackagePropertyList []*PackageProperty
-
- // GetByName gets the first property value with the specific name
- func (l PackagePropertyList) GetByName(name string) string {
- for _, pp := range l {
- if pp.Name == name {
- return pp.Value
- }
- }
- return ""
- }
-
- // PackageDescriptor describes a package
- type PackageDescriptor struct {
- Package *Package
- Owner *user_model.User
- Repository *repo_model.Repository
- Version *PackageVersion
- SemVer *version.Version
- Creator *user_model.User
- PackageProperties PackagePropertyList
- VersionProperties PackagePropertyList
- Metadata any
- Files []*PackageFileDescriptor
- }
-
- // PackageFileDescriptor describes a package file
- type PackageFileDescriptor struct {
- File *PackageFile
- Blob *PackageBlob
- Properties PackagePropertyList
- }
-
- // PackageWebLink returns the relative package web link
- func (pd *PackageDescriptor) PackageWebLink() string {
- return fmt.Sprintf("%s/-/packages/%s/%s", pd.Owner.HomeLink(), string(pd.Package.Type), url.PathEscape(pd.Package.LowerName))
- }
-
- // VersionWebLink returns the relative package version web link
- func (pd *PackageDescriptor) VersionWebLink() string {
- return fmt.Sprintf("%s/%s", pd.PackageWebLink(), url.PathEscape(pd.Version.LowerVersion))
- }
-
- // PackageHTMLURL returns the absolute package HTML URL
- func (pd *PackageDescriptor) PackageHTMLURL(ctx context.Context) string {
- return fmt.Sprintf("%s/-/packages/%s/%s", pd.Owner.HTMLURL(ctx), string(pd.Package.Type), url.PathEscape(pd.Package.LowerName))
- }
-
- // VersionHTMLURL returns the absolute package version HTML URL
- func (pd *PackageDescriptor) VersionHTMLURL(ctx context.Context) string {
- return fmt.Sprintf("%s/%s", pd.PackageHTMLURL(ctx), url.PathEscape(pd.Version.LowerVersion))
- }
-
- // CalculateBlobSize returns the total blobs size in bytes
- func (pd *PackageDescriptor) CalculateBlobSize() int64 {
- size := int64(0)
- for _, f := range pd.Files {
- size += f.Blob.Size
- }
- return size
- }
-
- // GetPackageDescriptor gets the package description for a version
- func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDescriptor, error) {
- return GetPackageDescriptorWithCache(ctx, pv, cache.NewEphemeralCache())
- }
-
- func GetPackageDescriptorWithCache(ctx context.Context, pv *PackageVersion, c *cache.EphemeralCache) (*PackageDescriptor, error) {
- p, err := cache.GetWithEphemeralCache(ctx, c, "package", pv.PackageID, GetPackageByID)
- if err != nil {
- return nil, err
- }
- o, err := cache.GetWithEphemeralCache(ctx, c, "user", p.OwnerID, user_model.GetUserByID)
- if err != nil {
- return nil, err
- }
- var repository *repo_model.Repository
- if p.RepoID > 0 {
- repository, err = cache.GetWithEphemeralCache(ctx, c, "repo", p.RepoID, repo_model.GetRepositoryByID)
- if err != nil && !repo_model.IsErrRepoNotExist(err) {
- return nil, err
- }
- }
- creator, err := cache.GetWithEphemeralCache(ctx, c, "user", pv.CreatorID, user_model.GetUserByID)
- if err != nil {
- if errors.Is(err, util.ErrNotExist) {
- creator = user_model.NewGhostUser()
- } else {
- return nil, err
- }
- }
- var semVer *version.Version
- if p.SemverCompatible {
- semVer, err = version.NewVersion(pv.Version)
- if err != nil {
- return nil, err
- }
- }
- pps, err := GetProperties(ctx, PropertyTypePackage, p.ID)
- if err != nil {
- return nil, err
- }
- pvps, err := GetProperties(ctx, PropertyTypeVersion, pv.ID)
- if err != nil {
- return nil, err
- }
- pfs, err := GetFilesByVersionID(ctx, pv.ID)
- if err != nil {
- return nil, err
- }
-
- pfds := make([]*PackageFileDescriptor, 0, len(pfs))
- for _, pf := range pfs {
- pfd, err := getPackageFileDescriptor(ctx, pf, c)
- if err != nil {
- return nil, err
- }
- pfds = append(pfds, pfd)
- }
-
- var metadata any
- switch p.Type {
- case TypeAlpine:
- metadata = &alpine.VersionMetadata{}
- case TypeArch:
- metadata = &arch.VersionMetadata{}
- case TypeCargo:
- metadata = &cargo.Metadata{}
- case TypeChef:
- metadata = &chef.Metadata{}
- case TypeComposer:
- metadata = &composer.Metadata{}
- case TypeConan:
- metadata = &conan.Metadata{}
- case TypeConda:
- metadata = &conda.VersionMetadata{}
- case TypeContainer:
- metadata = &container.Metadata{}
- case TypeCran:
- metadata = &cran.Metadata{}
- case TypeDebian:
- metadata = &debian.Metadata{}
- case TypeGeneric:
- // generic packages have no metadata
- case TypeGo:
- // go packages have no metadata
- case TypeHelm:
- metadata = &helm.Metadata{}
- case TypeNuGet:
- metadata = &nuget.Metadata{}
- case TypeNpm:
- metadata = &npm.Metadata{}
- case TypeMaven:
- metadata = &maven.Metadata{}
- case TypePub:
- metadata = &pub.Metadata{}
- case TypePyPI:
- metadata = &pypi.Metadata{}
- case TypeRpm:
- metadata = &rpm.VersionMetadata{}
- case TypeRubyGems:
- metadata = &rubygems.Metadata{}
- case TypeSwift:
- metadata = &swift.Metadata{}
- case TypeVagrant:
- metadata = &vagrant.Metadata{}
- default:
- panic("unknown package type: " + string(p.Type))
- }
- if metadata != nil {
- if err := json.Unmarshal([]byte(pv.MetadataJSON), &metadata); err != nil {
- return nil, err
- }
- }
-
- return &PackageDescriptor{
- Package: p,
- Owner: o,
- Repository: repository,
- Version: pv,
- SemVer: semVer,
- Creator: creator,
- PackageProperties: PackagePropertyList(pps),
- VersionProperties: PackagePropertyList(pvps),
- Metadata: metadata,
- Files: pfds,
- }, nil
- }
-
- // GetPackageFileDescriptor gets a package file descriptor for a package file
- func GetPackageFileDescriptor(ctx context.Context, pf *PackageFile) (*PackageFileDescriptor, error) {
- return getPackageFileDescriptor(ctx, pf, cache.NewEphemeralCache())
- }
-
- func getPackageFileDescriptor(ctx context.Context, pf *PackageFile, c *cache.EphemeralCache) (*PackageFileDescriptor, error) {
- pb, err := cache.GetWithEphemeralCache(ctx, c, "package_file_blob", pf.BlobID, GetBlobByID)
- if err != nil {
- return nil, err
- }
- pfps, err := GetProperties(ctx, PropertyTypeFile, pf.ID)
- if err != nil {
- return nil, err
- }
- return &PackageFileDescriptor{
- pf,
- pb,
- PackagePropertyList(pfps),
- }, nil
- }
-
- // GetPackageFileDescriptors gets the package file descriptors for the package files
- func GetPackageFileDescriptors(ctx context.Context, pfs []*PackageFile) ([]*PackageFileDescriptor, error) {
- pfds := make([]*PackageFileDescriptor, 0, len(pfs))
- for _, pf := range pfs {
- pfd, err := GetPackageFileDescriptor(ctx, pf)
- if err != nil {
- return nil, err
- }
- pfds = append(pfds, pfd)
- }
- return pfds, nil
- }
-
- // GetPackageDescriptors gets the package descriptions for the versions
- func GetPackageDescriptors(ctx context.Context, pvs []*PackageVersion) ([]*PackageDescriptor, error) {
- return getPackageDescriptors(ctx, pvs, cache.NewEphemeralCache())
- }
-
- func getPackageDescriptors(ctx context.Context, pvs []*PackageVersion, c *cache.EphemeralCache) ([]*PackageDescriptor, error) {
- pds := make([]*PackageDescriptor, 0, len(pvs))
- for _, pv := range pvs {
- pd, err := GetPackageDescriptorWithCache(ctx, pv, c)
- if err != nil {
- return nil, err
- }
- pds = append(pds, pd)
- }
- return pds, nil
- }
|