code.gitea.io/gitea@v1.22.3/models/packages/package.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 "fmt" 9 "strings" 10 11 "code.gitea.io/gitea/models/db" 12 "code.gitea.io/gitea/modules/util" 13 14 "xorm.io/builder" 15 ) 16 17 func init() { 18 db.RegisterModel(new(Package)) 19 } 20 21 var ( 22 // ErrDuplicatePackage indicates a duplicated package error 23 ErrDuplicatePackage = util.NewAlreadyExistErrorf("package already exists") 24 // ErrPackageNotExist indicates a package not exist error 25 ErrPackageNotExist = util.NewNotExistErrorf("package does not exist") 26 ) 27 28 // Type of a package 29 type Type string 30 31 // List of supported packages 32 const ( 33 TypeAlpine Type = "alpine" 34 TypeCargo Type = "cargo" 35 TypeChef Type = "chef" 36 TypeComposer Type = "composer" 37 TypeConan Type = "conan" 38 TypeConda Type = "conda" 39 TypeContainer Type = "container" 40 TypeCran Type = "cran" 41 TypeDebian Type = "debian" 42 TypeGeneric Type = "generic" 43 TypeGo Type = "go" 44 TypeHelm Type = "helm" 45 TypeMaven Type = "maven" 46 TypeNpm Type = "npm" 47 TypeNuGet Type = "nuget" 48 TypePub Type = "pub" 49 TypePyPI Type = "pypi" 50 TypeRpm Type = "rpm" 51 TypeRubyGems Type = "rubygems" 52 TypeSwift Type = "swift" 53 TypeVagrant Type = "vagrant" 54 ) 55 56 var TypeList = []Type{ 57 TypeAlpine, 58 TypeCargo, 59 TypeChef, 60 TypeComposer, 61 TypeConan, 62 TypeConda, 63 TypeContainer, 64 TypeCran, 65 TypeDebian, 66 TypeGeneric, 67 TypeGo, 68 TypeHelm, 69 TypeMaven, 70 TypeNpm, 71 TypeNuGet, 72 TypePub, 73 TypePyPI, 74 TypeRpm, 75 TypeRubyGems, 76 TypeSwift, 77 TypeVagrant, 78 } 79 80 // Name gets the name of the package type 81 func (pt Type) Name() string { 82 switch pt { 83 case TypeAlpine: 84 return "Alpine" 85 case TypeCargo: 86 return "Cargo" 87 case TypeChef: 88 return "Chef" 89 case TypeComposer: 90 return "Composer" 91 case TypeConan: 92 return "Conan" 93 case TypeConda: 94 return "Conda" 95 case TypeContainer: 96 return "Container" 97 case TypeCran: 98 return "CRAN" 99 case TypeDebian: 100 return "Debian" 101 case TypeGeneric: 102 return "Generic" 103 case TypeGo: 104 return "Go" 105 case TypeHelm: 106 return "Helm" 107 case TypeMaven: 108 return "Maven" 109 case TypeNpm: 110 return "npm" 111 case TypeNuGet: 112 return "NuGet" 113 case TypePub: 114 return "Pub" 115 case TypePyPI: 116 return "PyPI" 117 case TypeRpm: 118 return "RPM" 119 case TypeRubyGems: 120 return "RubyGems" 121 case TypeSwift: 122 return "Swift" 123 case TypeVagrant: 124 return "Vagrant" 125 } 126 panic(fmt.Sprintf("unknown package type: %s", string(pt))) 127 } 128 129 // SVGName gets the name of the package type svg image 130 func (pt Type) SVGName() string { 131 switch pt { 132 case TypeAlpine: 133 return "gitea-alpine" 134 case TypeCargo: 135 return "gitea-cargo" 136 case TypeChef: 137 return "gitea-chef" 138 case TypeComposer: 139 return "gitea-composer" 140 case TypeConan: 141 return "gitea-conan" 142 case TypeConda: 143 return "gitea-conda" 144 case TypeContainer: 145 return "octicon-container" 146 case TypeCran: 147 return "gitea-cran" 148 case TypeDebian: 149 return "gitea-debian" 150 case TypeGeneric: 151 return "octicon-package" 152 case TypeGo: 153 return "gitea-go" 154 case TypeHelm: 155 return "gitea-helm" 156 case TypeMaven: 157 return "gitea-maven" 158 case TypeNpm: 159 return "gitea-npm" 160 case TypeNuGet: 161 return "gitea-nuget" 162 case TypePub: 163 return "gitea-pub" 164 case TypePyPI: 165 return "gitea-python" 166 case TypeRpm: 167 return "gitea-rpm" 168 case TypeRubyGems: 169 return "gitea-rubygems" 170 case TypeSwift: 171 return "gitea-swift" 172 case TypeVagrant: 173 return "gitea-vagrant" 174 } 175 panic(fmt.Sprintf("unknown package type: %s", string(pt))) 176 } 177 178 // Package represents a package 179 type Package struct { 180 ID int64 `xorm:"pk autoincr"` 181 OwnerID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` 182 RepoID int64 `xorm:"INDEX"` 183 Type Type `xorm:"UNIQUE(s) INDEX NOT NULL"` 184 Name string `xorm:"NOT NULL"` 185 LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"` 186 SemverCompatible bool `xorm:"NOT NULL DEFAULT false"` 187 IsInternal bool `xorm:"NOT NULL DEFAULT false"` 188 } 189 190 // TryInsertPackage inserts a package. If a package exists already, ErrDuplicatePackage is returned 191 func TryInsertPackage(ctx context.Context, p *Package) (*Package, error) { 192 e := db.GetEngine(ctx) 193 194 existing := &Package{} 195 196 has, err := e.Where(builder.Eq{ 197 "owner_id": p.OwnerID, 198 "type": p.Type, 199 "lower_name": p.LowerName, 200 }).Get(existing) 201 if err != nil { 202 return nil, err 203 } 204 if has { 205 return existing, ErrDuplicatePackage 206 } 207 if _, err = e.Insert(p); err != nil { 208 return nil, err 209 } 210 return p, nil 211 } 212 213 // DeletePackageByID deletes a package by id 214 func DeletePackageByID(ctx context.Context, packageID int64) error { 215 _, err := db.GetEngine(ctx).ID(packageID).Delete(&Package{}) 216 return err 217 } 218 219 // SetRepositoryLink sets the linked repository 220 func SetRepositoryLink(ctx context.Context, packageID, repoID int64) error { 221 _, err := db.GetEngine(ctx).ID(packageID).Cols("repo_id").Update(&Package{RepoID: repoID}) 222 return err 223 } 224 225 // UnlinkRepositoryFromAllPackages unlinks every package from the repository 226 func UnlinkRepositoryFromAllPackages(ctx context.Context, repoID int64) error { 227 _, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Cols("repo_id").Update(&Package{}) 228 return err 229 } 230 231 // GetPackageByID gets a package by id 232 func GetPackageByID(ctx context.Context, packageID int64) (*Package, error) { 233 p := &Package{} 234 235 has, err := db.GetEngine(ctx).ID(packageID).Get(p) 236 if err != nil { 237 return nil, err 238 } 239 if !has { 240 return nil, ErrPackageNotExist 241 } 242 return p, nil 243 } 244 245 // GetPackageByName gets a package by name 246 func GetPackageByName(ctx context.Context, ownerID int64, packageType Type, name string) (*Package, error) { 247 var cond builder.Cond = builder.Eq{ 248 "package.owner_id": ownerID, 249 "package.type": packageType, 250 "package.lower_name": strings.ToLower(name), 251 "package.is_internal": false, 252 } 253 254 p := &Package{} 255 256 has, err := db.GetEngine(ctx). 257 Where(cond). 258 Get(p) 259 if err != nil { 260 return nil, err 261 } 262 if !has { 263 return nil, ErrPackageNotExist 264 } 265 return p, nil 266 } 267 268 // GetPackagesByType gets all packages of a specific type 269 func GetPackagesByType(ctx context.Context, ownerID int64, packageType Type) ([]*Package, error) { 270 var cond builder.Cond = builder.Eq{ 271 "package.owner_id": ownerID, 272 "package.type": packageType, 273 "package.is_internal": false, 274 } 275 276 ps := make([]*Package, 0, 10) 277 return ps, db.GetEngine(ctx). 278 Where(cond). 279 Find(&ps) 280 } 281 282 // FindUnreferencedPackages gets all packages without associated versions 283 func FindUnreferencedPackages(ctx context.Context) ([]*Package, error) { 284 in := builder. 285 Select("package.id"). 286 From("package"). 287 LeftJoin("package_version", "package_version.package_id = package.id"). 288 Where(builder.Expr("package_version.id IS NULL")) 289 290 ps := make([]*Package, 0, 10) 291 return ps, db.GetEngine(ctx). 292 // double select workaround for MySQL 293 // https://stackoverflow.com/questions/4471277/mysql-delete-from-with-subquery-as-condition 294 Where(builder.In("package.id", builder.Select("id").From(in, "temp"))). 295 Find(&ps) 296 } 297 298 // HasOwnerPackages tests if a user/org has accessible packages 299 func HasOwnerPackages(ctx context.Context, ownerID int64) (bool, error) { 300 return db.GetEngine(ctx). 301 Table("package_version"). 302 Join("INNER", "package", "package.id = package_version.package_id"). 303 Where(builder.Eq{ 304 "package_version.is_internal": false, 305 "package.owner_id": ownerID, 306 }). 307 Exist(&PackageVersion{}) 308 } 309 310 // HasRepositoryPackages tests if a repository has packages 311 func HasRepositoryPackages(ctx context.Context, repositoryID int64) (bool, error) { 312 return db.GetEngine(ctx).Where("repo_id = ?", repositoryID).Exist(&Package{}) 313 }