Better error handling and annotation

This commit is contained in:
Alexander Neumann 2014-10-07 23:19:26 +02:00
parent cbee80fc6d
commit 9b75f2cab0
3 changed files with 46 additions and 29 deletions

View File

@ -1,5 +1,7 @@
package backend
import "errors"
type Type string
const (
@ -14,6 +16,10 @@ const (
BackendVersion = 1
)
var (
ErrAlreadyPresent = errors.New("blob is already present in backend")
)
type Server interface {
Create(Type, []byte) (ID, error)
Get(Type, ID) ([]byte, error)

View File

@ -8,6 +8,8 @@ import (
"path/filepath"
"strconv"
"strings"
"github.com/juju/arrar"
)
const (
@ -131,7 +133,7 @@ func CreateLocal(dir string) (*Local, error) {
return nil, err
}
// open repository
// open backend
return OpenLocal(dir)
}
@ -169,12 +171,23 @@ func (b *Local) dir(t Type) string {
return filepath.Join(b.p, n)
}
// Create stores new content of type t and data and returns the ID.
// Create stores new content of type t and data and returns the ID. If the blob
// is already present, returns ErrAlreadyPresent and the blob's ID.
func (b *Local) Create(t Type, data []byte) (ID, error) {
// TODO: make sure that tempfile is removed upon error
// create tempfile in repository
var err error
// check if blob is already present in backend
id := IDFromData(data)
res, err := b.Test(t, id)
if err != nil {
return nil, arrar.Annotate(err, "test for presence")
}
if res {
return id, ErrAlreadyPresent
}
// create tempfile in backend
file, err := b.tempFile()
if err != nil {
return nil, err
@ -192,7 +205,6 @@ func (b *Local) Create(t Type, data []byte) (ID, error) {
}
// return id
id := IDFromData(data)
err = b.renameFile(file, t, id)
if err != nil {
return nil, err
@ -282,7 +294,7 @@ func (b *Local) Version() uint {
return b.ver
}
// Close closes the repository
// Close closes the backend
func (b *Local) Close() error {
return nil
}

View File

@ -14,6 +14,7 @@ import (
"strconv"
"strings"
"github.com/juju/arrar"
"github.com/pkg/sftp"
)
@ -71,7 +72,7 @@ func start_client(program string, args ...string) (*SFTP, error) {
}
// OpenSFTP opens an sftp backend. When the command is started via
// exec.Command, it is expected to speak sftp on stdin/stdout. The repository
// exec.Command, it is expected to speak sftp on stdin/stdout. The backend
// is expected at the given path.
func OpenSFTP(dir string, program string, args ...string) (*SFTP, error) {
sftp, err := start_client(program, args...)
@ -117,10 +118,6 @@ func OpenSFTP(dir string, program string, args ...string) (*SFTP, error) {
return nil, fmt.Errorf("unable to convert version to integer: %v\n", err)
}
if version != BackendVersion {
return nil, fmt.Errorf("wrong version %d", version)
}
// check version
if version != BackendVersion {
return nil, fmt.Errorf("wrong version %d", version)
@ -201,7 +198,7 @@ func CreateSFTP(dir string, program string, args ...string) (*SFTP, error) {
return nil, err
}
// open repository
// open backend
return OpenSFTP(dir, program, args...)
}
@ -258,33 +255,38 @@ func (r *SFTP) dir(t Type) string {
return filepath.Join(r.p, n)
}
// Create stores new content of type t and data and returns the ID.
// Create stores new content of type t and data and returns the ID. If the blob
// is already present, returns ErrAlreadyPresent and the blob's ID.
func (r *SFTP) Create(t Type, data []byte) (ID, error) {
// TODO: make sure that tempfile is removed upon error
// create tempfile in repository
var err error
// check if blob is already present in backend
id := IDFromData(data)
if ok, _ := r.Test(t, id); ok {
return id, ErrAlreadyPresent
}
// create tempfile in backend
filename, file, err := r.tempFile()
if err != nil {
return nil, err
return nil, arrar.Annotate(err, "create tempfile")
}
// write data to tempfile
_, err = file.Write(data)
if err != nil {
return nil, err
return nil, arrar.Annotate(err, "writing data to tempfile")
}
err = file.Close()
if err != nil {
return nil, err
return nil, arrar.Annotate(err, "close tempfile")
}
// return id
id := IDFromData(data)
err = r.renameFile(filename, t, id)
if err != nil {
return nil, err
return nil, arrar.Annotate(err, "rename file")
}
return id, nil
@ -315,20 +317,17 @@ func (r *SFTP) Get(t Type, id ID) ([]byte, error) {
// Test returns true if a blob of the given type and ID exists in the backend.
func (r *SFTP) Test(t Type, id ID) (bool, error) {
// try to open file
file, err := r.c.Open(r.filename(t, id))
defer func() {
file.Close()
if file != nil {
file.Close()
}
}()
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
if err == nil {
return true, nil
}
return true, nil
return false, err
}
// Remove removes the content stored at ID.