Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

packages.go 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  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. func checkCountQuotaExceeded(ctx context.Context, doer, owner *user_model.User) error {
  265. if doer.IsAdmin {
  266. return nil
  267. }
  268. if setting.Packages.LimitTotalOwnerCount > -1 {
  269. totalCount, err := packages_model.CountVersions(ctx, &packages_model.PackageSearchOptions{
  270. OwnerID: owner.ID,
  271. IsInternal: util.OptionalBoolFalse,
  272. })
  273. if err != nil {
  274. log.Error("CountVersions failed: %v", err)
  275. return err
  276. }
  277. if totalCount > setting.Packages.LimitTotalOwnerCount {
  278. return ErrQuotaTotalCount
  279. }
  280. }
  281. return nil
  282. }
  283. func checkSizeQuotaExceeded(ctx context.Context, doer, owner *user_model.User, packageType packages_model.Type, uploadSize int64) error {
  284. if doer.IsAdmin {
  285. return nil
  286. }
  287. var typeSpecificSize int64
  288. switch packageType {
  289. case packages_model.TypeComposer:
  290. typeSpecificSize = setting.Packages.LimitSizeComposer
  291. case packages_model.TypeConan:
  292. typeSpecificSize = setting.Packages.LimitSizeConan
  293. case packages_model.TypeContainer:
  294. typeSpecificSize = setting.Packages.LimitSizeContainer
  295. case packages_model.TypeGeneric:
  296. typeSpecificSize = setting.Packages.LimitSizeGeneric
  297. case packages_model.TypeHelm:
  298. typeSpecificSize = setting.Packages.LimitSizeHelm
  299. case packages_model.TypeMaven:
  300. typeSpecificSize = setting.Packages.LimitSizeMaven
  301. case packages_model.TypeNpm:
  302. typeSpecificSize = setting.Packages.LimitSizeNpm
  303. case packages_model.TypeNuGet:
  304. typeSpecificSize = setting.Packages.LimitSizeNuGet
  305. case packages_model.TypePub:
  306. typeSpecificSize = setting.Packages.LimitSizePub
  307. case packages_model.TypePyPI:
  308. typeSpecificSize = setting.Packages.LimitSizePyPI
  309. case packages_model.TypeRubyGems:
  310. typeSpecificSize = setting.Packages.LimitSizeRubyGems
  311. case packages_model.TypeVagrant:
  312. typeSpecificSize = setting.Packages.LimitSizeVagrant
  313. }
  314. if typeSpecificSize > -1 && typeSpecificSize < uploadSize {
  315. return ErrQuotaTypeSize
  316. }
  317. if setting.Packages.LimitTotalOwnerSize > -1 {
  318. totalSize, err := packages_model.CalculateFileSize(ctx, &packages_model.PackageFileSearchOptions{
  319. OwnerID: owner.ID,
  320. })
  321. if err != nil {
  322. log.Error("CalculateFileSize failed: %v", err)
  323. return err
  324. }
  325. if totalSize+uploadSize > setting.Packages.LimitTotalOwnerSize {
  326. return ErrQuotaTotalSize
  327. }
  328. }
  329. return nil
  330. }
  331. // RemovePackageVersionByNameAndVersion deletes a package version and all associated files
  332. func RemovePackageVersionByNameAndVersion(doer *user_model.User, pvi *PackageInfo) error {
  333. pv, err := packages_model.GetVersionByNameAndVersion(db.DefaultContext, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
  334. if err != nil {
  335. return err
  336. }
  337. return RemovePackageVersion(doer, pv)
  338. }
  339. // RemovePackageVersion deletes the package version and all associated files
  340. func RemovePackageVersion(doer *user_model.User, pv *packages_model.PackageVersion) error {
  341. ctx, committer, err := db.TxContext(db.DefaultContext)
  342. if err != nil {
  343. return err
  344. }
  345. defer committer.Close()
  346. pd, err := packages_model.GetPackageDescriptor(ctx, pv)
  347. if err != nil {
  348. return err
  349. }
  350. log.Trace("Deleting package: %v", pv.ID)
  351. if err := DeletePackageVersionAndReferences(ctx, pv); err != nil {
  352. return err
  353. }
  354. if err := committer.Commit(); err != nil {
  355. return err
  356. }
  357. notification.NotifyPackageDelete(db.DefaultContext, doer, pd)
  358. return nil
  359. }
  360. // DeletePackageVersionAndReferences deletes the package version and its properties and files
  361. func DeletePackageVersionAndReferences(ctx context.Context, pv *packages_model.PackageVersion) error {
  362. if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeVersion, pv.ID); err != nil {
  363. return err
  364. }
  365. pfs, err := packages_model.GetFilesByVersionID(ctx, pv.ID)
  366. if err != nil {
  367. return err
  368. }
  369. for _, pf := range pfs {
  370. if err := DeletePackageFile(ctx, pf); err != nil {
  371. return err
  372. }
  373. }
  374. return packages_model.DeleteVersionByID(ctx, pv.ID)
  375. }
  376. // DeletePackageFile deletes the package file and its properties
  377. func DeletePackageFile(ctx context.Context, pf *packages_model.PackageFile) error {
  378. if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil {
  379. return err
  380. }
  381. return packages_model.DeleteFileByID(ctx, pf.ID)
  382. }
  383. // Cleanup removes expired package data
  384. func Cleanup(taskCtx context.Context, olderThan time.Duration) error {
  385. ctx, committer, err := db.TxContext(taskCtx)
  386. if err != nil {
  387. return err
  388. }
  389. defer committer.Close()
  390. err = packages_model.IterateEnabledCleanupRules(ctx, func(ctx context.Context, pcr *packages_model.PackageCleanupRule) error {
  391. select {
  392. case <-taskCtx.Done():
  393. return db.ErrCancelledf("While processing package cleanup rules")
  394. default:
  395. }
  396. if err := pcr.CompiledPattern(); err != nil {
  397. return fmt.Errorf("CleanupRule [%d]: CompilePattern failed: %w", pcr.ID, err)
  398. }
  399. olderThan := time.Now().AddDate(0, 0, -pcr.RemoveDays)
  400. packages, err := packages_model.GetPackagesByType(ctx, pcr.OwnerID, pcr.Type)
  401. if err != nil {
  402. return fmt.Errorf("CleanupRule [%d]: GetPackagesByType failed: %w", pcr.ID, err)
  403. }
  404. for _, p := range packages {
  405. pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{
  406. PackageID: p.ID,
  407. IsInternal: util.OptionalBoolFalse,
  408. Sort: packages_model.SortCreatedDesc,
  409. Paginator: db.NewAbsoluteListOptions(pcr.KeepCount, 200),
  410. })
  411. if err != nil {
  412. return fmt.Errorf("CleanupRule [%d]: SearchVersions failed: %w", pcr.ID, err)
  413. }
  414. for _, pv := range pvs {
  415. if skip, err := container_service.ShouldBeSkipped(ctx, pcr, p, pv); err != nil {
  416. return fmt.Errorf("CleanupRule [%d]: container.ShouldBeSkipped failed: %w", pcr.ID, err)
  417. } else if skip {
  418. log.Debug("Rule[%d]: keep '%s/%s' (container)", pcr.ID, p.Name, pv.Version)
  419. continue
  420. }
  421. toMatch := pv.LowerVersion
  422. if pcr.MatchFullName {
  423. toMatch = p.LowerName + "/" + pv.LowerVersion
  424. }
  425. if pcr.KeepPatternMatcher != nil && pcr.KeepPatternMatcher.MatchString(toMatch) {
  426. log.Debug("Rule[%d]: keep '%s/%s' (keep pattern)", pcr.ID, p.Name, pv.Version)
  427. continue
  428. }
  429. if pv.CreatedUnix.AsLocalTime().After(olderThan) {
  430. log.Debug("Rule[%d]: keep '%s/%s' (remove days)", pcr.ID, p.Name, pv.Version)
  431. continue
  432. }
  433. if pcr.RemovePatternMatcher != nil && !pcr.RemovePatternMatcher.MatchString(toMatch) {
  434. log.Debug("Rule[%d]: keep '%s/%s' (remove pattern)", pcr.ID, p.Name, pv.Version)
  435. continue
  436. }
  437. log.Debug("Rule[%d]: remove '%s/%s'", pcr.ID, p.Name, pv.Version)
  438. if err := DeletePackageVersionAndReferences(ctx, pv); err != nil {
  439. return fmt.Errorf("CleanupRule [%d]: DeletePackageVersionAndReferences failed: %w", pcr.ID, err)
  440. }
  441. }
  442. }
  443. return nil
  444. })
  445. if err != nil {
  446. return err
  447. }
  448. if err := container_service.Cleanup(ctx, olderThan); err != nil {
  449. return err
  450. }
  451. ps, err := packages_model.FindUnreferencedPackages(ctx)
  452. if err != nil {
  453. return err
  454. }
  455. for _, p := range ps {
  456. if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypePackage, p.ID); err != nil {
  457. return err
  458. }
  459. if err := packages_model.DeletePackageByID(ctx, p.ID); err != nil {
  460. return err
  461. }
  462. }
  463. pbs, err := packages_model.FindExpiredUnreferencedBlobs(ctx, olderThan)
  464. if err != nil {
  465. return err
  466. }
  467. for _, pb := range pbs {
  468. if err := packages_model.DeleteBlobByID(ctx, pb.ID); err != nil {
  469. return err
  470. }
  471. }
  472. if err := committer.Commit(); err != nil {
  473. return err
  474. }
  475. contentStore := packages_module.NewContentStore()
  476. for _, pb := range pbs {
  477. if err := contentStore.Delete(packages_module.BlobHash256Key(pb.HashSHA256)); err != nil {
  478. log.Error("Error deleting package blob [%v]: %v", pb.ID, err)
  479. }
  480. }
  481. return nil
  482. }
  483. // GetFileStreamByPackageNameAndVersion returns the content of the specific package file
  484. func GetFileStreamByPackageNameAndVersion(ctx context.Context, pvi *PackageInfo, pfi *PackageFileInfo) (io.ReadSeekCloser, *packages_model.PackageFile, error) {
  485. 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)
  486. pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
  487. if err != nil {
  488. if err == packages_model.ErrPackageNotExist {
  489. return nil, nil, err
  490. }
  491. log.Error("Error getting package: %v", err)
  492. return nil, nil, err
  493. }
  494. return GetFileStreamByPackageVersion(ctx, pv, pfi)
  495. }
  496. // GetFileStreamByPackageVersionAndFileID returns the content of the specific package file
  497. func GetFileStreamByPackageVersionAndFileID(ctx context.Context, owner *user_model.User, versionID, fileID int64) (io.ReadSeekCloser, *packages_model.PackageFile, error) {
  498. log.Trace("Getting package file stream: %v, %v, %v", owner.ID, versionID, fileID)
  499. pv, err := packages_model.GetVersionByID(ctx, versionID)
  500. if err != nil {
  501. if err != packages_model.ErrPackageNotExist {
  502. log.Error("Error getting package version: %v", err)
  503. }
  504. return nil, nil, err
  505. }
  506. p, err := packages_model.GetPackageByID(ctx, pv.PackageID)
  507. if err != nil {
  508. log.Error("Error getting package: %v", err)
  509. return nil, nil, err
  510. }
  511. if p.OwnerID != owner.ID {
  512. return nil, nil, packages_model.ErrPackageNotExist
  513. }
  514. pf, err := packages_model.GetFileForVersionByID(ctx, versionID, fileID)
  515. if err != nil {
  516. log.Error("Error getting file: %v", err)
  517. return nil, nil, err
  518. }
  519. return GetPackageFileStream(ctx, pf)
  520. }
  521. // GetFileStreamByPackageVersion returns the content of the specific package file
  522. func GetFileStreamByPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pfi *PackageFileInfo) (io.ReadSeekCloser, *packages_model.PackageFile, error) {
  523. pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, pfi.Filename, pfi.CompositeKey)
  524. if err != nil {
  525. return nil, nil, err
  526. }
  527. return GetPackageFileStream(ctx, pf)
  528. }
  529. // GetPackageFileStream returns the content of the specific package file
  530. func GetPackageFileStream(ctx context.Context, pf *packages_model.PackageFile) (io.ReadSeekCloser, *packages_model.PackageFile, error) {
  531. pb, err := packages_model.GetBlobByID(ctx, pf.BlobID)
  532. if err != nil {
  533. return nil, nil, err
  534. }
  535. s, err := packages_module.NewContentStore().Get(packages_module.BlobHash256Key(pb.HashSHA256))
  536. if err == nil {
  537. if pf.IsLead {
  538. if err := packages_model.IncrementDownloadCounter(ctx, pf.VersionID); err != nil {
  539. log.Error("Error incrementing download counter: %v", err)
  540. }
  541. }
  542. }
  543. return s, pf, err
  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: util.OptionalBoolNone,
  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. }