123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- // Copyright 2022 The Gitea Authors. All rights reserved.
- // SPDX-License-Identifier: MIT
-
- package container
-
- import (
- "context"
- "encoding/hex"
- "errors"
- "fmt"
- "os"
- "strings"
- "sync"
-
- "code.gitea.io/gitea/models/db"
- packages_model "code.gitea.io/gitea/models/packages"
- container_model "code.gitea.io/gitea/models/packages/container"
- "code.gitea.io/gitea/modules/log"
- packages_module "code.gitea.io/gitea/modules/packages"
- container_module "code.gitea.io/gitea/modules/packages/container"
- "code.gitea.io/gitea/modules/util"
- packages_service "code.gitea.io/gitea/services/packages"
- )
-
- var uploadVersionMutex sync.Mutex
-
- // saveAsPackageBlob creates a package blob from an upload
- // The uploaded blob gets stored in a special upload version to link them to the package/image
- func saveAsPackageBlob(hsr packages_module.HashedSizeReader, pi *packages_service.PackageInfo) (*packages_model.PackageBlob, error) {
- pb := packages_service.NewPackageBlob(hsr)
-
- exists := false
-
- contentStore := packages_module.NewContentStore()
-
- uploadVersion, err := getOrCreateUploadVersion(pi)
- if err != nil {
- return nil, err
- }
-
- err = db.WithTx(db.DefaultContext, func(ctx context.Context) error {
- pb, exists, err = packages_model.GetOrInsertBlob(ctx, pb)
- if err != nil {
- log.Error("Error inserting package blob: %v", err)
- return err
- }
- // FIXME: Workaround to be removed in v1.20
- // https://github.com/go-gitea/gitea/issues/19586
- if exists {
- err = contentStore.Has(packages_module.BlobHash256Key(pb.HashSHA256))
- if err != nil && (errors.Is(err, util.ErrNotExist) || errors.Is(err, os.ErrNotExist)) {
- log.Debug("Package registry inconsistent: blob %s does not exist on file system", pb.HashSHA256)
- exists = false
- }
- }
- if !exists {
- if err := contentStore.Save(packages_module.BlobHash256Key(pb.HashSHA256), hsr, hsr.Size()); err != nil {
- log.Error("Error saving package blob in content store: %v", err)
- return err
- }
- }
-
- return createFileForBlob(ctx, uploadVersion, pb)
- })
- if err != nil {
- if !exists {
- if err := contentStore.Delete(packages_module.BlobHash256Key(pb.HashSHA256)); err != nil {
- log.Error("Error deleting package blob from content store: %v", err)
- }
- }
- return nil, err
- }
-
- return pb, nil
- }
-
- // mountBlob mounts the specific blob to a different package
- func mountBlob(pi *packages_service.PackageInfo, pb *packages_model.PackageBlob) error {
- uploadVersion, err := getOrCreateUploadVersion(pi)
- if err != nil {
- return err
- }
-
- return db.WithTx(db.DefaultContext, func(ctx context.Context) error {
- return createFileForBlob(ctx, uploadVersion, pb)
- })
- }
-
- func getOrCreateUploadVersion(pi *packages_service.PackageInfo) (*packages_model.PackageVersion, error) {
- var uploadVersion *packages_model.PackageVersion
-
- // FIXME: Replace usage of mutex with database transaction
- // https://github.com/go-gitea/gitea/pull/21862
- uploadVersionMutex.Lock()
- err := db.WithTx(db.DefaultContext, func(ctx context.Context) error {
- created := true
- p := &packages_model.Package{
- OwnerID: pi.Owner.ID,
- Type: packages_model.TypeContainer,
- Name: strings.ToLower(pi.Name),
- LowerName: strings.ToLower(pi.Name),
- }
- var err error
- if p, err = packages_model.TryInsertPackage(ctx, p); err != nil {
- if err == packages_model.ErrDuplicatePackage {
- created = false
- } else {
- log.Error("Error inserting package: %v", err)
- return err
- }
- }
-
- if created {
- if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypePackage, p.ID, container_module.PropertyRepository, strings.ToLower(pi.Owner.LowerName+"/"+pi.Name)); err != nil {
- log.Error("Error setting package property: %v", err)
- return err
- }
- }
-
- pv := &packages_model.PackageVersion{
- PackageID: p.ID,
- CreatorID: pi.Owner.ID,
- Version: container_model.UploadVersion,
- LowerVersion: container_model.UploadVersion,
- IsInternal: true,
- MetadataJSON: "null",
- }
- if pv, err = packages_model.GetOrInsertVersion(ctx, pv); err != nil {
- if err != packages_model.ErrDuplicatePackageVersion {
- log.Error("Error inserting package: %v", err)
- return err
- }
- }
-
- uploadVersion = pv
-
- return nil
- })
- uploadVersionMutex.Unlock()
-
- return uploadVersion, err
- }
-
- func createFileForBlob(ctx context.Context, pv *packages_model.PackageVersion, pb *packages_model.PackageBlob) error {
- filename := strings.ToLower(fmt.Sprintf("sha256_%s", pb.HashSHA256))
-
- pf := &packages_model.PackageFile{
- VersionID: pv.ID,
- BlobID: pb.ID,
- Name: filename,
- LowerName: filename,
- CompositeKey: packages_model.EmptyFileKey,
- }
- var err error
- if pf, err = packages_model.TryInsertFile(ctx, pf); err != nil {
- if err == packages_model.ErrDuplicatePackageFile {
- return nil
- }
- log.Error("Error inserting package file: %v", err)
- return err
- }
-
- if _, err := packages_model.InsertProperty(ctx, packages_model.PropertyTypeFile, pf.ID, container_module.PropertyDigest, digestFromPackageBlob(pb)); err != nil {
- log.Error("Error setting package file property: %v", err)
- return err
- }
-
- return nil
- }
-
- func deleteBlob(ownerID int64, image, digest string) error {
- return db.WithTx(db.DefaultContext, func(ctx context.Context) error {
- pfds, err := container_model.GetContainerBlobs(ctx, &container_model.BlobSearchOptions{
- OwnerID: ownerID,
- Image: image,
- Digest: digest,
- })
- if err != nil {
- return err
- }
-
- for _, file := range pfds {
- if err := packages_service.DeletePackageFile(ctx, file.File); err != nil {
- return err
- }
- }
- return nil
- })
- }
-
- func digestFromHashSummer(h packages_module.HashSummer) string {
- _, _, hashSHA256, _ := h.Sums()
- return "sha256:" + hex.EncodeToString(hashSHA256)
- }
-
- func digestFromPackageBlob(pb *packages_model.PackageBlob) string {
- return "sha256:" + pb.HashSHA256
- }
|