Simply backend interface

Rename CreateBlob() method to Create(), remove old Create* methods
This commit is contained in:
Alexander Neumann 2015-02-15 17:26:08 +01:00
parent 35636a9d92
commit 72c951a6ec
6 changed files with 82 additions and 210 deletions

View file

@ -38,9 +38,7 @@ type Getter interface {
} }
type Creater interface { type Creater interface {
Create(Type, []byte) (ID, error) Create(Type) (Blob, error)
CreateFrom(Type, io.Reader) (ID, error)
CreateBlob(Type) (Blob, error)
} }
type Tester interface { type Tester interface {

View file

@ -10,8 +10,6 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"github.com/juju/arrar"
) )
const ( const (
@ -183,96 +181,6 @@ func (b *Local) dirname(t Type, id ID) string {
return filepath.Join(b.p, n) return filepath.Join(b.p, n)
} }
// 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
// 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
}
// write data to tempfile
_, err = file.Write(data)
if err != nil {
return nil, err
}
err = file.Close()
if err != nil {
return nil, err
}
// return id
err = b.renameFile(file, t, id)
if err != nil {
return nil, err
}
return id, nil
}
// CreateFrom reads content from rd and stores it as type t. Returned is the
// storage ID. If the blob is already present, returns ErrAlreadyPresent and
// the blob's ID.
func (b *Local) CreateFrom(t Type, rd io.Reader) (ID, error) {
// TODO: make sure that tempfile is removed upon error
// check hash while writing
hr := NewHashingReader(rd, newHash())
// create tempfile in backend
file, err := b.tempFile()
if err != nil {
return nil, err
}
// write data to tempfile
_, err = io.Copy(file, hr)
if err != nil {
return nil, err
}
err = file.Close()
if err != nil {
return nil, err
}
// get ID
id := ID(hr.Sum(nil))
// check for duplicate ID
res, err := b.Test(t, id)
if err != nil {
return nil, arrar.Annotate(err, "test for presence")
}
if res {
return id, ErrAlreadyPresent
}
// rename file
err = b.renameFile(file, t, id)
if err != nil {
return nil, err
}
return id, nil
}
type localBlob struct { type localBlob struct {
f *os.File f *os.File
h hash.Hash h hash.Hash
@ -325,7 +233,7 @@ func (lb *localBlob) ID() (ID, error) {
// Create creates a new blob of type t. Blob implements io.WriteCloser. Once // Create creates a new blob of type t. Blob implements io.WriteCloser. Once
// Close() has been called, ID() can be used to retrieve the ID. If the blob is // Close() has been called, ID() can be used to retrieve the ID. If the blob is
// already present, Close() returns ErrAlreadyPresent. // already present, Close() returns ErrAlreadyPresent.
func (b *Local) CreateBlob(t Type) (Blob, error) { func (b *Local) Create(t Type) (Blob, error) {
// TODO: make sure that tempfile is removed upon error // TODO: make sure that tempfile is removed upon error
// create tempfile in backend // create tempfile in backend

View file

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"flag" "flag"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"sort" "sort"
"testing" "testing"
@ -69,7 +70,7 @@ func testBackend(b backend.Backend, t *testing.T) {
// add files // add files
for _, test := range TestStrings { for _, test := range TestStrings {
// store string in backend // store string in backend
blob, err := b.CreateBlob(tpe) blob, err := b.Create(tpe)
ok(t, err) ok(t, err)
_, err = blob.Write([]byte(test.data)) _, err = blob.Write([]byte(test.data))
@ -97,24 +98,43 @@ func testBackend(b backend.Backend, t *testing.T) {
equals(t, test.data, string(buf)) equals(t, test.data, string(buf))
} }
// test stream functions with first file // test adding the first file again
test := TestStrings[0] test := TestStrings[0]
id, err := backend.ParseID(test.id) id, err := backend.ParseID(test.id)
ok(t, err) ok(t, err)
// create with reader, should return error // create blob
_, err = b.CreateFrom(tpe, bytes.NewReader([]byte(test.data))) blob, err := b.Create(tpe)
ok(t, err)
_, err = io.Copy(blob, bytes.NewReader([]byte(test.data)))
ok(t, err)
err = blob.Close()
assert(t, err == backend.ErrAlreadyPresent, assert(t, err == backend.ErrAlreadyPresent,
"expected ErrAlreadyPresent, got %v", err) "wrong error returned: expected %v, got %v",
backend.ErrAlreadyPresent, err)
id2, err := blob.ID()
ok(t, err)
assert(t, id.Equal(id2), "IDs do not match: expected %v, got %v", id, id2)
// remove and recreate // remove and recreate
err = b.Remove(tpe, id) err = b.Remove(tpe, id)
ok(t, err) ok(t, err)
id2, err := b.CreateFrom(tpe, bytes.NewReader([]byte(test.data))) // create blob
blob, err = b.Create(tpe)
ok(t, err) ok(t, err)
assert(t, id.Equal(id2),
"expected id %v, got %v", id, id2) _, err = io.Copy(blob, bytes.NewReader([]byte(test.data)))
ok(t, err)
err = blob.Close()
ok(t, err)
id2, err = blob.ID()
ok(t, err)
assert(t, id.Equal(id2), "IDs do not match: expected %v, got %v", id, id2)
// list items // list items
IDs := backend.IDs{} IDs := backend.IDs{}

View file

@ -15,7 +15,6 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/juju/arrar"
"github.com/pkg/sftp" "github.com/pkg/sftp"
) )
@ -291,96 +290,6 @@ func (r *SFTP) dirname(t Type, id ID) string {
return filepath.Join(r.p, n) return filepath.Join(r.p, n)
} }
// 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
// check if blob is already present in backend
id := IDFromData(data)
res, err := r.Test(t, id)
if err != nil {
return nil, arrar.Annotate(err, "test for presence")
}
if res {
return id, ErrAlreadyPresent
}
// create tempfile in backend
filename, file, err := r.tempFile()
if err != nil {
return nil, arrar.Annotate(err, "create tempfile")
}
// write data to tempfile
_, err = file.Write(data)
if err != nil {
return nil, arrar.Annotate(err, "writing data to tempfile")
}
err = file.Close()
if err != nil {
return nil, arrar.Annotate(err, "close tempfile")
}
// return id
err = r.renameFile(filename, t, id)
if err != nil {
return nil, arrar.Annotate(err, "rename file")
}
return id, nil
}
// CreateFrom reads content from rd and stores it as type t. Returned is the
// storage ID. If the blob is already present, returns ErrAlreadyPresent and
// the blob's ID.
func (r *SFTP) CreateFrom(t Type, rd io.Reader) (ID, error) {
// TODO: make sure that tempfile is removed upon error
// check hash while writing
hr := NewHashingReader(rd, newHash())
// create tempfile in backend
filename, file, err := r.tempFile()
if err != nil {
return nil, err
}
// write data to tempfile
_, err = io.Copy(file, hr)
if err != nil {
return nil, err
}
err = file.Close()
if err != nil {
return nil, err
}
// get ID
id := ID(hr.Sum(nil))
// check for duplicate ID
res, err := r.Test(t, id)
if err != nil {
return nil, arrar.Annotate(err, "test for presence")
}
if res {
return id, ErrAlreadyPresent
}
// rename file
err = r.renameFile(filename, t, id)
if err != nil {
return nil, err
}
return id, nil
}
type sftpBlob struct { type sftpBlob struct {
f *sftp.File f *sftp.File
name string name string
@ -434,7 +343,7 @@ func (sb *sftpBlob) ID() (ID, error) {
// Create creates a new blob of type t. Blob implements io.WriteCloser. Once // Create creates a new blob of type t. Blob implements io.WriteCloser. Once
// Close() has been called, ID() can be used to retrieve the ID. If the blob is // Close() has been called, ID() can be used to retrieve the ID. If the blob is
// already present, Close() returns ErrAlreadyPresent. // already present, Close() returns ErrAlreadyPresent.
func (r *SFTP) CreateBlob(t Type) (Blob, error) { func (r *SFTP) Create(t Type) (Blob, error) {
// TODO: make sure that tempfile is removed upon error // TODO: make sure that tempfile is removed upon error
// create tempfile in backend // create tempfile in backend

18
key.go
View file

@ -209,10 +209,26 @@ func AddKey(s Server, password string, template *Key) (*Key, error) {
} }
// store in repository and return // store in repository and return
id, err := s.Create(backend.Key, buf) blob, err := s.Create(backend.Key)
if err != nil { if err != nil {
return nil, err return nil, err
} }
_, err = blob.Write(buf)
if err != nil {
return nil, err
}
err = blob.Close()
if err != nil {
return nil, err
}
id, err := blob.ID()
if err != nil {
return nil, err
}
newkey.id = id newkey.id = id
FreeChunkBuf("key", newkey.Data) FreeChunkBuf("key", newkey.Data)

View file

@ -169,7 +169,22 @@ func (s Server) Save(t backend.Type, data []byte, id backend.ID) (Blob, error) {
ciphertext = ciphertext[:n] ciphertext = ciphertext[:n]
// save blob // save blob
sid, err := s.Create(t, ciphertext) backendBlob, err := s.Create(t)
if err != nil {
return Blob{}, err
}
_, err = backendBlob.Write(ciphertext)
if err != nil {
return Blob{}, err
}
err = backendBlob.Close()
if err != nil {
return Blob{}, err
}
sid, err := backendBlob.ID()
if err != nil { if err != nil {
return Blob{}, err return Blob{}, err
} }
@ -225,8 +240,22 @@ func (s Server) SaveFrom(t backend.Type, id backend.ID, length uint, rd io.Reade
ciphertext = ciphertext[:n] ciphertext = ciphertext[:n]
// save blob backendBlob, err := s.Create(t)
sid, err := s.Create(t, ciphertext) if err != nil {
return Blob{}, err
}
_, err = backendBlob.Write(ciphertext)
if err != nil {
return Blob{}, err
}
err = backendBlob.Close()
if err != nil {
return Blob{}, err
}
sid, err := backendBlob.ID()
if err != nil { if err != nil {
return Blob{}, err return Blob{}, err
} }
@ -322,16 +351,8 @@ func (s Server) GetReader(t backend.Type, id backend.ID) (io.ReadCloser, error)
return s.be.GetReader(t, id) return s.be.GetReader(t, id)
} }
func (s Server) Create(t backend.Type, data []byte) (backend.ID, error) { func (s Server) Create(t backend.Type) (backend.Blob, error) {
return s.be.Create(t, data) return s.be.Create(t)
}
func (s Server) CreateFrom(t backend.Type, r io.Reader) (backend.ID, error) {
return s.be.CreateFrom(t, r)
}
func (s Server) CreateBlob(t backend.Type) (backend.Blob, error) {
return s.be.CreateBlob(t)
} }
func (s Server) Test(t backend.Type, id backend.ID) (bool, error) { func (s Server) Test(t backend.Type, id backend.ID) (bool, error) {