code.gitea.io/gitea@v1.22.3/modules/storage/storage.go (about)

     1  // Copyright 2020 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package storage
     5  
     6  import (
     7  	"context"
     8  	"errors"
     9  	"fmt"
    10  	"io"
    11  	"net/url"
    12  	"os"
    13  
    14  	"code.gitea.io/gitea/modules/log"
    15  	"code.gitea.io/gitea/modules/setting"
    16  )
    17  
    18  // ErrURLNotSupported represents url is not supported
    19  var ErrURLNotSupported = errors.New("url method not supported")
    20  
    21  // ErrInvalidConfiguration is called when there is invalid configuration for a storage
    22  type ErrInvalidConfiguration struct {
    23  	cfg any
    24  	err error
    25  }
    26  
    27  func (err ErrInvalidConfiguration) Error() string {
    28  	if err.err != nil {
    29  		return fmt.Sprintf("Invalid Configuration Argument: %v: Error: %v", err.cfg, err.err)
    30  	}
    31  	return fmt.Sprintf("Invalid Configuration Argument: %v", err.cfg)
    32  }
    33  
    34  // IsErrInvalidConfiguration checks if an error is an ErrInvalidConfiguration
    35  func IsErrInvalidConfiguration(err error) bool {
    36  	_, ok := err.(ErrInvalidConfiguration)
    37  	return ok
    38  }
    39  
    40  type Type = setting.StorageType
    41  
    42  // NewStorageFunc is a function that creates a storage
    43  type NewStorageFunc func(ctx context.Context, cfg *setting.Storage) (ObjectStorage, error)
    44  
    45  var storageMap = map[Type]NewStorageFunc{}
    46  
    47  // RegisterStorageType registers a provided storage type with a function to create it
    48  func RegisterStorageType(typ Type, fn func(ctx context.Context, cfg *setting.Storage) (ObjectStorage, error)) {
    49  	storageMap[typ] = fn
    50  }
    51  
    52  // Object represents the object on the storage
    53  type Object interface {
    54  	io.ReadCloser
    55  	io.Seeker
    56  	Stat() (os.FileInfo, error)
    57  }
    58  
    59  // ObjectStorage represents an object storage to handle a bucket and files
    60  type ObjectStorage interface {
    61  	Open(path string) (Object, error)
    62  	// Save store a object, if size is unknown set -1
    63  	Save(path string, r io.Reader, size int64) (int64, error)
    64  	Stat(path string) (os.FileInfo, error)
    65  	Delete(path string) error
    66  	URL(path, name string) (*url.URL, error)
    67  	IterateObjects(path string, iterator func(path string, obj Object) error) error
    68  }
    69  
    70  // Copy copies a file from source ObjectStorage to dest ObjectStorage
    71  func Copy(dstStorage ObjectStorage, dstPath string, srcStorage ObjectStorage, srcPath string) (int64, error) {
    72  	f, err := srcStorage.Open(srcPath)
    73  	if err != nil {
    74  		return 0, err
    75  	}
    76  	defer f.Close()
    77  
    78  	size := int64(-1)
    79  	fsinfo, err := f.Stat()
    80  	if err == nil {
    81  		size = fsinfo.Size()
    82  	}
    83  
    84  	return dstStorage.Save(dstPath, f, size)
    85  }
    86  
    87  // Clean delete all the objects in this storage
    88  func Clean(storage ObjectStorage) error {
    89  	return storage.IterateObjects("", func(path string, obj Object) error {
    90  		_ = obj.Close()
    91  		return storage.Delete(path)
    92  	})
    93  }
    94  
    95  // SaveFrom saves data to the ObjectStorage with path p from the callback
    96  func SaveFrom(objStorage ObjectStorage, p string, callback func(w io.Writer) error) error {
    97  	pr, pw := io.Pipe()
    98  	defer pr.Close()
    99  	go func() {
   100  		defer pw.Close()
   101  		if err := callback(pw); err != nil {
   102  			_ = pw.CloseWithError(err)
   103  		}
   104  	}()
   105  
   106  	_, err := objStorage.Save(p, pr, -1)
   107  	return err
   108  }
   109  
   110  var (
   111  	// Attachments represents attachments storage
   112  	Attachments ObjectStorage = uninitializedStorage
   113  
   114  	// LFS represents lfs storage
   115  	LFS ObjectStorage = uninitializedStorage
   116  
   117  	// Avatars represents user avatars storage
   118  	Avatars ObjectStorage = uninitializedStorage
   119  	// RepoAvatars represents repository avatars storage
   120  	RepoAvatars ObjectStorage = uninitializedStorage
   121  
   122  	// RepoArchives represents repository archives storage
   123  	RepoArchives ObjectStorage = uninitializedStorage
   124  
   125  	// Packages represents packages storage
   126  	Packages ObjectStorage = uninitializedStorage
   127  
   128  	// Actions represents actions storage
   129  	Actions ObjectStorage = uninitializedStorage
   130  	// Actions Artifacts represents actions artifacts storage
   131  	ActionsArtifacts ObjectStorage = uninitializedStorage
   132  )
   133  
   134  // Init init the stoarge
   135  func Init() error {
   136  	for _, f := range []func() error{
   137  		initAttachments,
   138  		initAvatars,
   139  		initRepoAvatars,
   140  		initLFS,
   141  		initRepoArchives,
   142  		initPackages,
   143  		initActions,
   144  	} {
   145  		if err := f(); err != nil {
   146  			return err
   147  		}
   148  	}
   149  	return nil
   150  }
   151  
   152  // NewStorage takes a storage type and some config and returns an ObjectStorage or an error
   153  func NewStorage(typStr Type, cfg *setting.Storage) (ObjectStorage, error) {
   154  	if len(typStr) == 0 {
   155  		typStr = setting.LocalStorageType
   156  	}
   157  	fn, ok := storageMap[typStr]
   158  	if !ok {
   159  		return nil, fmt.Errorf("Unsupported storage type: %s", typStr)
   160  	}
   161  
   162  	return fn(context.Background(), cfg)
   163  }
   164  
   165  func initAvatars() (err error) {
   166  	log.Info("Initialising Avatar storage with type: %s", setting.Avatar.Storage.Type)
   167  	Avatars, err = NewStorage(setting.Avatar.Storage.Type, setting.Avatar.Storage)
   168  	return err
   169  }
   170  
   171  func initAttachments() (err error) {
   172  	if !setting.Attachment.Enabled {
   173  		Attachments = discardStorage("Attachment isn't enabled")
   174  		return nil
   175  	}
   176  	log.Info("Initialising Attachment storage with type: %s", setting.Attachment.Storage.Type)
   177  	Attachments, err = NewStorage(setting.Attachment.Storage.Type, setting.Attachment.Storage)
   178  	return err
   179  }
   180  
   181  func initLFS() (err error) {
   182  	if !setting.LFS.StartServer {
   183  		LFS = discardStorage("LFS isn't enabled")
   184  		return nil
   185  	}
   186  	log.Info("Initialising LFS storage with type: %s", setting.LFS.Storage.Type)
   187  	LFS, err = NewStorage(setting.LFS.Storage.Type, setting.LFS.Storage)
   188  	return err
   189  }
   190  
   191  func initRepoAvatars() (err error) {
   192  	log.Info("Initialising Repository Avatar storage with type: %s", setting.RepoAvatar.Storage.Type)
   193  	RepoAvatars, err = NewStorage(setting.RepoAvatar.Storage.Type, setting.RepoAvatar.Storage)
   194  	return err
   195  }
   196  
   197  func initRepoArchives() (err error) {
   198  	log.Info("Initialising Repository Archive storage with type: %s", setting.RepoArchive.Storage.Type)
   199  	RepoArchives, err = NewStorage(setting.RepoArchive.Storage.Type, setting.RepoArchive.Storage)
   200  	return err
   201  }
   202  
   203  func initPackages() (err error) {
   204  	if !setting.Packages.Enabled {
   205  		Packages = discardStorage("Packages isn't enabled")
   206  		return nil
   207  	}
   208  	log.Info("Initialising Packages storage with type: %s", setting.Packages.Storage.Type)
   209  	Packages, err = NewStorage(setting.Packages.Storage.Type, setting.Packages.Storage)
   210  	return err
   211  }
   212  
   213  func initActions() (err error) {
   214  	if !setting.Actions.Enabled {
   215  		Actions = discardStorage("Actions isn't enabled")
   216  		ActionsArtifacts = discardStorage("ActionsArtifacts isn't enabled")
   217  		return nil
   218  	}
   219  	log.Info("Initialising Actions storage with type: %s", setting.Actions.LogStorage.Type)
   220  	if Actions, err = NewStorage(setting.Actions.LogStorage.Type, setting.Actions.LogStorage); err != nil {
   221  		return err
   222  	}
   223  	log.Info("Initialising ActionsArtifacts storage with type: %s", setting.Actions.ArtifactStorage.Type)
   224  	ActionsArtifacts, err = NewStorage(setting.Actions.ArtifactStorage.Type, setting.Actions.ArtifactStorage)
   225  	return err
   226  }