tavern/asset/storage_file.go

105 lines
2.3 KiB
Go

package asset
import (
"context"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"github.com/ngerakines/tavern/errors"
)
type fileStorage struct {
Base string
}
const (
filePrefix = "file://"
)
func NewFileStorage(base string) (Storage, error) {
if !filepath.IsAbs(base) {
return nil, fmt.Errorf("base path is not absolute: %s", base)
}
return &fileStorage{
Base: base,
}, nil
}
var _ Storage = fileStorage{}
func (f fileStorage) Close() error {
return nil
}
func (f fileStorage) Create(ctx context.Context, fileName string, reader io.Reader) (string, error) {
fullPath := filepath.Join(f.Base, fileName)
prefixedPath := fmt.Sprintf("%s%s", filePrefix, fullPath)
exists, err := f.Exists(ctx, prefixedPath)
if err != nil {
return "", errors.NewAssetExistsError(err)
}
if exists {
return "", errors.NewAssetExistsError(nil)
}
out, err := os.Create(fullPath)
if err != nil {
return "", err
}
defer out.Close()
_, err = io.Copy(out, reader)
if err != nil {
return "", err
}
return prefixedPath, err
}
func (f fileStorage) Delete(ctx context.Context, location string) error {
if !strings.HasPrefix(location, fmt.Sprintf("%s%s", filePrefix, f.Base)) {
return fmt.Errorf("invalid file storage location: %s", location)
}
location = strings.TrimPrefix(location, filePrefix)
return os.Remove(location)
}
func (f fileStorage) Exists(ctx context.Context, location string) (bool, error) {
if !strings.HasPrefix(location, fmt.Sprintf("%s%s", filePrefix, f.Base)) {
return false, fmt.Errorf("invalid file storage location: %s", location)
}
location = strings.TrimPrefix(location, filePrefix)
_, err := os.Stat(location)
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
return true, nil
}
func (f fileStorage) Read(ctx context.Context, location string) (io.ReadCloser, error) {
if !strings.HasPrefix(location, fmt.Sprintf("%s%s", filePrefix, f.Base)) {
return nil, fmt.Errorf("invalid file storage location: %s", location)
}
location = strings.TrimPrefix(location, filePrefix)
return os.Open(location)
}
func (f fileStorage) Upload(ctx context.Context, checksum string, source string) (string, error) {
file, err := os.Open(source)
if err != nil {
return "", err
}
// TODO: handle this error
defer file.Close()
return f.Create(ctx, checksum, file)
}