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 }