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.

storage.go 6.5KB

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