You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

package.go 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package packages
  4. import (
  5. "context"
  6. "fmt"
  7. "strings"
  8. "code.gitea.io/gitea/models/db"
  9. "code.gitea.io/gitea/modules/util"
  10. "xorm.io/builder"
  11. )
  12. func init() {
  13. db.RegisterModel(new(Package))
  14. }
  15. var (
  16. // ErrDuplicatePackage indicates a duplicated package error
  17. ErrDuplicatePackage = util.NewAlreadyExistErrorf("package already exists")
  18. // ErrPackageNotExist indicates a package not exist error
  19. ErrPackageNotExist = util.NewNotExistErrorf("package does not exist")
  20. )
  21. // Type of a package
  22. type Type string
  23. // List of supported packages
  24. const (
  25. TypeComposer Type = "composer"
  26. TypeConan Type = "conan"
  27. TypeContainer Type = "container"
  28. TypeGeneric Type = "generic"
  29. TypeHelm Type = "helm"
  30. TypeMaven Type = "maven"
  31. TypeNpm Type = "npm"
  32. TypeNuGet Type = "nuget"
  33. TypePub Type = "pub"
  34. TypePyPI Type = "pypi"
  35. TypeRubyGems Type = "rubygems"
  36. TypeVagrant Type = "vagrant"
  37. )
  38. var TypeList = []Type{
  39. TypeComposer,
  40. TypeConan,
  41. TypeContainer,
  42. TypeGeneric,
  43. TypeHelm,
  44. TypeMaven,
  45. TypeNpm,
  46. TypeNuGet,
  47. TypePub,
  48. TypePyPI,
  49. TypeRubyGems,
  50. TypeVagrant,
  51. }
  52. // Name gets the name of the package type
  53. func (pt Type) Name() string {
  54. switch pt {
  55. case TypeComposer:
  56. return "Composer"
  57. case TypeConan:
  58. return "Conan"
  59. case TypeContainer:
  60. return "Container"
  61. case TypeGeneric:
  62. return "Generic"
  63. case TypeHelm:
  64. return "Helm"
  65. case TypeMaven:
  66. return "Maven"
  67. case TypeNpm:
  68. return "npm"
  69. case TypeNuGet:
  70. return "NuGet"
  71. case TypePub:
  72. return "Pub"
  73. case TypePyPI:
  74. return "PyPI"
  75. case TypeRubyGems:
  76. return "RubyGems"
  77. case TypeVagrant:
  78. return "Vagrant"
  79. }
  80. panic(fmt.Sprintf("unknown package type: %s", string(pt)))
  81. }
  82. // SVGName gets the name of the package type svg image
  83. func (pt Type) SVGName() string {
  84. switch pt {
  85. case TypeComposer:
  86. return "gitea-composer"
  87. case TypeConan:
  88. return "gitea-conan"
  89. case TypeContainer:
  90. return "octicon-container"
  91. case TypeGeneric:
  92. return "octicon-package"
  93. case TypeHelm:
  94. return "gitea-helm"
  95. case TypeMaven:
  96. return "gitea-maven"
  97. case TypeNpm:
  98. return "gitea-npm"
  99. case TypeNuGet:
  100. return "gitea-nuget"
  101. case TypePub:
  102. return "gitea-pub"
  103. case TypePyPI:
  104. return "gitea-python"
  105. case TypeRubyGems:
  106. return "gitea-rubygems"
  107. case TypeVagrant:
  108. return "gitea-vagrant"
  109. }
  110. panic(fmt.Sprintf("unknown package type: %s", string(pt)))
  111. }
  112. // Package represents a package
  113. type Package struct {
  114. ID int64 `xorm:"pk autoincr"`
  115. OwnerID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"`
  116. RepoID int64 `xorm:"INDEX"`
  117. Type Type `xorm:"UNIQUE(s) INDEX NOT NULL"`
  118. Name string `xorm:"NOT NULL"`
  119. LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`
  120. SemverCompatible bool `xorm:"NOT NULL DEFAULT false"`
  121. }
  122. // TryInsertPackage inserts a package. If a package exists already, ErrDuplicatePackage is returned
  123. func TryInsertPackage(ctx context.Context, p *Package) (*Package, error) {
  124. e := db.GetEngine(ctx)
  125. key := &Package{
  126. OwnerID: p.OwnerID,
  127. Type: p.Type,
  128. LowerName: p.LowerName,
  129. }
  130. has, err := e.Get(key)
  131. if err != nil {
  132. return nil, err
  133. }
  134. if has {
  135. return key, ErrDuplicatePackage
  136. }
  137. if _, err = e.Insert(p); err != nil {
  138. return nil, err
  139. }
  140. return p, nil
  141. }
  142. // DeletePackageByID deletes a package by id
  143. func DeletePackageByID(ctx context.Context, packageID int64) error {
  144. _, err := db.GetEngine(ctx).ID(packageID).Delete(&Package{})
  145. return err
  146. }
  147. // SetRepositoryLink sets the linked repository
  148. func SetRepositoryLink(ctx context.Context, packageID, repoID int64) error {
  149. _, err := db.GetEngine(ctx).ID(packageID).Cols("repo_id").Update(&Package{RepoID: repoID})
  150. return err
  151. }
  152. // UnlinkRepositoryFromAllPackages unlinks every package from the repository
  153. func UnlinkRepositoryFromAllPackages(ctx context.Context, repoID int64) error {
  154. _, err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Cols("repo_id").Update(&Package{})
  155. return err
  156. }
  157. // GetPackageByID gets a package by id
  158. func GetPackageByID(ctx context.Context, packageID int64) (*Package, error) {
  159. p := &Package{}
  160. has, err := db.GetEngine(ctx).ID(packageID).Get(p)
  161. if err != nil {
  162. return nil, err
  163. }
  164. if !has {
  165. return nil, ErrPackageNotExist
  166. }
  167. return p, nil
  168. }
  169. // GetPackageByName gets a package by name
  170. func GetPackageByName(ctx context.Context, ownerID int64, packageType Type, name string) (*Package, error) {
  171. var cond builder.Cond = builder.Eq{
  172. "package.owner_id": ownerID,
  173. "package.type": packageType,
  174. "package.lower_name": strings.ToLower(name),
  175. }
  176. p := &Package{}
  177. has, err := db.GetEngine(ctx).
  178. Where(cond).
  179. Get(p)
  180. if err != nil {
  181. return nil, err
  182. }
  183. if !has {
  184. return nil, ErrPackageNotExist
  185. }
  186. return p, nil
  187. }
  188. // GetPackagesByType gets all packages of a specific type
  189. func GetPackagesByType(ctx context.Context, ownerID int64, packageType Type) ([]*Package, error) {
  190. var cond builder.Cond = builder.Eq{
  191. "package.owner_id": ownerID,
  192. "package.type": packageType,
  193. }
  194. ps := make([]*Package, 0, 10)
  195. return ps, db.GetEngine(ctx).
  196. Where(cond).
  197. Find(&ps)
  198. }
  199. // FindUnreferencedPackages gets all packages without associated versions
  200. func FindUnreferencedPackages(ctx context.Context) ([]*Package, error) {
  201. in := builder.
  202. Select("package.id").
  203. From("package").
  204. LeftJoin("package_version", "package_version.package_id = package.id").
  205. Where(builder.Expr("package_version.id IS NULL"))
  206. ps := make([]*Package, 0, 10)
  207. return ps, db.GetEngine(ctx).
  208. // double select workaround for MySQL
  209. // https://stackoverflow.com/questions/4471277/mysql-delete-from-with-subquery-as-condition
  210. Where(builder.In("package.id", builder.Select("id").From(in, "temp"))).
  211. Find(&ps)
  212. }
  213. // HasOwnerPackages tests if a user/org has accessible packages
  214. func HasOwnerPackages(ctx context.Context, ownerID int64) (bool, error) {
  215. return db.GetEngine(ctx).
  216. Table("package_version").
  217. Join("INNER", "package", "package.id = package_version.package_id").
  218. Where(builder.Eq{
  219. "package_version.is_internal": false,
  220. "package.owner_id": ownerID,
  221. }).
  222. Exist(&PackageVersion{})
  223. }
  224. // HasRepositoryPackages tests if a repository has packages
  225. func HasRepositoryPackages(ctx context.Context, repositoryID int64) (bool, error) {
  226. return db.GetEngine(ctx).Where("repo_id = ?", repositoryID).Exist(&Package{})
  227. }