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

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