mirror of
https://github.com/octoleo/restic.git
synced 2024-11-30 00:33:57 +00:00
backend: Add IsNotExist
This commit is contained in:
parent
6f24d038f8
commit
af9ba3be91
@ -152,6 +152,10 @@ func pruneRepository(gopts GlobalOptions, repo restic.Repository) error {
|
|||||||
|
|
||||||
err = restic.FindUsedBlobs(ctx, repo, *sn.Tree, usedBlobs, seenBlobs)
|
err = restic.FindUsedBlobs(ctx, repo, *sn.Tree, usedBlobs, seenBlobs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if repo.Backend().IsNotExist(err) {
|
||||||
|
return errors.Fatal("unable to load a tree from the repo: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +36,10 @@ type Backend interface {
|
|||||||
// arbitrary order. A goroutine is started for this, which is stopped when
|
// arbitrary order. A goroutine is started for this, which is stopped when
|
||||||
// ctx is cancelled.
|
// ctx is cancelled.
|
||||||
List(ctx context.Context, t FileType) <-chan string
|
List(ctx context.Context, t FileType) <-chan string
|
||||||
|
|
||||||
|
// IsNotExist returns true if the error was caused by a non-existing file
|
||||||
|
// in the backend.
|
||||||
|
IsNotExist(err error) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileInfo is returned by Stat() and contains information about a file in the
|
// FileInfo is returned by Stat() and contains information about a file in the
|
||||||
|
@ -151,6 +151,11 @@ func (wr *wrapReader) Close() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsNotExist returns true if the error is caused by a non-existing file.
|
||||||
|
func (be *b2Backend) IsNotExist(err error) bool {
|
||||||
|
return b2.IsNotExist(errors.Cause(err))
|
||||||
|
}
|
||||||
|
|
||||||
// Load returns the data stored in the backend for h at the given offset
|
// Load returns the data stored in the backend for h at the given offset
|
||||||
// and saves it in p. Load has the same semantics as io.ReaderAt.
|
// and saves it in p. Load has the same semantics as io.ReaderAt.
|
||||||
func (be *b2Backend) Load(ctx context.Context, h restic.Handle, length int, offset int64) (io.ReadCloser, error) {
|
func (be *b2Backend) Load(ctx context.Context, h restic.Handle, length int, offset int64) (io.ReadCloser, error) {
|
||||||
|
@ -75,6 +75,11 @@ func (b *Local) Location() string {
|
|||||||
return b.Path
|
return b.Path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsNotExist returns true if the error is caused by a non existing file.
|
||||||
|
func (b *Local) IsNotExist(err error) bool {
|
||||||
|
return os.IsNotExist(errors.Cause(err))
|
||||||
|
}
|
||||||
|
|
||||||
// Save stores data in the backend at the handle.
|
// Save stores data in the backend at the handle.
|
||||||
func (b *Local) Save(ctx context.Context, h restic.Handle, rd io.Reader) (err error) {
|
func (b *Local) Save(ctx context.Context, h restic.Handle, rd io.Reader) (err error) {
|
||||||
debug.Log("Save %v", h)
|
debug.Log("Save %v", h)
|
||||||
|
@ -19,6 +19,8 @@ type memMap map[restic.Handle][]byte
|
|||||||
// make sure that MemoryBackend implements backend.Backend
|
// make sure that MemoryBackend implements backend.Backend
|
||||||
var _ restic.Backend = &MemoryBackend{}
|
var _ restic.Backend = &MemoryBackend{}
|
||||||
|
|
||||||
|
var errNotFound = errors.New("not found")
|
||||||
|
|
||||||
// MemoryBackend is a mock backend that uses a map for storing all data in
|
// MemoryBackend is a mock backend that uses a map for storing all data in
|
||||||
// memory. This should only be used for tests.
|
// memory. This should only be used for tests.
|
||||||
type MemoryBackend struct {
|
type MemoryBackend struct {
|
||||||
@ -51,6 +53,11 @@ func (be *MemoryBackend) Test(ctx context.Context, h restic.Handle) (bool, error
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsNotExist returns true if the file does not exist.
|
||||||
|
func (be *MemoryBackend) IsNotExist(err error) bool {
|
||||||
|
return errors.Cause(err) == errNotFound
|
||||||
|
}
|
||||||
|
|
||||||
// Save adds new Data to the backend.
|
// Save adds new Data to the backend.
|
||||||
func (be *MemoryBackend) Save(ctx context.Context, h restic.Handle, rd io.Reader) error {
|
func (be *MemoryBackend) Save(ctx context.Context, h restic.Handle, rd io.Reader) error {
|
||||||
if err := h.Valid(); err != nil {
|
if err := h.Valid(); err != nil {
|
||||||
@ -101,7 +108,7 @@ func (be *MemoryBackend) Load(ctx context.Context, h restic.Handle, length int,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := be.data[h]; !ok {
|
if _, ok := be.data[h]; !ok {
|
||||||
return nil, errors.New("no such data")
|
return nil, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := be.data[h]
|
buf := be.data[h]
|
||||||
@ -134,7 +141,7 @@ func (be *MemoryBackend) Stat(ctx context.Context, h restic.Handle) (restic.File
|
|||||||
|
|
||||||
e, ok := be.data[h]
|
e, ok := be.data[h]
|
||||||
if !ok {
|
if !ok {
|
||||||
return restic.FileInfo{}, errors.New("no such data")
|
return restic.FileInfo{}, errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
return restic.FileInfo{Size: int64(len(e))}, nil
|
return restic.FileInfo{Size: int64(len(e))}, nil
|
||||||
@ -148,7 +155,7 @@ func (be *MemoryBackend) Remove(ctx context.Context, h restic.Handle) error {
|
|||||||
debug.Log("Remove %v", h)
|
debug.Log("Remove %v", h)
|
||||||
|
|
||||||
if _, ok := be.data[h]; !ok {
|
if _, ok := be.data[h]; !ok {
|
||||||
return errors.New("no such data")
|
return errNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(be.data, h)
|
delete(be.data, h)
|
||||||
|
@ -138,6 +138,23 @@ func (b *restBackend) Save(ctx context.Context, h restic.Handle, rd io.Reader) (
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrIsNotExist is returned whenever the requested file does not exist on the
|
||||||
|
// server.
|
||||||
|
type ErrIsNotExist struct {
|
||||||
|
restic.Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e ErrIsNotExist) Error() string {
|
||||||
|
return fmt.Sprintf("%v does not exist", e.Handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotExist returns true if the error was caused by a non-existing file.
|
||||||
|
func (b *restBackend) IsNotExist(err error) bool {
|
||||||
|
err = errors.Cause(err)
|
||||||
|
_, ok := err.(ErrIsNotExist)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
// Load returns a reader that yields the contents of the file at h at the
|
// Load returns a reader that yields the contents of the file at h at the
|
||||||
// given offset. If length is nonzero, only a portion of the file is
|
// given offset. If length is nonzero, only a portion of the file is
|
||||||
// returned. rd must be closed after use.
|
// returned. rd must be closed after use.
|
||||||
@ -179,6 +196,11 @@ func (b *restBackend) Load(ctx context.Context, h restic.Handle, length int, off
|
|||||||
return nil, errors.Wrap(err, "client.Do")
|
return nil, errors.Wrap(err, "client.Do")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusNotFound {
|
||||||
|
_ = resp.Body.Close()
|
||||||
|
return nil, ErrIsNotExist{h}
|
||||||
|
}
|
||||||
|
|
||||||
if resp.StatusCode != 200 && resp.StatusCode != 206 {
|
if resp.StatusCode != 200 && resp.StatusCode != 206 {
|
||||||
_ = resp.Body.Close()
|
_ = resp.Body.Close()
|
||||||
return nil, errors.Errorf("unexpected HTTP response (%v): %v", resp.StatusCode, resp.Status)
|
return nil, errors.Errorf("unexpected HTTP response (%v): %v", resp.StatusCode, resp.Status)
|
||||||
@ -205,6 +227,11 @@ func (b *restBackend) Stat(ctx context.Context, h restic.Handle) (restic.FileInf
|
|||||||
return restic.FileInfo{}, errors.Wrap(err, "Close")
|
return restic.FileInfo{}, errors.Wrap(err, "Close")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusNotFound {
|
||||||
|
_ = resp.Body.Close()
|
||||||
|
return restic.FileInfo{}, ErrIsNotExist{h}
|
||||||
|
}
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != 200 {
|
||||||
return restic.FileInfo{}, errors.Errorf("unexpected HTTP response (%v): %v", resp.StatusCode, resp.Status)
|
return restic.FileInfo{}, errors.Errorf("unexpected HTTP response (%v): %v", resp.StatusCode, resp.Status)
|
||||||
}
|
}
|
||||||
@ -248,6 +275,11 @@ func (b *restBackend) Remove(ctx context.Context, h restic.Handle) error {
|
|||||||
return errors.Wrap(err, "client.Do")
|
return errors.Wrap(err, "client.Do")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusNotFound {
|
||||||
|
_ = resp.Body.Close()
|
||||||
|
return ErrIsNotExist{h}
|
||||||
|
}
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != 200 {
|
||||||
return errors.Errorf("blob not removed, server response: %v (%v)", resp.Status, resp.StatusCode)
|
return errors.Errorf("blob not removed, server response: %v (%v)", resp.Status, resp.StatusCode)
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
// Backend implements a mock backend.
|
// Backend implements a mock backend.
|
||||||
type Backend struct {
|
type Backend struct {
|
||||||
CloseFn func() error
|
CloseFn func() error
|
||||||
|
IsNotExistFn func(err error) bool
|
||||||
SaveFn func(ctx context.Context, h restic.Handle, rd io.Reader) error
|
SaveFn func(ctx context.Context, h restic.Handle, rd io.Reader) error
|
||||||
LoadFn func(ctx context.Context, h restic.Handle, length int, offset int64) (io.ReadCloser, error)
|
LoadFn func(ctx context.Context, h restic.Handle, length int, offset int64) (io.ReadCloser, error)
|
||||||
StatFn func(ctx context.Context, h restic.Handle) (restic.FileInfo, error)
|
StatFn func(ctx context.Context, h restic.Handle) (restic.FileInfo, error)
|
||||||
@ -39,6 +40,15 @@ func (m *Backend) Location() string {
|
|||||||
return m.LocationFn()
|
return m.LocationFn()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsNotExist returns true if the error is caused by a missing file.
|
||||||
|
func (m *Backend) IsNotExist(err error) bool {
|
||||||
|
if m.IsNotExistFn == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return m.IsNotExistFn(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Save data in the backend.
|
// Save data in the backend.
|
||||||
func (m *Backend) Save(ctx context.Context, h restic.Handle, rd io.Reader) error {
|
func (m *Backend) Save(ctx context.Context, h restic.Handle, rd io.Reader) error {
|
||||||
if m.SaveFn == nil {
|
if m.SaveFn == nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user