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.4KB

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