gitea源码

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package packages
  4. import (
  5. "context"
  6. "encoding/hex"
  7. "errors"
  8. "fmt"
  9. "io"
  10. "net/http"
  11. "net/url"
  12. "strings"
  13. "code.gitea.io/gitea/models/db"
  14. packages_model "code.gitea.io/gitea/models/packages"
  15. repo_model "code.gitea.io/gitea/models/repo"
  16. user_model "code.gitea.io/gitea/models/user"
  17. "code.gitea.io/gitea/modules/json"
  18. "code.gitea.io/gitea/modules/log"
  19. "code.gitea.io/gitea/modules/optional"
  20. packages_module "code.gitea.io/gitea/modules/packages"
  21. "code.gitea.io/gitea/modules/setting"
  22. "code.gitea.io/gitea/modules/storage"
  23. notify_service "code.gitea.io/gitea/services/notify"
  24. )
  25. var (
  26. ErrQuotaTypeSize = errors.New("maximum allowed package type size exceeded")
  27. ErrQuotaTotalSize = errors.New("maximum allowed package storage quota exceeded")
  28. ErrQuotaTotalCount = errors.New("maximum allowed package count exceeded")
  29. )
  30. // PackageInfo describes a package
  31. type PackageInfo struct {
  32. Owner *user_model.User
  33. PackageType packages_model.Type
  34. Name string
  35. Version string
  36. }
  37. // PackageCreationInfo describes a package to create
  38. type PackageCreationInfo struct {
  39. PackageInfo
  40. SemverCompatible bool
  41. Creator *user_model.User
  42. Metadata any
  43. PackageProperties map[string]string
  44. VersionProperties map[string]string
  45. }
  46. // PackageFileInfo describes a package file
  47. type PackageFileInfo struct {
  48. Filename string
  49. CompositeKey string
  50. }
  51. // PackageFileCreationInfo describes a package file to create
  52. type PackageFileCreationInfo struct {
  53. PackageFileInfo
  54. Creator *user_model.User
  55. Data packages_module.HashedSizeReader
  56. IsLead bool
  57. Properties map[string]string
  58. OverwriteExisting bool
  59. }
  60. // CreatePackageAndAddFile creates a package with a file. If the same package exists already, ErrDuplicatePackageVersion is returned
  61. func CreatePackageAndAddFile(ctx context.Context, pvci *PackageCreationInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageVersion, *packages_model.PackageFile, error) {
  62. return createPackageAndAddFile(ctx, pvci, pfci, false)
  63. }
  64. // CreatePackageOrAddFileToExisting creates a package with a file or adds the file if the package exists already
  65. func CreatePackageOrAddFileToExisting(ctx context.Context, pvci *PackageCreationInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageVersion, *packages_model.PackageFile, error) {
  66. return createPackageAndAddFile(ctx, pvci, pfci, true)
  67. }
  68. func createPackageAndAddFile(ctx context.Context, pvci *PackageCreationInfo, pfci *PackageFileCreationInfo, allowDuplicate bool) (*packages_model.PackageVersion, *packages_model.PackageFile, error) {
  69. dbCtx, committer, err := db.TxContext(ctx)
  70. if err != nil {
  71. return nil, nil, err
  72. }
  73. defer committer.Close()
  74. pv, created, err := createPackageAndVersion(dbCtx, pvci, allowDuplicate)
  75. if err != nil {
  76. return nil, nil, err
  77. }
  78. pf, pb, blobCreated, err := addFileToPackageVersion(dbCtx, pv, &pvci.PackageInfo, pfci)
  79. removeBlob := false
  80. defer func() {
  81. if blobCreated && removeBlob {
  82. contentStore := packages_module.NewContentStore()
  83. if err := contentStore.Delete(packages_module.BlobHash256Key(pb.HashSHA256)); err != nil {
  84. log.Error("Error deleting package blob from content store: %v", err)
  85. }
  86. }
  87. }()
  88. if err != nil {
  89. removeBlob = true
  90. return nil, nil, err
  91. }
  92. if err := committer.Commit(); err != nil {
  93. removeBlob = true
  94. return nil, nil, err
  95. }
  96. if created {
  97. pd, err := packages_model.GetPackageDescriptor(ctx, pv)
  98. if err != nil {
  99. return nil, nil, err
  100. }
  101. notify_service.PackageCreate(ctx, pvci.Creator, pd)
  102. }
  103. return pv, pf, nil
  104. }
  105. func createPackageAndVersion(ctx context.Context, pvci *PackageCreationInfo, allowDuplicate bool) (*packages_model.PackageVersion, bool, error) {
  106. log.Trace("Creating package: %v, %v, %v, %s, %s, %+v, %+v, %v", pvci.Creator.ID, pvci.Owner.ID, pvci.PackageType, pvci.Name, pvci.Version, pvci.PackageProperties, pvci.VersionProperties, allowDuplicate)
  107. packageCreated := true
  108. p := &packages_model.Package{
  109. OwnerID: pvci.Owner.ID,
  110. Type: pvci.PackageType,
  111. Name: pvci.Name,
  112. LowerName: strings.ToLower(pvci.Name),
  113. SemverCompatible: pvci.SemverCompatible,
  114. }
  115. var err error
  116. if p, err = packages_model.TryInsertPackage(ctx, p); err != nil {
  117. if !errors.Is(err, packages_model.ErrDuplicatePackage) {
  118. log.Error("Error inserting package: %v", err)
  119. return nil, false, err
  120. }
  121. packageCreated = false
  122. }
  123. if packageCreated {
  124. for name, value := range pvci.PackageProperties {
  125. if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypePackage, p.ID, name, value); err != nil {
  126. log.Error("Error setting package property: %v", err)
  127. return nil, false, err
  128. }
  129. }
  130. }
  131. metadataJSON, err := json.Marshal(pvci.Metadata)
  132. if err != nil {
  133. return nil, false, err
  134. }
  135. versionCreated := true
  136. pv := &packages_model.PackageVersion{
  137. PackageID: p.ID,
  138. CreatorID: pvci.Creator.ID,
  139. Version: pvci.Version,
  140. LowerVersion: strings.ToLower(pvci.Version),
  141. MetadataJSON: string(metadataJSON),
  142. }
  143. if pv, err = packages_model.GetOrInsertVersion(ctx, pv); err != nil {
  144. if errors.Is(err, packages_model.ErrDuplicatePackageVersion) && allowDuplicate {
  145. versionCreated = false
  146. } else {
  147. log.Error("Error inserting package: %v", err) // other error, or disallowing duplicates
  148. return nil, false, err
  149. }
  150. }
  151. if versionCreated {
  152. if err := CheckCountQuotaExceeded(ctx, pvci.Creator, pvci.Owner); err != nil {
  153. return nil, false, err
  154. }
  155. for name, value := range pvci.VersionProperties {
  156. if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypeVersion, pv.ID, name, value); err != nil {
  157. log.Error("Error setting package version property: %v", err)
  158. return nil, false, err
  159. }
  160. }
  161. }
  162. return pv, versionCreated, nil
  163. }
  164. // AddFileToExistingPackage adds a file to an existing package. If the package does not exist, ErrPackageNotExist is returned
  165. func AddFileToExistingPackage(ctx context.Context, pvi *PackageInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, error) {
  166. return addFileToPackageWrapper(ctx, func(ctx context.Context) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) {
  167. pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
  168. if err != nil {
  169. return nil, nil, false, err
  170. }
  171. return addFileToPackageVersion(ctx, pv, pvi, pfci)
  172. })
  173. }
  174. // AddFileToPackageVersionInternal adds a file to the package
  175. // This method skips quota checks and should only be used for system-managed packages.
  176. func AddFileToPackageVersionInternal(ctx context.Context, pv *packages_model.PackageVersion, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, error) {
  177. return addFileToPackageWrapper(ctx, func(ctx context.Context) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) {
  178. return addFileToPackageVersionUnchecked(ctx, pv, pfci)
  179. })
  180. }
  181. func addFileToPackageWrapper(ctx context.Context, fn func(ctx context.Context) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error)) (*packages_model.PackageFile, error) {
  182. ctx, committer, err := db.TxContext(ctx)
  183. if err != nil {
  184. return nil, err
  185. }
  186. defer committer.Close()
  187. pf, pb, blobCreated, err := fn(ctx)
  188. removeBlob := false
  189. defer func() {
  190. if removeBlob {
  191. contentStore := packages_module.NewContentStore()
  192. if err := contentStore.Delete(packages_module.BlobHash256Key(pb.HashSHA256)); err != nil {
  193. log.Error("Error deleting package blob from content store: %v", err)
  194. }
  195. }
  196. }()
  197. if err != nil {
  198. removeBlob = blobCreated
  199. return nil, err
  200. }
  201. if err := committer.Commit(); err != nil {
  202. removeBlob = blobCreated
  203. return nil, err
  204. }
  205. return pf, nil
  206. }
  207. // NewPackageBlob creates a package blob instance
  208. func NewPackageBlob(hsr packages_module.HashedSizeReader) *packages_model.PackageBlob {
  209. hashMD5, hashSHA1, hashSHA256, hashSHA512 := hsr.Sums()
  210. return &packages_model.PackageBlob{
  211. Size: hsr.Size(),
  212. HashMD5: hex.EncodeToString(hashMD5),
  213. HashSHA1: hex.EncodeToString(hashSHA1),
  214. HashSHA256: hex.EncodeToString(hashSHA256),
  215. HashSHA512: hex.EncodeToString(hashSHA512),
  216. }
  217. }
  218. func addFileToPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pvi *PackageInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) {
  219. if err := CheckSizeQuotaExceeded(ctx, pfci.Creator, pvi.Owner, pvi.PackageType, pfci.Data.Size()); err != nil {
  220. return nil, nil, false, err
  221. }
  222. return addFileToPackageVersionUnchecked(ctx, pv, pfci)
  223. }
  224. func addFileToPackageVersionUnchecked(ctx context.Context, pv *packages_model.PackageVersion, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) {
  225. log.Trace("Adding package file: %v, %s", pv.ID, pfci.Filename)
  226. pb, exists, err := packages_model.GetOrInsertBlob(ctx, NewPackageBlob(pfci.Data))
  227. if err != nil {
  228. log.Error("Error inserting package blob: %v", err)
  229. return nil, nil, false, err
  230. }
  231. if !exists {
  232. contentStore := packages_module.NewContentStore()
  233. if err := contentStore.Save(packages_module.BlobHash256Key(pb.HashSHA256), pfci.Data, pfci.Data.Size()); err != nil {
  234. log.Error("Error saving package blob in content store: %v", err)
  235. return nil, nil, false, err
  236. }
  237. }
  238. if pfci.OverwriteExisting {
  239. pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, pfci.Filename, pfci.CompositeKey)
  240. if err != nil && err != packages_model.ErrPackageFileNotExist {
  241. return nil, pb, !exists, err
  242. }
  243. if pf != nil {
  244. // Short circuit if blob is the same
  245. if pf.BlobID == pb.ID {
  246. return pf, pb, !exists, nil
  247. }
  248. if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
  249. return nil, pb, !exists, err
  250. }
  251. if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
  252. return nil, pb, !exists, err
  253. }
  254. }
  255. }
  256. pf := &packages_model.PackageFile{
  257. VersionID: pv.ID,
  258. BlobID: pb.ID,
  259. Name: pfci.Filename,
  260. LowerName: strings.ToLower(pfci.Filename),
  261. CompositeKey: pfci.CompositeKey,
  262. IsLead: pfci.IsLead,
  263. }
  264. if pf, err = packages_model.TryInsertFile(ctx, pf); err != nil {
  265. if err != packages_model.ErrDuplicatePackageFile {
  266. log.Error("Error inserting package file: %v", err)
  267. }
  268. return nil, pb, !exists, err
  269. }
  270. for name, value := range pfci.Properties {
  271. if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypeFile, pf.ID, name, value); err != nil {
  272. log.Error("Error setting package file property: %v", err)
  273. return pf, pb, !exists, err
  274. }
  275. }
  276. return pf, pb, !exists, nil
  277. }
  278. // CheckCountQuotaExceeded checks if the owner has more than the allowed packages
  279. // The check is skipped if the doer is an admin.
  280. func CheckCountQuotaExceeded(ctx context.Context, doer, owner *user_model.User) error {
  281. if doer.IsAdmin {
  282. return nil
  283. }
  284. if setting.Packages.LimitTotalOwnerCount > -1 {
  285. totalCount, err := packages_model.CountVersions(ctx, &packages_model.PackageSearchOptions{
  286. OwnerID: owner.ID,
  287. IsInternal: optional.Some(false),
  288. })
  289. if err != nil {
  290. log.Error("CountVersions failed: %v", err)
  291. return err
  292. }
  293. if totalCount > setting.Packages.LimitTotalOwnerCount {
  294. return ErrQuotaTotalCount
  295. }
  296. }
  297. return nil
  298. }
  299. // CheckSizeQuotaExceeded checks if the upload size is bigger than the allowed size
  300. // The check is skipped if the doer is an admin.
  301. func CheckSizeQuotaExceeded(ctx context.Context, doer, owner *user_model.User, packageType packages_model.Type, uploadSize int64) error {
  302. if doer.IsAdmin {
  303. return nil
  304. }
  305. var typeSpecificSize int64
  306. switch packageType {
  307. case packages_model.TypeAlpine:
  308. typeSpecificSize = setting.Packages.LimitSizeAlpine
  309. case packages_model.TypeArch:
  310. typeSpecificSize = setting.Packages.LimitSizeArch
  311. case packages_model.TypeCargo:
  312. typeSpecificSize = setting.Packages.LimitSizeCargo
  313. case packages_model.TypeChef:
  314. typeSpecificSize = setting.Packages.LimitSizeChef
  315. case packages_model.TypeComposer:
  316. typeSpecificSize = setting.Packages.LimitSizeComposer
  317. case packages_model.TypeConan:
  318. typeSpecificSize = setting.Packages.LimitSizeConan
  319. case packages_model.TypeConda:
  320. typeSpecificSize = setting.Packages.LimitSizeConda
  321. case packages_model.TypeContainer:
  322. typeSpecificSize = setting.Packages.LimitSizeContainer
  323. case packages_model.TypeCran:
  324. typeSpecificSize = setting.Packages.LimitSizeCran
  325. case packages_model.TypeDebian:
  326. typeSpecificSize = setting.Packages.LimitSizeDebian
  327. case packages_model.TypeGeneric:
  328. typeSpecificSize = setting.Packages.LimitSizeGeneric
  329. case packages_model.TypeGo:
  330. typeSpecificSize = setting.Packages.LimitSizeGo
  331. case packages_model.TypeHelm:
  332. typeSpecificSize = setting.Packages.LimitSizeHelm
  333. case packages_model.TypeMaven:
  334. typeSpecificSize = setting.Packages.LimitSizeMaven
  335. case packages_model.TypeNpm:
  336. typeSpecificSize = setting.Packages.LimitSizeNpm
  337. case packages_model.TypeNuGet:
  338. typeSpecificSize = setting.Packages.LimitSizeNuGet
  339. case packages_model.TypePub:
  340. typeSpecificSize = setting.Packages.LimitSizePub
  341. case packages_model.TypePyPI:
  342. typeSpecificSize = setting.Packages.LimitSizePyPI
  343. case packages_model.TypeRpm:
  344. typeSpecificSize = setting.Packages.LimitSizeRpm
  345. case packages_model.TypeRubyGems:
  346. typeSpecificSize = setting.Packages.LimitSizeRubyGems
  347. case packages_model.TypeSwift:
  348. typeSpecificSize = setting.Packages.LimitSizeSwift
  349. case packages_model.TypeVagrant:
  350. typeSpecificSize = setting.Packages.LimitSizeVagrant
  351. }
  352. if typeSpecificSize > -1 && typeSpecificSize < uploadSize {
  353. return ErrQuotaTypeSize
  354. }
  355. if setting.Packages.LimitTotalOwnerSize > -1 {
  356. totalSize, err := packages_model.CalculateFileSize(ctx, &packages_model.PackageFileSearchOptions{
  357. OwnerID: owner.ID,
  358. })
  359. if err != nil {
  360. log.Error("CalculateFileSize failed: %v", err)
  361. return err
  362. }
  363. if totalSize+uploadSize > setting.Packages.LimitTotalOwnerSize {
  364. return ErrQuotaTotalSize
  365. }
  366. }
  367. return nil
  368. }
  369. // GetOrCreateInternalPackageVersion gets or creates an internal package
  370. // Some package types need such internal packages for housekeeping.
  371. func GetOrCreateInternalPackageVersion(ctx context.Context, ownerID int64, packageType packages_model.Type, name, version string) (*packages_model.PackageVersion, error) {
  372. var pv *packages_model.PackageVersion
  373. return pv, db.WithTx(ctx, func(ctx context.Context) error {
  374. p := &packages_model.Package{
  375. OwnerID: ownerID,
  376. Type: packageType,
  377. Name: name,
  378. LowerName: name,
  379. IsInternal: true,
  380. }
  381. var err error
  382. if p, err = packages_model.TryInsertPackage(ctx, p); err != nil {
  383. if !errors.Is(err, packages_model.ErrDuplicatePackage) {
  384. log.Error("Error inserting package: %v", err)
  385. return err
  386. }
  387. }
  388. pv = &packages_model.PackageVersion{
  389. PackageID: p.ID,
  390. CreatorID: ownerID,
  391. Version: version,
  392. LowerVersion: version,
  393. IsInternal: true,
  394. MetadataJSON: "null",
  395. }
  396. if pv, err = packages_model.GetOrInsertVersion(ctx, pv); err != nil {
  397. if err != packages_model.ErrDuplicatePackageVersion {
  398. log.Error("Error inserting package version: %v", err)
  399. return err
  400. }
  401. }
  402. return nil
  403. })
  404. }
  405. // RemovePackageVersionByNameAndVersion deletes a package version and all associated files
  406. func RemovePackageVersionByNameAndVersion(ctx context.Context, doer *user_model.User, pvi *PackageInfo) error {
  407. pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
  408. if err != nil {
  409. return err
  410. }
  411. return RemovePackageVersion(ctx, doer, pv)
  412. }
  413. // RemovePackageVersion deletes the package version and all associated files
  414. func RemovePackageVersion(ctx context.Context, doer *user_model.User, pv *packages_model.PackageVersion) error {
  415. pd, err := packages_model.GetPackageDescriptor(ctx, pv)
  416. if err != nil {
  417. return err
  418. }
  419. if err := db.WithTx(ctx, func(ctx context.Context) error {
  420. log.Trace("Deleting package: %v", pv.ID)
  421. return DeletePackageVersionAndReferences(ctx, pv)
  422. }); err != nil {
  423. return err
  424. }
  425. notify_service.PackageDelete(ctx, doer, pd)
  426. return nil
  427. }
  428. // RemovePackageFileAndVersionIfUnreferenced deletes the package file and the version if there are no referenced files afterwards
  429. func RemovePackageFileAndVersionIfUnreferenced(ctx context.Context, doer *user_model.User, pf *packages_model.PackageFile) error {
  430. var pd *packages_model.PackageDescriptor
  431. if err := db.WithTx(ctx, func(ctx context.Context) error {
  432. if err := DeletePackageFile(ctx, pf); err != nil {
  433. return err
  434. }
  435. has, err := packages_model.HasVersionFileReferences(ctx, pf.VersionID)
  436. if err != nil {
  437. return err
  438. }
  439. if !has {
  440. pv, err := packages_model.GetVersionByID(ctx, pf.VersionID)
  441. if err != nil {
  442. return err
  443. }
  444. pd, err = packages_model.GetPackageDescriptor(ctx, pv)
  445. if err != nil {
  446. return err
  447. }
  448. if err := DeletePackageVersionAndReferences(ctx, pv); err != nil {
  449. return err
  450. }
  451. }
  452. return nil
  453. }); err != nil {
  454. return err
  455. }
  456. if pd != nil {
  457. notify_service.PackageDelete(ctx, doer, pd)
  458. }
  459. return nil
  460. }
  461. // DeletePackageVersionAndReferences deletes the package version and its properties and files
  462. func DeletePackageVersionAndReferences(ctx context.Context, pv *packages_model.PackageVersion) error {
  463. if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeVersion, pv.ID); err != nil {
  464. return err
  465. }
  466. pfs, err := packages_model.GetFilesByVersionID(ctx, pv.ID)
  467. if err != nil {
  468. return err
  469. }
  470. for _, pf := range pfs {
  471. if err := DeletePackageFile(ctx, pf); err != nil {
  472. return err
  473. }
  474. }
  475. return packages_model.DeleteVersionByID(ctx, pv.ID)
  476. }
  477. // DeletePackageFile deletes the package file and its properties
  478. func DeletePackageFile(ctx context.Context, pf *packages_model.PackageFile) error {
  479. if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
  480. return err
  481. }
  482. return packages_model.DeleteFileByID(ctx, pf.ID)
  483. }
  484. // OpenFileForDownloadByPackageNameAndVersion returns the content of the specific package file and increases the download counter.
  485. func OpenFileForDownloadByPackageNameAndVersion(ctx context.Context, pvi *PackageInfo, pfi *PackageFileInfo, method string) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
  486. log.Trace("Getting package file stream: %v, %v, %s, %s, %s, %s", pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version, pfi.Filename, pfi.CompositeKey)
  487. pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
  488. if err != nil {
  489. if err == packages_model.ErrPackageNotExist {
  490. return nil, nil, nil, err
  491. }
  492. log.Error("Error getting package: %v", err)
  493. return nil, nil, nil, err
  494. }
  495. return OpenFileForDownloadByPackageVersion(ctx, pv, pfi, method)
  496. }
  497. // OpenFileForDownloadByPackageVersion returns the content of the specific package file and increases the download counter.
  498. func OpenFileForDownloadByPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pfi *PackageFileInfo, method string) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
  499. pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, pfi.Filename, pfi.CompositeKey)
  500. if err != nil {
  501. return nil, nil, nil, err
  502. }
  503. return OpenFileForDownload(ctx, pf, method)
  504. }
  505. // OpenFileForDownload returns the content of the specific package file and increases the download counter.
  506. func OpenFileForDownload(ctx context.Context, pf *packages_model.PackageFile, method string) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
  507. pb, err := packages_model.GetBlobByID(ctx, pf.BlobID)
  508. if err != nil {
  509. return nil, nil, nil, err
  510. }
  511. return OpenBlobForDownload(ctx, pf, pb, method, nil)
  512. }
  513. func OpenBlobStream(pb *packages_model.PackageBlob) (io.ReadSeekCloser, error) {
  514. cs := packages_module.NewContentStore()
  515. key := packages_module.BlobHash256Key(pb.HashSHA256)
  516. return cs.OpenBlob(key)
  517. }
  518. // OpenBlobForDownload returns the content of the specific package blob and increases the download counter.
  519. // If the storage supports direct serving and it's enabled, only the direct serving url is returned.
  520. func OpenBlobForDownload(ctx context.Context, pf *packages_model.PackageFile, pb *packages_model.PackageBlob, method string, serveDirectReqParams url.Values) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
  521. key := packages_module.BlobHash256Key(pb.HashSHA256)
  522. cs := packages_module.NewContentStore()
  523. var s io.ReadSeekCloser
  524. var u *url.URL
  525. var err error
  526. if cs.ShouldServeDirect() {
  527. u, err = cs.GetServeDirectURL(key, pf.Name, method, serveDirectReqParams)
  528. if err != nil && !errors.Is(err, storage.ErrURLNotSupported) {
  529. log.Error("Error getting serve direct url (fallback to local reader): %v", err)
  530. }
  531. }
  532. if u == nil {
  533. s, err = cs.OpenBlob(key)
  534. }
  535. if err != nil {
  536. return nil, nil, nil, err
  537. }
  538. if pf.IsLead && method == http.MethodGet {
  539. if err := packages_model.IncrementDownloadCounter(ctx, pf.VersionID); err != nil {
  540. log.Error("Error incrementing download counter: %v", err)
  541. }
  542. }
  543. return s, u, pf, nil
  544. }
  545. // RemoveAllPackages for User
  546. func RemoveAllPackages(ctx context.Context, userID int64) (int, error) {
  547. count := 0
  548. for {
  549. pkgVersions, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
  550. Paginator: &db.ListOptions{
  551. PageSize: repo_model.RepositoryListDefaultPageSize,
  552. Page: 1,
  553. },
  554. OwnerID: userID,
  555. IsInternal: optional.None[bool](),
  556. })
  557. if err != nil {
  558. return count, fmt.Errorf("GetOwnedPackages[%d]: %w", userID, err)
  559. }
  560. if len(pkgVersions) == 0 {
  561. break
  562. }
  563. for _, pv := range pkgVersions {
  564. if err := DeletePackageVersionAndReferences(ctx, pv); err != nil {
  565. return count, fmt.Errorf("unable to delete package %d:%s[%d]. Error: %w", pv.PackageID, pv.Version, pv.ID, err)
  566. }
  567. count++
  568. }
  569. }
  570. return count, nil
  571. }