code.gitea.io/gitea@v1.22.3/models/packages/descriptor.go (about)

     1  // Copyright 2021 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package packages
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"net/url"
    11  
    12  	repo_model "code.gitea.io/gitea/models/repo"
    13  	user_model "code.gitea.io/gitea/models/user"
    14  	"code.gitea.io/gitea/modules/json"
    15  	"code.gitea.io/gitea/modules/packages/alpine"
    16  	"code.gitea.io/gitea/modules/packages/cargo"
    17  	"code.gitea.io/gitea/modules/packages/chef"
    18  	"code.gitea.io/gitea/modules/packages/composer"
    19  	"code.gitea.io/gitea/modules/packages/conan"
    20  	"code.gitea.io/gitea/modules/packages/conda"
    21  	"code.gitea.io/gitea/modules/packages/container"
    22  	"code.gitea.io/gitea/modules/packages/cran"
    23  	"code.gitea.io/gitea/modules/packages/debian"
    24  	"code.gitea.io/gitea/modules/packages/helm"
    25  	"code.gitea.io/gitea/modules/packages/maven"
    26  	"code.gitea.io/gitea/modules/packages/npm"
    27  	"code.gitea.io/gitea/modules/packages/nuget"
    28  	"code.gitea.io/gitea/modules/packages/pub"
    29  	"code.gitea.io/gitea/modules/packages/pypi"
    30  	"code.gitea.io/gitea/modules/packages/rpm"
    31  	"code.gitea.io/gitea/modules/packages/rubygems"
    32  	"code.gitea.io/gitea/modules/packages/swift"
    33  	"code.gitea.io/gitea/modules/packages/vagrant"
    34  	"code.gitea.io/gitea/modules/util"
    35  
    36  	"github.com/hashicorp/go-version"
    37  )
    38  
    39  // PackagePropertyList is a list of package properties
    40  type PackagePropertyList []*PackageProperty
    41  
    42  // GetByName gets the first property value with the specific name
    43  func (l PackagePropertyList) GetByName(name string) string {
    44  	for _, pp := range l {
    45  		if pp.Name == name {
    46  			return pp.Value
    47  		}
    48  	}
    49  	return ""
    50  }
    51  
    52  // PackageDescriptor describes a package
    53  type PackageDescriptor struct {
    54  	Package           *Package
    55  	Owner             *user_model.User
    56  	Repository        *repo_model.Repository
    57  	Version           *PackageVersion
    58  	SemVer            *version.Version
    59  	Creator           *user_model.User
    60  	PackageProperties PackagePropertyList
    61  	VersionProperties PackagePropertyList
    62  	Metadata          any
    63  	Files             []*PackageFileDescriptor
    64  }
    65  
    66  // PackageFileDescriptor describes a package file
    67  type PackageFileDescriptor struct {
    68  	File       *PackageFile
    69  	Blob       *PackageBlob
    70  	Properties PackagePropertyList
    71  }
    72  
    73  // PackageWebLink returns the relative package web link
    74  func (pd *PackageDescriptor) PackageWebLink() string {
    75  	return fmt.Sprintf("%s/-/packages/%s/%s", pd.Owner.HomeLink(), string(pd.Package.Type), url.PathEscape(pd.Package.LowerName))
    76  }
    77  
    78  // VersionWebLink returns the relative package version web link
    79  func (pd *PackageDescriptor) VersionWebLink() string {
    80  	return fmt.Sprintf("%s/%s", pd.PackageWebLink(), url.PathEscape(pd.Version.LowerVersion))
    81  }
    82  
    83  // PackageHTMLURL returns the absolute package HTML URL
    84  func (pd *PackageDescriptor) PackageHTMLURL() string {
    85  	return fmt.Sprintf("%s/-/packages/%s/%s", pd.Owner.HTMLURL(), string(pd.Package.Type), url.PathEscape(pd.Package.LowerName))
    86  }
    87  
    88  // VersionHTMLURL returns the absolute package version HTML URL
    89  func (pd *PackageDescriptor) VersionHTMLURL() string {
    90  	return fmt.Sprintf("%s/%s", pd.PackageHTMLURL(), url.PathEscape(pd.Version.LowerVersion))
    91  }
    92  
    93  // CalculateBlobSize returns the total blobs size in bytes
    94  func (pd *PackageDescriptor) CalculateBlobSize() int64 {
    95  	size := int64(0)
    96  	for _, f := range pd.Files {
    97  		size += f.Blob.Size
    98  	}
    99  	return size
   100  }
   101  
   102  // GetPackageDescriptor gets the package description for a version
   103  func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDescriptor, error) {
   104  	p, err := GetPackageByID(ctx, pv.PackageID)
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	o, err := user_model.GetUserByID(ctx, p.OwnerID)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	repository, err := repo_model.GetRepositoryByID(ctx, p.RepoID)
   113  	if err != nil && !repo_model.IsErrRepoNotExist(err) {
   114  		return nil, err
   115  	}
   116  	creator, err := user_model.GetUserByID(ctx, pv.CreatorID)
   117  	if err != nil {
   118  		if errors.Is(err, util.ErrNotExist) {
   119  			creator = user_model.NewGhostUser()
   120  		} else {
   121  			return nil, err
   122  		}
   123  	}
   124  	var semVer *version.Version
   125  	if p.SemverCompatible {
   126  		semVer, err = version.NewVersion(pv.Version)
   127  		if err != nil {
   128  			return nil, err
   129  		}
   130  	}
   131  	pps, err := GetProperties(ctx, PropertyTypePackage, p.ID)
   132  	if err != nil {
   133  		return nil, err
   134  	}
   135  	pvps, err := GetProperties(ctx, PropertyTypeVersion, pv.ID)
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  	pfs, err := GetFilesByVersionID(ctx, pv.ID)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  
   144  	pfds, err := GetPackageFileDescriptors(ctx, pfs)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  
   149  	var metadata any
   150  	switch p.Type {
   151  	case TypeAlpine:
   152  		metadata = &alpine.VersionMetadata{}
   153  	case TypeCargo:
   154  		metadata = &cargo.Metadata{}
   155  	case TypeChef:
   156  		metadata = &chef.Metadata{}
   157  	case TypeComposer:
   158  		metadata = &composer.Metadata{}
   159  	case TypeConan:
   160  		metadata = &conan.Metadata{}
   161  	case TypeConda:
   162  		metadata = &conda.VersionMetadata{}
   163  	case TypeContainer:
   164  		metadata = &container.Metadata{}
   165  	case TypeCran:
   166  		metadata = &cran.Metadata{}
   167  	case TypeDebian:
   168  		metadata = &debian.Metadata{}
   169  	case TypeGeneric:
   170  		// generic packages have no metadata
   171  	case TypeGo:
   172  		// go packages have no metadata
   173  	case TypeHelm:
   174  		metadata = &helm.Metadata{}
   175  	case TypeNuGet:
   176  		metadata = &nuget.Metadata{}
   177  	case TypeNpm:
   178  		metadata = &npm.Metadata{}
   179  	case TypeMaven:
   180  		metadata = &maven.Metadata{}
   181  	case TypePub:
   182  		metadata = &pub.Metadata{}
   183  	case TypePyPI:
   184  		metadata = &pypi.Metadata{}
   185  	case TypeRpm:
   186  		metadata = &rpm.VersionMetadata{}
   187  	case TypeRubyGems:
   188  		metadata = &rubygems.Metadata{}
   189  	case TypeSwift:
   190  		metadata = &swift.Metadata{}
   191  	case TypeVagrant:
   192  		metadata = &vagrant.Metadata{}
   193  	default:
   194  		panic(fmt.Sprintf("unknown package type: %s", string(p.Type)))
   195  	}
   196  	if metadata != nil {
   197  		if err := json.Unmarshal([]byte(pv.MetadataJSON), &metadata); err != nil {
   198  			return nil, err
   199  		}
   200  	}
   201  
   202  	return &PackageDescriptor{
   203  		Package:           p,
   204  		Owner:             o,
   205  		Repository:        repository,
   206  		Version:           pv,
   207  		SemVer:            semVer,
   208  		Creator:           creator,
   209  		PackageProperties: PackagePropertyList(pps),
   210  		VersionProperties: PackagePropertyList(pvps),
   211  		Metadata:          metadata,
   212  		Files:             pfds,
   213  	}, nil
   214  }
   215  
   216  // GetPackageFileDescriptor gets a package file descriptor for a package file
   217  func GetPackageFileDescriptor(ctx context.Context, pf *PackageFile) (*PackageFileDescriptor, error) {
   218  	pb, err := GetBlobByID(ctx, pf.BlobID)
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	pfps, err := GetProperties(ctx, PropertyTypeFile, pf.ID)
   223  	if err != nil {
   224  		return nil, err
   225  	}
   226  	return &PackageFileDescriptor{
   227  		pf,
   228  		pb,
   229  		PackagePropertyList(pfps),
   230  	}, nil
   231  }
   232  
   233  // GetPackageFileDescriptors gets the package file descriptors for the package files
   234  func GetPackageFileDescriptors(ctx context.Context, pfs []*PackageFile) ([]*PackageFileDescriptor, error) {
   235  	pfds := make([]*PackageFileDescriptor, 0, len(pfs))
   236  	for _, pf := range pfs {
   237  		pfd, err := GetPackageFileDescriptor(ctx, pf)
   238  		if err != nil {
   239  			return nil, err
   240  		}
   241  		pfds = append(pfds, pfd)
   242  	}
   243  	return pfds, nil
   244  }
   245  
   246  // GetPackageDescriptors gets the package descriptions for the versions
   247  func GetPackageDescriptors(ctx context.Context, pvs []*PackageVersion) ([]*PackageDescriptor, error) {
   248  	pds := make([]*PackageDescriptor, 0, len(pvs))
   249  	for _, pv := range pvs {
   250  		pd, err := GetPackageDescriptor(ctx, pv)
   251  		if err != nil {
   252  			return nil, err
   253  		}
   254  		pds = append(pds, pd)
   255  	}
   256  	return pds, nil
   257  }