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.

packages.go 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  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. "strings"
  11. "time"
  12. "code.gitea.io/gitea/models/db"
  13. packages_model "code.gitea.io/gitea/models/packages"
  14. repo_model "code.gitea.io/gitea/models/repo"
  15. user_model "code.gitea.io/gitea/models/user"
  16. "code.gitea.io/gitea/modules/json"
  17. "code.gitea.io/gitea/modules/log"
  18. "code.gitea.io/gitea/modules/notification"
  19. packages_module "code.gitea.io/gitea/modules/packages"
  20. "code.gitea.io/gitea/modules/setting"
  21. "code.gitea.io/gitea/modules/util"
  22. container_service "code.gitea.io/gitea/services/packages/container"
  23. )
  24. var (
  25. ErrQuotaTypeSize = errors.New("maximum allowed package type size exceeded")
  26. ErrQuotaTotalSize = errors.New("maximum allowed package storage quota exceeded")
  27. ErrQuotaTotalCount = errors.New("maximum allowed package count exceeded")
  28. )
  29. // PackageInfo describes a package
  30. type PackageInfo struct {
  31. Owner *user_model.User
  32. PackageType packages_model.Type
  33. Name string
  34. Version string
  35. }
  36. // PackageCreationInfo describes a package to create
  37. type PackageCreationInfo struct {
  38. PackageInfo
  39. SemverCompatible bool
  40. Creator *user_model.User
  41. Metadata interface{}
  42. PackageProperties map[string]string
  43. VersionProperties map[string]string
  44. }
  45. // PackageFileInfo describes a package file
  46. type PackageFileInfo struct {
  47. Filename string
  48. CompositeKey string
  49. }
  50. // PackageFileCreationInfo describes a package file to create
  51. type PackageFileCreationInfo struct {
  52. PackageFileInfo
  53. Creator *user_model.User
  54. Data packages_module.HashedSizeReader
  55. IsLead bool
  56. Properties map[string]string
  57. OverwriteExisting bool
  58. }
  59. // CreatePackageAndAddFile creates a package with a file. If the same package exists already, ErrDuplicatePackageVersion is returned
  60. func CreatePackageAndAddFile(pvci *PackageCreationInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageVersion, *packages_model.PackageFile, error) {
  61. return createPackageAndAddFile(pvci, pfci, false)
  62. }
  63. // CreatePackageOrAddFileToExisting creates a package with a file or adds the file if the package exists already
  64. func CreatePackageOrAddFileToExisting(pvci *PackageCreationInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageVersion, *packages_model.PackageFile, error) {
  65. return createPackageAndAddFile(pvci, pfci, true)
  66. }
  67. func createPackageAndAddFile(pvci *PackageCreationInfo, pfci *PackageFileCreationInfo, allowDuplicate bool) (*packages_model.PackageVersion, *packages_model.PackageFile, error) {
  68. ctx, committer, err := db.TxContext(db.DefaultContext)
  69. if err != nil {
  70. return nil, nil, err
  71. }
  72. defer committer.Close()
  73. pv, created, err := createPackageAndVersion(ctx, pvci, allowDuplicate)
  74. if err != nil {
  75. return nil, nil, err
  76. }
  77. pf, pb, blobCreated, err := addFileToPackageVersion(ctx, pv, &pvci.PackageInfo, pfci)
  78. removeBlob := false
  79. defer func() {
  80. if blobCreated && removeBlob {
  81. contentStore := packages_module.NewContentStore()
  82. if err := contentStore.Delete(packages_module.BlobHash256Key(pb.HashSHA256)); err != nil {
  83. log.Error("Error deleting package blob from content store: %v", err)
  84. }
  85. }
  86. }()
  87. if err != nil {
  88. removeBlob = true
  89. return nil, nil, err
  90. }
  91. if err := committer.Commit(); err != nil {
  92. removeBlob = true
  93. return nil, nil, err
  94. }
  95. if created {
  96. pd, err := packages_model.GetPackageDescriptor(db.DefaultContext, pv)
  97. if err != nil {
  98. return nil, nil, err
  99. }
  100. notification.NotifyPackageCreate(db.DefaultContext, pvci.Creator, pd)
  101. }
  102. return pv, pf, nil
  103. }
  104. func createPackageAndVersion(ctx context.Context, pvci *PackageCreationInfo, allowDuplicate bool) (*packages_model.PackageVersion, bool, error) {
  105. 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)
  106. packageCreated := true
  107. p := &packages_model.Package{
  108. OwnerID: pvci.Owner.ID,
  109. Type: pvci.PackageType,
  110. Name: pvci.Name,
  111. LowerName: strings.ToLower(pvci.Name),
  112. SemverCompatible: pvci.SemverCompatible,
  113. }
  114. var err error
  115. if p, err = packages_model.TryInsertPackage(ctx, p); err != nil {
  116. if err == packages_model.ErrDuplicatePackage {
  117. packageCreated = false
  118. } else {
  119. log.Error("Error inserting package: %v", err)
  120. return nil, false, err
  121. }
  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 err == packages_model.ErrDuplicatePackageVersion {
  145. versionCreated = false
  146. }
  147. if err != packages_model.ErrDuplicatePackageVersion || !allowDuplicate {
  148. log.Error("Error inserting package: %v", err)
  149. return nil, false, err
  150. }
  151. }
  152. if versionCreated {
  153. if err := CheckCountQuotaExceeded(ctx, pvci.Creator, pvci.Owner); err != nil {
  154. return nil, false, err
  155. }
  156. for name, value := range pvci.VersionProperties {
  157. if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypeVersion, pv.ID, name, value); err != nil {
  158. log.Error("Error setting package version property: %v", err)
  159. return nil, false, err
  160. }
  161. }
  162. }
  163. return pv, versionCreated, nil
  164. }
  165. // AddFileToExistingPackage adds a file to an existing package. If the package does not exist, ErrPackageNotExist is returned
  166. func AddFileToExistingPackage(pvi *PackageInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageVersion, *packages_model.PackageFile, error) {
  167. ctx, committer, err := db.TxContext(db.DefaultContext)
  168. if err != nil {
  169. return nil, nil, err
  170. }
  171. defer committer.Close()
  172. pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
  173. if err != nil {
  174. return nil, nil, err
  175. }
  176. pf, pb, blobCreated, err := addFileToPackageVersion(ctx, pv, pvi, pfci)
  177. removeBlob := false
  178. defer func() {
  179. if removeBlob {
  180. contentStore := packages_module.NewContentStore()
  181. if err := contentStore.Delete(packages_module.BlobHash256Key(pb.HashSHA256)); err != nil {
  182. log.Error("Error deleting package blob from content store: %v", err)
  183. }
  184. }
  185. }()
  186. if err != nil {
  187. removeBlob = blobCreated
  188. return nil, nil, err
  189. }
  190. if err := committer.Commit(); err != nil {
  191. removeBlob = blobCreated
  192. return nil, nil, err
  193. }
  194. return pv, pf, nil
  195. }
  196. // NewPackageBlob creates a package blob instance
  197. func NewPackageBlob(hsr packages_module.HashedSizeReader) *packages_model.PackageBlob {
  198. hashMD5, hashSHA1, hashSHA256, hashSHA512 := hsr.Sums()
  199. return &packages_model.PackageBlob{
  200. Size: hsr.Size(),
  201. HashMD5: hex.EncodeToString(hashMD5),
  202. HashSHA1: hex.EncodeToString(hashSHA1),
  203. HashSHA256: hex.EncodeToString(hashSHA256),
  204. HashSHA512: hex.EncodeToString(hashSHA512),
  205. }
  206. }
  207. func addFileToPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pvi *PackageInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) {
  208. log.Trace("Adding package file: %v, %s", pv.ID, pfci.Filename)
  209. if err := CheckSizeQuotaExceeded(ctx, pfci.Creator, pvi.Owner, pvi.PackageType, pfci.Data.Size()); err != nil {
  210. return nil, nil, false, err
  211. }
  212. pb, exists, err := packages_model.GetOrInsertBlob(ctx, NewPackageBlob(pfci.Data))
  213. if err != nil {
  214. log.Error("Error inserting package blob: %v", err)
  215. return nil, nil, false, err
  216. }
  217. if !exists {
  218. contentStore := packages_module.NewContentStore()
  219. if err := contentStore.Save(packages_module.BlobHash256Key(pb.HashSHA256), pfci.Data, pfci.Data.Size()); err != nil {
  220. log.Error("Error saving package blob in content store: %v", err)
  221. return nil, nil, false, err
  222. }
  223. }
  224. if pfci.OverwriteExisting {
  225. pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, pfci.Filename, pfci.CompositeKey)
  226. if err != nil && err != packages_model.ErrPackageFileNotExist {
  227. return nil, pb, !exists, err
  228. }
  229. if pf != nil {
  230. // Short circuit if blob is the same
  231. if pf.BlobID == pb.ID {
  232. return pf, pb, !exists, nil
  233. }
  234. if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
  235. return nil, pb, !exists, err
  236. }
  237. if err := packages_model.DeleteFileByID(ctx, pf.ID); err != nil {
  238. return nil, pb, !exists, err
  239. }
  240. }
  241. }
  242. pf := &packages_model.PackageFile{
  243. VersionID: pv.ID,
  244. BlobID: pb.ID,
  245. Name: pfci.Filename,
  246. LowerName: strings.ToLower(pfci.Filename),
  247. CompositeKey: pfci.CompositeKey,
  248. IsLead: pfci.IsLead,
  249. }
  250. if pf, err = packages_model.TryInsertFile(ctx, pf); err != nil {
  251. if err != packages_model.ErrDuplicatePackageFile {
  252. log.Error("Error inserting package file: %v", err)
  253. }
  254. return nil, pb, !exists, err
  255. }
  256. for name, value := range pfci.Properties {
  257. if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypeFile, pf.ID, name, value); err != nil {
  258. log.Error("Error setting package file property: %v", err)
  259. return pf, pb, !exists, err
  260. }
  261. }
  262. return pf, pb, !exists, nil
  263. }
  264. // CheckCountQuotaExceeded checks if the owner has more than the allowed packages
  265. // The check is skipped if the doer is an admin.
  266. func CheckCountQuotaExceeded(ctx context.Context, doer, owner *user_model.User) error {
  267. if doer.IsAdmin {
  268. return nil
  269. }
  270. if setting.Packages.LimitTotalOwnerCount > -1 {
  271. totalCount, err := packages_model.CountVersions(ctx, &packages_model.PackageSearchOptions{
  272. OwnerID: owner.ID,
  273. IsInternal: util.OptionalBoolFalse,
  274. })
  275. if err != nil {
  276. log.Error("CountVersions failed: %v", err)
  277. return err
  278. }
  279. if totalCount > setting.Packages.LimitTotalOwnerCount {
  280. return ErrQuotaTotalCount
  281. }
  282. }
  283. return nil
  284. }
  285. // CheckSizeQuotaExceeded checks if the upload size is bigger than the allowed size
  286. // The check is skipped if the doer is an admin.
  287. func CheckSizeQuotaExceeded(ctx context.Context, doer, owner *user_model.User, packageType packages_model.Type, uploadSize int64) error {
  288. if doer.IsAdmin {
  289. return nil
  290. }
  291. var typeSpecificSize int64
  292. switch packageType {
  293. case packages_model.TypeComposer:
  294. typeSpecificSize = setting.Packages.LimitSizeComposer
  295. case packages_model.TypeConan:
  296. typeSpecificSize = setting.Packages.LimitSizeConan
  297. case packages_model.TypeContainer:
  298. typeSpecificSize = setting.Packages.LimitSizeContainer
  299. case packages_model.TypeGeneric:
  300. typeSpecificSize = setting.Packages.LimitSizeGeneric
  301. case packages_model.TypeHelm:
  302. typeSpecificSize = setting.Packages.LimitSizeHelm
  303. case packages_model.TypeMaven:
  304. typeSpecificSize = setting.Packages.LimitSizeMaven
  305. case packages_model.TypeNpm:
  306. typeSpecificSize = setting.Packages.LimitSizeNpm
  307. case packages_model.TypeNuGet:
  308. typeSpecificSize = setting.Packages.LimitSizeNuGet
  309. case packages_model.TypePub:
  310. typeSpecificSize = setting.Packages.LimitSizePub
  311. case packages_model.TypePyPI:
  312. typeSpecificSize = setting.Packages.LimitSizePyPI
  313. case packages_model.TypeRubyGems:
  314. typeSpecificSize = setting.Packages.LimitSizeRubyGems
  315. case packages_model.TypeVagrant:
  316. typeSpecificSize = setting.Packages.LimitSizeVagrant
  317. }
  318. if typeSpecificSize > -1 && typeSpecificSize < uploadSize {
  319. return ErrQuotaTypeSize
  320. }
  321. if setting.Packages.LimitTotalOwnerSize > -1 {
  322. totalSize, err := packages_model.CalculateFileSize(ctx, &packages_model.PackageFileSearchOptions{
  323. OwnerID: owner.ID,
  324. })
  325. if err != nil {
  326. log.Error("CalculateFileSize failed: %v", err)
  327. return err
  328. }
  329. if totalSize+uploadSize > setting.Packages.LimitTotalOwnerSize {
  330. return ErrQuotaTotalSize
  331. }
  332. }
  333. return nil
  334. }
  335. // RemovePackageVersionByNameAndVersion deletes a package version and all associated files
  336. func RemovePackageVersionByNameAndVersion(doer *user_model.User, pvi *PackageInfo) error {
  337. pv, err := packages_model.GetVersionByNameAndVersion(db.DefaultContext, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
  338. if err != nil {
  339. return err
  340. }
  341. return RemovePackageVersion(doer, pv)
  342. }
  343. // RemovePackageVersion deletes the package version and all associated files
  344. func RemovePackageVersion(doer *user_model.User, pv *packages_model.PackageVersion) error {
  345. ctx, committer, err := db.TxContext(db.DefaultContext)
  346. if err != nil {
  347. return err
  348. }
  349. defer committer.Close()
  350. pd, err := packages_model.GetPackageDescriptor(ctx, pv)
  351. if err != nil {
  352. return err
  353. }
  354. log.Trace("Deleting package: %v", pv.ID)
  355. if err := DeletePackageVersionAndReferences(ctx, pv); err != nil {
  356. return err
  357. }
  358. if err := committer.Commit(); err != nil {
  359. return err
  360. }
  361. notification.NotifyPackageDelete(db.DefaultContext, doer, pd)
  362. return nil
  363. }
  364. // DeletePackageVersionAndReferences deletes the package version and its properties and files
  365. func DeletePackageVersionAndReferences(ctx context.Context, pv *packages_model.PackageVersion) error {
  366. if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeVersion, pv.ID); err != nil {
  367. return err
  368. }
  369. pfs, err := packages_model.GetFilesByVersionID(ctx, pv.ID)
  370. if err != nil {
  371. return err
  372. }
  373. for _, pf := range pfs {
  374. if err := DeletePackageFile(ctx, pf); err != nil {
  375. return err
  376. }
  377. }
  378. return packages_model.DeleteVersionByID(ctx, pv.ID)
  379. }
  380. // DeletePackageFile deletes the package file and its properties
  381. func DeletePackageFile(ctx context.Context, pf *packages_model.PackageFile) error {
  382. if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
  383. return err
  384. }
  385. return packages_model.DeleteFileByID(ctx, pf.ID)
  386. }
  387. // Cleanup removes expired package data
  388. func Cleanup(taskCtx context.Context, olderThan time.Duration) error {
  389. ctx, committer, err := db.TxContext(taskCtx)
  390. if err != nil {
  391. return err
  392. }
  393. defer committer.Close()
  394. err = packages_model.IterateEnabledCleanupRules(ctx, func(ctx context.Context, pcr *packages_model.PackageCleanupRule) error {
  395. select {
  396. case <-taskCtx.Done():
  397. return db.ErrCancelledf("While processing package cleanup rules")
  398. default:
  399. }
  400. if err := pcr.CompiledPattern(); err != nil {
  401. return fmt.Errorf("CleanupRule [%d]: CompilePattern failed: %w", pcr.ID, err)
  402. }
  403. olderThan := time.Now().AddDate(0, 0, -pcr.RemoveDays)
  404. packages, err := packages_model.GetPackagesByType(ctx, pcr.OwnerID, pcr.Type)
  405. if err != nil {
  406. return fmt.Errorf("CleanupRule [%d]: GetPackagesByType failed: %w", pcr.ID, err)
  407. }
  408. for _, p := range packages {
  409. pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
  410. PackageID: p.ID,
  411. IsInternal: util.OptionalBoolFalse,
  412. Sort: packages_model.SortCreatedDesc,
  413. Paginator: db.NewAbsoluteListOptions(pcr.KeepCount, 200),
  414. })
  415. if err != nil {
  416. return fmt.Errorf("CleanupRule [%d]: SearchVersions failed: %w", pcr.ID, err)
  417. }
  418. for _, pv := range pvs {
  419. if skip, err := container_service.ShouldBeSkipped(ctx, pcr, p, pv); err != nil {
  420. return fmt.Errorf("CleanupRule [%d]: container.ShouldBeSkipped failed: %w", pcr.ID, err)
  421. } else if skip {
  422. log.Debug("Rule[%d]: keep '%s/%s' (container)", pcr.ID, p.Name, pv.Version)
  423. continue
  424. }
  425. toMatch := pv.LowerVersion
  426. if pcr.MatchFullName {
  427. toMatch = p.LowerName + "/" + pv.LowerVersion
  428. }
  429. if pcr.KeepPatternMatcher != nil && pcr.KeepPatternMatcher.MatchString(toMatch) {
  430. log.Debug("Rule[%d]: keep '%s/%s' (keep pattern)", pcr.ID, p.Name, pv.Version)
  431. continue
  432. }
  433. if pv.CreatedUnix.AsLocalTime().After(olderThan) {
  434. log.Debug("Rule[%d]: keep '%s/%s' (remove days)", pcr.ID, p.Name, pv.Version)
  435. continue
  436. }
  437. if pcr.RemovePatternMatcher != nil && !pcr.RemovePatternMatcher.MatchString(toMatch) {
  438. log.Debug("Rule[%d]: keep '%s/%s' (remove pattern)", pcr.ID, p.Name, pv.Version)
  439. continue
  440. }
  441. log.Debug("Rule[%d]: remove '%s/%s'", pcr.ID, p.Name, pv.Version)
  442. if err := DeletePackageVersionAndReferences(ctx, pv); err != nil {
  443. return fmt.Errorf("CleanupRule [%d]: DeletePackageVersionAndReferences failed: %w", pcr.ID, err)
  444. }
  445. }
  446. }
  447. return nil
  448. })
  449. if err != nil {
  450. return err
  451. }
  452. if err := container_service.Cleanup(ctx, olderThan); err != nil {
  453. return err
  454. }
  455. ps, err := packages_model.FindUnreferencedPackages(ctx)
  456. if err != nil {
  457. return err
  458. }
  459. for _, p := range ps {
  460. if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypePackage, p.ID); err != nil {
  461. return err
  462. }
  463. if err := packages_model.DeletePackageByID(ctx, p.ID); err != nil {
  464. return err
  465. }
  466. }
  467. pbs, err := packages_model.FindExpiredUnreferencedBlobs(ctx, olderThan)
  468. if err != nil {
  469. return err
  470. }
  471. for _, pb := range pbs {
  472. if err := packages_model.DeleteBlobByID(ctx, pb.ID); err != nil {
  473. return err
  474. }
  475. }
  476. if err := committer.Commit(); err != nil {
  477. return err
  478. }
  479. contentStore := packages_module.NewContentStore()
  480. for _, pb := range pbs {
  481. if err := contentStore.Delete(packages_module.BlobHash256Key(pb.HashSHA256)); err != nil {
  482. log.Error("Error deleting package blob [%v]: %v", pb.ID, err)
  483. }
  484. }
  485. return nil
  486. }
  487. // GetFileStreamByPackageNameAndVersion returns the content of the specific package file
  488. func GetFileStreamByPackageNameAndVersion(ctx context.Context, pvi *PackageInfo, pfi *PackageFileInfo) (io.ReadSeekCloser, *packages_model.PackageFile, error) {
  489. 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)
  490. pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
  491. if err != nil {
  492. if err == packages_model.ErrPackageNotExist {
  493. return nil, nil, err
  494. }
  495. log.Error("Error getting package: %v", err)
  496. return nil, nil, err
  497. }
  498. return GetFileStreamByPackageVersion(ctx, pv, pfi)
  499. }
  500. // GetFileStreamByPackageVersionAndFileID returns the content of the specific package file
  501. func GetFileStreamByPackageVersionAndFileID(ctx context.Context, owner *user_model.User, versionID, fileID int64) (io.ReadSeekCloser, *packages_model.PackageFile, error) {
  502. log.Trace("Getting package file stream: %v, %v, %v", owner.ID, versionID, fileID)
  503. pv, err := packages_model.GetVersionByID(ctx, versionID)
  504. if err != nil {
  505. if err != packages_model.ErrPackageNotExist {
  506. log.Error("Error getting package version: %v", err)
  507. }
  508. return nil, nil, err
  509. }
  510. p, err := packages_model.GetPackageByID(ctx, pv.PackageID)
  511. if err != nil {
  512. log.Error("Error getting package: %v", err)
  513. return nil, nil, err
  514. }
  515. if p.OwnerID != owner.ID {
  516. return nil, nil, packages_model.ErrPackageNotExist
  517. }
  518. pf, err := packages_model.GetFileForVersionByID(ctx, versionID, fileID)
  519. if err != nil {
  520. log.Error("Error getting file: %v", err)
  521. return nil, nil, err
  522. }
  523. return GetPackageFileStream(ctx, pf)
  524. }
  525. // GetFileStreamByPackageVersion returns the content of the specific package file
  526. func GetFileStreamByPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pfi *PackageFileInfo) (io.ReadSeekCloser, *packages_model.PackageFile, error) {
  527. pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, pfi.Filename, pfi.CompositeKey)
  528. if err != nil {
  529. return nil, nil, err
  530. }
  531. return GetPackageFileStream(ctx, pf)
  532. }
  533. // GetPackageFileStream returns the content of the specific package file
  534. func GetPackageFileStream(ctx context.Context, pf *packages_model.PackageFile) (io.ReadSeekCloser, *packages_model.PackageFile, error) {
  535. pb, err := packages_model.GetBlobByID(ctx, pf.BlobID)
  536. if err != nil {
  537. return nil, nil, err
  538. }
  539. s, err := packages_module.NewContentStore().Get(packages_module.BlobHash256Key(pb.HashSHA256))
  540. if err == nil {
  541. if pf.IsLead {
  542. if err := packages_model.IncrementDownloadCounter(ctx, pf.VersionID); err != nil {
  543. log.Error("Error incrementing download counter: %v", err)
  544. }
  545. }
  546. }
  547. return s, pf, err
  548. }
  549. // RemoveAllPackages for User
  550. func RemoveAllPackages(ctx context.Context, userID int64) (int, error) {
  551. count := 0
  552. for {
  553. pkgVersions, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
  554. Paginator: &db.ListOptions{
  555. PageSize: repo_model.RepositoryListDefaultPageSize,
  556. Page: 1,
  557. },
  558. OwnerID: userID,
  559. IsInternal: util.OptionalBoolNone,
  560. })
  561. if err != nil {
  562. return count, fmt.Errorf("GetOwnedPackages[%d]: %w", userID, err)
  563. }
  564. if len(pkgVersions) == 0 {
  565. break
  566. }
  567. for _, pv := range pkgVersions {
  568. if err := DeletePackageVersionAndReferences(ctx, pv); err != nil {
  569. return count, fmt.Errorf("unable to delete package %d:%s[%d]. Error: %w", pv.PackageID, pv.Version, pv.ID, err)
  570. }
  571. count++
  572. }
  573. }
  574. return count, nil
  575. }