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

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