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 5.5KB

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