mirror of https://gitlab.com/ngerakines/tavern.git
Fixed bug in asset storage. Added support for referrencing existing file.
This commit is contained in:
parent
6b3059b62f
commit
811ff6bab5
|
@ -71,7 +71,7 @@ func fileCommandAction(cliCtx *cli.Context) error {
|
|||
s := storage.DefaultStorage(storage.LoggingSQLDriver{Driver: db, Logger: logger})
|
||||
|
||||
a := Agent{
|
||||
AssetStorage: FileStorage{Base: "./assets/"},
|
||||
AssetStorage: fileStorage{Base: "./assets/"},
|
||||
DataStorage: s,
|
||||
HTTPClient: common.DefaultHTTPClient(),
|
||||
}
|
||||
|
|
|
@ -7,37 +7,43 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/ngerakines/tavern/errors"
|
||||
)
|
||||
|
||||
type FileStorage struct {
|
||||
type fileStorage struct {
|
||||
Base string
|
||||
}
|
||||
|
||||
const (
|
||||
filePrefix = "file:/"
|
||||
filePrefix = "file://"
|
||||
)
|
||||
|
||||
func NewFileStorage(base string) Storage {
|
||||
return &FileStorage{
|
||||
Base: base,
|
||||
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{}
|
||||
var _ Storage = fileStorage{}
|
||||
|
||||
func (f FileStorage) Close() error {
|
||||
func (f fileStorage) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f FileStorage) Create(ctx context.Context, fileName string, reader io.Reader) (string, error) {
|
||||
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, fileName)
|
||||
exists, err := f.Exists(ctx, prefixedPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return "", errors.NewAssetExistsError(err)
|
||||
}
|
||||
if exists {
|
||||
return "", fmt.Errorf("file exists")
|
||||
return "", errors.NewAssetExistsError(nil)
|
||||
}
|
||||
|
||||
out, err := os.Create(fullPath)
|
||||
|
@ -50,10 +56,10 @@ func (f FileStorage) Create(ctx context.Context, fileName string, reader io.Read
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%s%s", filePrefix, fullPath), err
|
||||
return prefixedPath, err
|
||||
}
|
||||
|
||||
func (f FileStorage) Delete(ctx context.Context, location string) error {
|
||||
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)
|
||||
}
|
||||
|
@ -62,7 +68,7 @@ func (f FileStorage) Delete(ctx context.Context, location string) error {
|
|||
return os.Remove(location)
|
||||
}
|
||||
|
||||
func (f FileStorage) Exists(ctx context.Context, location string) (bool, error) {
|
||||
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)
|
||||
}
|
||||
|
@ -78,7 +84,7 @@ func (f FileStorage) Exists(ctx context.Context, location string) (bool, error)
|
|||
return true, nil
|
||||
}
|
||||
|
||||
func (f FileStorage) Read(ctx context.Context, location string) (io.ReadCloser, error) {
|
||||
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)
|
||||
}
|
||||
|
@ -87,7 +93,7 @@ func (f FileStorage) Read(ctx context.Context, location string) (io.ReadCloser,
|
|||
return os.Open(location)
|
||||
}
|
||||
|
||||
func (f FileStorage) Upload(ctx context.Context, checksum string, source string) (string, error) {
|
||||
func (f fileStorage) Upload(ctx context.Context, checksum string, source string) (string, error) {
|
||||
file, err := os.Open(source)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by herr at 2020-04-06 16:49:37.156923587 -0400 EDT m=+0.009252653
|
||||
// This file was generated by herr at 2020-04-25 17:37:16.201857172 -0400 EDT m=+0.009406643
|
||||
package errors
|
||||
|
||||
import (
|
||||
|
@ -950,6 +950,11 @@ type AccessDeniedError struct {
|
|||
Stack *stack
|
||||
}
|
||||
|
||||
type AssetExistsError struct {
|
||||
Err error
|
||||
Stack *stack
|
||||
}
|
||||
|
||||
var _ CodedError = NotFoundError{}
|
||||
var _ CodedError = EncryptFailedError{}
|
||||
var _ CodedError = DecryptFailedError{}
|
||||
|
@ -1136,6 +1141,7 @@ var _ CodedError = TranslatorNotFoundError{}
|
|||
var _ CodedError = TranslationNotFoundError{}
|
||||
var _ CodedError = InvalidUserIDError{}
|
||||
var _ CodedError = AccessDeniedError{}
|
||||
var _ CodedError = AssetExistsError{}
|
||||
|
||||
// ErrorFromCode returns the CodedError for a serialized coded error string.
|
||||
func ErrorFromCode(code string) (bool, error) {
|
||||
|
@ -1512,6 +1518,8 @@ func ErrorFromCode(code string) (bool, error) {
|
|||
return true, InvalidUserIDError{}
|
||||
case "TAVWEBAAAAAAAJ":
|
||||
return true, AccessDeniedError{}
|
||||
case "TAVWEBAAAAAAAK":
|
||||
return true, AssetExistsError{}
|
||||
default:
|
||||
return false, fmt.Errorf("unknown error code: %s", code)
|
||||
}
|
||||
|
@ -3935,6 +3943,19 @@ func WrapAccessDeniedError(err error) error {
|
|||
return NewAccessDeniedError(err)
|
||||
}
|
||||
|
||||
func NewAssetExistsError(err error) error {
|
||||
|
||||
return AssetExistsError{ Err: err, Stack: callers() }
|
||||
|
||||
}
|
||||
|
||||
func WrapAssetExistsError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return NewAssetExistsError(err)
|
||||
}
|
||||
|
||||
func (e NotFoundError) Error() string {
|
||||
return "TAVAAAAAAAB"
|
||||
}
|
||||
|
@ -12863,6 +12884,54 @@ func (e AccessDeniedError) Format(s fmt.State, verb rune) {
|
|||
}
|
||||
}
|
||||
|
||||
func (e AssetExistsError) Error() string {
|
||||
return "TAVWEBAAAAAAAK"
|
||||
}
|
||||
|
||||
func (e AssetExistsError) Unwrap() error {
|
||||
return e.Err
|
||||
}
|
||||
|
||||
func (e AssetExistsError) Is(target error) bool {
|
||||
t, ok := target.(AssetExistsError)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return t.Prefix() == "TAVWEB" && t.Code() == 10
|
||||
}
|
||||
|
||||
func (e AssetExistsError) Code() int {
|
||||
return 10
|
||||
}
|
||||
|
||||
func (e AssetExistsError) Description() string {
|
||||
return "The asset exists."
|
||||
}
|
||||
|
||||
func (e AssetExistsError) Prefix() string {
|
||||
return "TAVWEB"
|
||||
}
|
||||
|
||||
func (e AssetExistsError) String() string {
|
||||
return "TAVWEBAAAAAAAK The asset exists."
|
||||
}
|
||||
|
||||
func (e AssetExistsError) Format(s fmt.State, verb rune) {
|
||||
switch verb {
|
||||
case 'v':
|
||||
if s.Flag('+') {
|
||||
fmt.Fprintf(s, "%+v", e.Unwrap())
|
||||
e.Stack.Format(s, verb)
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
case 's':
|
||||
io.WriteString(s, "TAVWEBAAAAAAAK")
|
||||
case 'q':
|
||||
fmt.Fprintf(s, "%q", "TAVWEBAAAAAAAK")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Frame represents a program counter inside a stack frame.
|
||||
// For historical reasons if Frame is interpreted as a uintptr
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by herr at 2020-04-06 16:49:37.190086312 -0400 EDT m=+0.042415353
|
||||
// This file was generated by herr at 2020-04-25 17:37:16.231089715 -0400 EDT m=+0.038639143
|
||||
package errors
|
||||
|
||||
import (
|
||||
|
@ -9018,4 +9018,50 @@ func TestAccessDenied (t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAssetExists (t *testing.T) {
|
||||
err1 := NewAssetExistsError(nil)
|
||||
{
|
||||
err1, ok := err1.(AssetExistsError)
|
||||
if !ok {
|
||||
t.Errorf("Assertion failed on AssetExists: %T is not AssetExistsError", err1)
|
||||
}
|
||||
if err1.Prefix() != "TAVWEB" {
|
||||
t.Errorf("Assertion failed on AssetExists: %s != TAVWEB", err1.Prefix())
|
||||
}
|
||||
if err1.Code() != 10 {
|
||||
t.Errorf("Assertion failed on AssetExists: %d != 10", err1.Code())
|
||||
}
|
||||
if err1.Description() != "The asset exists." {
|
||||
t.Errorf("Assertion failed on AssetExists: %s != The asset exists.", err1.Description())
|
||||
}
|
||||
}
|
||||
|
||||
errNotFound := fmt.Errorf("not found")
|
||||
errThingNotFound := fmt.Errorf("thing: %w", errNotFound)
|
||||
err2 := NewAssetExistsError(errThingNotFound)
|
||||
{
|
||||
err2, ok := err2.(AssetExistsError)
|
||||
if !ok {
|
||||
t.Errorf("Assertion failed on AssetExists: %T is not AssetExistsError", err2)
|
||||
}
|
||||
errNestErr2 := fmt.Errorf("oh snap: %w", err2)
|
||||
if err2.Code() != 10 {
|
||||
t.Errorf("Assertion failed on AssetExists: %d != 10", err2.Code())
|
||||
}
|
||||
if !errors.Is(err2, errNotFound) {
|
||||
t.Errorf("Assertion failed on AssetExists: errNotFound not unwrapped correctly")
|
||||
}
|
||||
if !errors.Is(err2, errThingNotFound) {
|
||||
t.Errorf("Assertion failed on AssetExists: errThingNotFound not unwrapped correctly")
|
||||
}
|
||||
if !errors.Is(err2, AssetExistsError{}) {
|
||||
t.Errorf("Assertion failed on AssetExists: AssetExistsError{} not identified correctly")
|
||||
}
|
||||
if !errors.Is(errNestErr2, AssetExistsError{}) {
|
||||
t.Errorf("Assertion failed on AssetExists: AssetExistsError{} not identified correctly")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -6,4 +6,5 @@
|
|||
6,TAVWEB,TranslatorNotFound ,Translator not found # Used when the underlying translation system isn't found.
|
||||
7,TAVWEB,TranslationNotFound ,Translation not found
|
||||
8,TAVWEB,InvalidUserID ,The user id is invalid.
|
||||
9,TAVWEB,AccessDenied ,Access denied.
|
||||
9,TAVWEB,AccessDenied ,Access denied.
|
||||
10,TAVWEB,AssetExists,The asset exists.
|
|
1
go.mod
1
go.mod
|
@ -24,6 +24,7 @@ require (
|
|||
github.com/piprate/json-gold v0.3.0
|
||||
github.com/prometheus/client_golang v1.5.1
|
||||
github.com/russross/blackfriday/v2 v2.0.1
|
||||
github.com/sslhound/herr v1.4.1 // indirect
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/teacat/noire v1.0.0
|
||||
github.com/urfave/cli/v2 v2.2.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -396,6 +396,8 @@ github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tL
|
|||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
github.com/sslhound/herr v1.4.1 h1:7EBdK2gDkT7lFve3KXC1PGJUasgeQRVYbZbI3qcpl0c=
|
||||
github.com/sslhound/herr v1.4.1/go.mod h1:3zw8Zr8bwddppECO/GycmavbbGYyT6oCm0urxmSXfR0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
|
|
|
@ -928,5 +928,10 @@
|
|||
"locale": "en",
|
||||
"key": "TAVWEBAAAAAAAJ",
|
||||
"trans": "Access denied."
|
||||
},
|
||||
{
|
||||
"locale": "en",
|
||||
"key": "TAVWEBAAAAAAAK",
|
||||
"trans": "The asset exists."
|
||||
}
|
||||
]
|
|
@ -173,8 +173,9 @@ func serverCommandAction(cliCtx *cli.Context) error {
|
|||
var assetStorage asset.Storage
|
||||
switch assetStorageConfig.Type {
|
||||
case "file":
|
||||
assetStorage = asset.FileStorage{
|
||||
Base: assetStorageConfig.FileBasePath,
|
||||
assetStorage, err = asset.NewFileStorage(assetStorageConfig.FileBasePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown asset storage type: %s", assetStorageConfig.Type)
|
||||
|
|
|
@ -733,7 +733,7 @@ func (h handler) uploadHash(ctx context.Context, file *multipart.FileHeader) (st
|
|||
}
|
||||
|
||||
fullLocation, err := h.assetStorage.Upload(context.Background(), checksum, tmpFileName)
|
||||
if err != nil {
|
||||
if err != nil && !errors.Is(err, errors.NewAssetExistsError(nil)) {
|
||||
return storage.ImageAsset{}, err
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue