aboutsummaryrefslogtreecommitdiff
path: root/internal/lfsutil/storage.go
diff options
context:
space:
mode:
authorᴜɴᴋɴᴡᴏɴ <u@gogs.io>2020-04-10 22:13:42 +0800
committerGitHub <noreply@github.com>2020-04-10 22:13:42 +0800
commit9a5b227f3ee2b2a3854d3aec022cc9a0cf0868b3 (patch)
tree7600826f4affce28e95588de921d801f0414f046 /internal/lfsutil/storage.go
parent3e055e329cf93eb5de77562d7795240808d31c08 (diff)
lfsutil: add `Storager` interface and local storage (#6083)
* Add Storager interface * Add tests * Add back note * Add tests for basic protocol routes * Fix lint errors
Diffstat (limited to 'internal/lfsutil/storage.go')
-rw-r--r--internal/lfsutil/storage.go93
1 files changed, 88 insertions, 5 deletions
diff --git a/internal/lfsutil/storage.go b/internal/lfsutil/storage.go
index b2bfe37f..a357b8a8 100644
--- a/internal/lfsutil/storage.go
+++ b/internal/lfsutil/storage.go
@@ -5,9 +5,31 @@
package lfsutil
import (
+ "io"
+ "os"
"path/filepath"
+
+ "github.com/pkg/errors"
+
+ "gogs.io/gogs/internal/osutil"
)
+var ErrObjectNotExist = errors.New("Object does not exist")
+
+// Storager is an storage backend for uploading and downloading LFS objects.
+type Storager interface {
+ // Storage returns the name of the storage backend.
+ Storage() Storage
+ // Upload reads content from the io.ReadCloser and uploads as given oid.
+ // The reader is closed once upload is finished. ErrInvalidOID is returned
+ // if the given oid is not valid.
+ Upload(oid OID, rc io.ReadCloser) (int64, error)
+ // Download streams content of given oid to the io.Writer. It is caller's
+ // responsibility the close the writer when needed. ErrObjectNotExist is
+ // returned if the given oid does not exist.
+ Download(oid OID, w io.Writer) error
+}
+
// Storage is the storage type of an LFS object.
type Storage string
@@ -15,12 +37,73 @@ const (
StorageLocal Storage = "local"
)
-// StorageLocalPath returns computed file path for storing object on local file system.
-// It returns empty string if given "oid" isn't valid.
-func StorageLocalPath(root string, oid OID) string {
- if !ValidOID(oid) {
+var _ Storager = (*LocalStorage)(nil)
+
+// LocalStorage is a LFS storage backend on local file system.
+type LocalStorage struct {
+ // The root path for storing LFS objects.
+ Root string
+}
+
+func (s *LocalStorage) Storage() Storage {
+ return StorageLocal
+}
+
+func (s *LocalStorage) storagePath(oid OID) string {
+ if len(oid) < 2 {
return ""
}
- return filepath.Join(root, string(oid[0]), string(oid[1]), string(oid))
+ return filepath.Join(s.Root, string(oid[0]), string(oid[1]), string(oid))
+}
+
+func (s *LocalStorage) Upload(oid OID, rc io.ReadCloser) (int64, error) {
+ if !ValidOID(oid) {
+ return 0, ErrInvalidOID
+ }
+
+ var err error
+ fpath := s.storagePath(oid)
+ defer func() {
+ rc.Close()
+
+ if err != nil {
+ _ = os.Remove(fpath)
+ }
+ }()
+
+ err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm)
+ if err != nil {
+ return 0, errors.Wrap(err, "create directories")
+ }
+ w, err := os.Create(fpath)
+ if err != nil {
+ return 0, errors.Wrap(err, "create file")
+ }
+ defer w.Close()
+
+ written, err := io.Copy(w, rc)
+ if err != nil {
+ return 0, errors.Wrap(err, "copy file")
+ }
+ return written, nil
+}
+
+func (s *LocalStorage) Download(oid OID, w io.Writer) error {
+ fpath := s.storagePath(oid)
+ if !osutil.IsFile(fpath) {
+ return ErrObjectNotExist
+ }
+
+ r, err := os.Open(fpath)
+ if err != nil {
+ return errors.Wrap(err, "open file")
+ }
+ defer r.Close()
+
+ _, err = io.Copy(w, r)
+ if err != nil {
+ return errors.Wrap(err, "copy file")
+ }
+ return nil
}