code.gitea.io/gitea@v1.19.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 interface{}
    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 is a type of Storage
    41  type Type string
    42  
    43  // NewStorageFunc is a function that creates a storage
    44  type NewStorageFunc func(ctx context.Context, cfg interface{}) (ObjectStorage, error)
    45  
    46  var storageMap = map[Type]NewStorageFunc{}
    47  
    48  // RegisterStorageType registers a provided storage type with a function to create it
    49  func RegisterStorageType(typ Type, fn func(ctx context.Context, cfg interface{}) (ObjectStorage, error)) {
    50  	storageMap[typ] = fn
    51  }
    52  
    53  // Object represents the object on the storage
    54  type Object interface {
    55  	io.ReadCloser
    56  	io.Seeker
    57  	Stat() (os.FileInfo, error)
    58  }
    59  
    60  // ObjectStorage represents an object storage to handle a bucket and files
    61  type ObjectStorage interface {
    62  	Open(path string) (Object, error)
    63  	// Save store a object, if size is unknown set -1
    64  	Save(path string, r io.Reader, size int64) (int64, error)
    65  	Stat(path string) (os.FileInfo, error)
    66  	Delete(path string) error
    67  	URL(path, name string) (*url.URL, error)
    68  	IterateObjects(func(path string, obj Object) error) error
    69  }
    70  
    71  // Copy copies a file from source ObjectStorage to dest ObjectStorage
    72  func Copy(dstStorage ObjectStorage, dstPath string, srcStorage ObjectStorage, srcPath string) (int64, error) {
    73  	f, err := srcStorage.Open(srcPath)
    74  	if err != nil {
    75  		return 0, err
    76  	}
    77  	defer f.Close()
    78  
    79  	size := int64(-1)
    80  	fsinfo, err := f.Stat()
    81  	if err == nil {
    82  		size = fsinfo.Size()
    83  	}
    84  
    85  	return dstStorage.Save(dstPath, f, size)
    86  }
    87  
    88  // Clean delete all the objects in this storage
    89  func Clean(storage ObjectStorage) error {
    90  	return storage.IterateObjects(func(path string, obj Object) error {
    91  		_ = obj.Close()
    92  		return storage.Delete(path)
    93  	})
    94  }
    95  
    96  // SaveFrom saves data to the ObjectStorage with path p from the callback
    97  func SaveFrom(objStorage ObjectStorage, p string, callback func(w io.Writer) error) error {
    98  	pr, pw := io.Pipe()
    99  	defer pr.Close()
   100  	go func() {
   101  		defer pw.Close()
   102  		if err := callback(pw); err != nil {
   103  			_ = pw.CloseWithError(err)
   104  		}
   105  	}()
   106  
   107  	_, err := objStorage.Save(p, pr, -1)
   108  	return err
   109  }
   110  
   111  var (
   112  	// Attachments represents attachments storage
   113  	Attachments ObjectStorage = uninitializedStorage
   114  
   115  	// LFS represents lfs storage
   116  	LFS ObjectStorage = uninitializedStorage
   117  
   118  	// Avatars represents user avatars storage
   119  	Avatars ObjectStorage = uninitializedStorage
   120  	// RepoAvatars represents repository avatars storage
   121  	RepoAvatars ObjectStorage = uninitializedStorage
   122  
   123  	// RepoArchives represents repository archives storage
   124  	RepoArchives ObjectStorage = uninitializedStorage
   125  
   126  	// Packages represents packages storage
   127  	Packages ObjectStorage = uninitializedStorage
   128  
   129  	// Actions represents actions storage
   130  	Actions ObjectStorage = uninitializedStorage
   131  )
   132  
   133  // Init init the stoarge
   134  func Init() error {
   135  	for _, f := range []func() error{
   136  		initAttachments,
   137  		initAvatars,
   138  		initRepoAvatars,
   139  		initLFS,
   140  		initRepoArchives,
   141  		initPackages,
   142  		initActions,
   143  	} {
   144  		if err := f(); err != nil {
   145  			return err
   146  		}
   147  	}
   148  	return nil
   149  }
   150  
   151  // NewStorage takes a storage type and some config and returns an ObjectStorage or an error
   152  func NewStorage(typStr string, cfg interface{}) (ObjectStorage, error) {
   153  	if len(typStr) == 0 {
   154  		typStr = string(LocalStorageType)
   155  	}
   156  	fn, ok := storageMap[Type(typStr)]
   157  	if !ok {
   158  		return nil, fmt.Errorf("Unsupported storage type: %s", typStr)
   159  	}
   160  
   161  	return fn(context.Background(), cfg)
   162  }
   163  
   164  func initAvatars() (err error) {
   165  	log.Info("Initialising Avatar storage with type: %s", setting.Avatar.Storage.Type)
   166  	Avatars, err = NewStorage(setting.Avatar.Storage.Type, &setting.Avatar.Storage)
   167  	return err
   168  }
   169  
   170  func initAttachments() (err error) {
   171  	if !setting.Attachment.Enabled {
   172  		Attachments = discardStorage("Attachment isn't enabled")
   173  		return nil
   174  	}
   175  	log.Info("Initialising Attachment storage with type: %s", setting.Attachment.Storage.Type)
   176  	Attachments, err = NewStorage(setting.Attachment.Storage.Type, &setting.Attachment.Storage)
   177  	return err
   178  }
   179  
   180  func initLFS() (err error) {
   181  	if !setting.LFS.StartServer {
   182  		LFS = discardStorage("LFS isn't enabled")
   183  		return nil
   184  	}
   185  	log.Info("Initialising LFS storage with type: %s", setting.LFS.Storage.Type)
   186  	LFS, err = NewStorage(setting.LFS.Storage.Type, &setting.LFS.Storage)
   187  	return err
   188  }
   189  
   190  func initRepoAvatars() (err error) {
   191  	log.Info("Initialising Repository Avatar storage with type: %s", setting.RepoAvatar.Storage.Type)
   192  	RepoAvatars, err = NewStorage(setting.RepoAvatar.Storage.Type, &setting.RepoAvatar.Storage)
   193  	return err
   194  }
   195  
   196  func initRepoArchives() (err error) {
   197  	log.Info("Initialising Repository Archive storage with type: %s", setting.RepoArchive.Storage.Type)
   198  	RepoArchives, err = NewStorage(setting.RepoArchive.Storage.Type, &setting.RepoArchive.Storage)
   199  	return err
   200  }
   201  
   202  func initPackages() (err error) {
   203  	if !setting.Packages.Enabled {
   204  		Packages = discardStorage("Packages isn't enabled")
   205  		return nil
   206  	}
   207  	log.Info("Initialising Packages storage with type: %s", setting.Packages.Storage.Type)
   208  	Packages, err = NewStorage(setting.Packages.Storage.Type, &setting.Packages.Storage)
   209  	return err
   210  }
   211  
   212  func initActions() (err error) {
   213  	if !setting.Actions.Enabled {
   214  		Actions = discardStorage("Actions isn't enabled")
   215  		return nil
   216  	}
   217  	log.Info("Initialising Actions storage with type: %s", setting.Actions.Storage.Type)
   218  	Actions, err = NewStorage(setting.Actions.Storage.Type, &setting.Actions.Storage)
   219  	return err
   220  }