gitea源码

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