Copy interfaces and basic types to package restic/

This commit is contained in:
Alexander Neumann 2016-08-31 19:10:10 +02:00
parent bfdd26c541
commit 82c2dafb23
19 changed files with 351 additions and 224 deletions

View File

@ -83,7 +83,7 @@ func ArchiveReader(repo *repository.Repository, p *Progress, rd io.Reader, name
Name: name,
AccessTime: time.Now(),
ModTime: time.Now(),
Type: "file",
FileType: "file",
Mode: 0644,
Size: fileSize,
UID: sn.UID,

View File

@ -307,7 +307,7 @@ func (arch *Archiver) fileWorker(wg *sync.WaitGroup, p *Progress, done <-chan st
}
// otherwise read file normally
if node.Type == "file" && len(node.Content) == 0 {
if node.FileType == "file" && len(node.Content) == 0 {
debug.Log("Archiver.fileWorker", " read and save %v, content: %v", e.Path(), node.Content)
err = arch.SaveFile(p, node)
if err != nil {
@ -374,7 +374,7 @@ func (arch *Archiver) dirWorker(wg *sync.WaitGroup, p *Progress, done <-chan str
node := res.(*Node)
tree.Insert(node)
if node.Type == "dir" {
if node.FileType == "dir" {
debug.Log("Archiver.dirWorker", "got tree node for %s: %v", node.path, node.Subtree)
if node.Subtree.IsNull() {

View File

@ -12,6 +12,7 @@ import (
"restic"
"restic/backend"
"restic/mock"
"restic/pack"
"restic/repository"
)
@ -36,30 +37,30 @@ func randomID() backend.ID {
}
// forgetfulBackend returns a backend that forgets everything.
func forgetfulBackend() backend.Backend {
be := &backend.MockBackend{}
func forgetfulBackend() restic.Backend {
be := &mock.Backend{}
be.TestFn = func(t backend.Type, name string) (bool, error) {
be.TestFn = func(t restic.FileType, name string) (bool, error) {
return false, nil
}
be.LoadFn = func(h backend.Handle, p []byte, off int64) (int, error) {
be.LoadFn = func(h restic.Handle, p []byte, off int64) (int, error) {
return 0, errors.New("not found")
}
be.SaveFn = func(h backend.Handle, p []byte) error {
be.SaveFn = func(h restic.Handle, p []byte) error {
return nil
}
be.StatFn = func(h backend.Handle) (backend.BlobInfo, error) {
return backend.BlobInfo{}, errors.New("not found")
be.StatFn = func(h restic.Handle) (restic.BlobInfo, error) {
return restic.BlobInfo{}, errors.New("not found")
}
be.RemoveFn = func(t backend.Type, name string) error {
be.RemoveFn = func(t restic.FileType, name string) error {
return nil
}
be.ListFn = func(t backend.Type, done <-chan struct{}) <-chan string {
be.ListFn = func(t restic.FileType, done <-chan struct{}) <-chan string {
ch := make(chan string)
close(ch)
return ch

55
src/restic/backend.go Normal file
View File

@ -0,0 +1,55 @@
package restic
// FileType is the type of a file in the backend.
type FileType string
// These are the different data types a backend can store.
const (
DataFile FileType = "data"
KeyFile = "key"
LockFile = "lock"
SnapshotFile = "snapshot"
IndexFile = "index"
ConfigFile = "config"
)
// Backend is used to store and access data.
type Backend interface {
// Location returns a string that describes the type and location of the
// repository.
Location() string
// Test a boolean value whether a Blob with the name and type exists.
Test(t FileType, name string) (bool, error)
// Remove removes a Blob with type t and name.
Remove(t FileType, name string) error
// Close the backend
Close() error
// 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, except
// that a negative offset is also allowed. In this case it references a
// position relative to the end of the file (similar to Seek()).
Load(h Handle, p []byte, off int64) (int, error)
// Save stores the data in the backend under the given handle.
Save(h Handle, p []byte) error
// Stat returns information about the blob identified by h.
Stat(h Handle) (BlobInfo, error)
// List returns a channel that yields all names of blobs of type t in an
// arbitrary order. A goroutine is started for this. If the channel done is
// closed, sending stops.
List(t FileType, done <-chan struct{}) <-chan string
// Delete the complete repository.
Delete() error
}
// BlobInfo is returned by Stat() and contains information about a stored blob.
type BlobInfo struct {
Size int64
}

View File

@ -17,13 +17,14 @@ type entry struct {
type memMap map[entry][]byte
// make sure that MemoryBackend implements backend.Backend
var _ backend.Backend = &MemoryBackend{}
// MemoryBackend is a mock backend that uses a map for storing all data in
// memory. This should only be used for tests.
type MemoryBackend struct {
data memMap
m sync.Mutex
backend.MockBackend
}
// New returns a new backend that saves all data in a map in memory.
@ -32,60 +33,13 @@ func New() *MemoryBackend {
data: make(memMap),
}
be.MockBackend.TestFn = func(t backend.Type, name string) (bool, error) {
return memTest(be, t, name)
}
be.MockBackend.LoadFn = func(h backend.Handle, p []byte, off int64) (int, error) {
return memLoad(be, h, p, off)
}
be.MockBackend.SaveFn = func(h backend.Handle, p []byte) error {
return memSave(be, h, p)
}
be.MockBackend.StatFn = func(h backend.Handle) (backend.BlobInfo, error) {
return memStat(be, h)
}
be.MockBackend.RemoveFn = func(t backend.Type, name string) error {
return memRemove(be, t, name)
}
be.MockBackend.ListFn = func(t backend.Type, done <-chan struct{}) <-chan string {
return memList(be, t, done)
}
be.MockBackend.DeleteFn = func() error {
be.m.Lock()
defer be.m.Unlock()
be.data = make(memMap)
return nil
}
be.MockBackend.LocationFn = func() string {
return "Memory Backend"
}
debug.Log("MemoryBackend.New", "created new memory backend")
return be
}
func (be *MemoryBackend) insert(t backend.Type, name string, data []byte) error {
be.m.Lock()
defer be.m.Unlock()
if _, ok := be.data[entry{t, name}]; ok {
return errors.New("already present")
}
be.data[entry{t, name}] = data
return nil
}
func memTest(be *MemoryBackend, t backend.Type, name string) (bool, error) {
// Test returns whether a file exists.
func (be *MemoryBackend) Test(t backend.Type, name string) (bool, error) {
be.m.Lock()
defer be.m.Unlock()
@ -98,7 +52,8 @@ func memTest(be *MemoryBackend, t backend.Type, name string) (bool, error) {
return false, nil
}
func memLoad(be *MemoryBackend, h backend.Handle, p []byte, off int64) (int, error) {
// Load reads data from the backend.
func (be *MemoryBackend) Load(h backend.Handle, p []byte, off int64) (int, error) {
if err := h.Valid(); err != nil {
return 0, err
}
@ -137,7 +92,8 @@ func memLoad(be *MemoryBackend, h backend.Handle, p []byte, off int64) (int, err
return n, nil
}
func memSave(be *MemoryBackend, h backend.Handle, p []byte) error {
// Save adds new Data to the backend.
func (be *MemoryBackend) Save(h backend.Handle, p []byte) error {
if err := h.Valid(); err != nil {
return err
}
@ -161,7 +117,8 @@ func memSave(be *MemoryBackend, h backend.Handle, p []byte) error {
return nil
}
func memStat(be *MemoryBackend, h backend.Handle) (backend.BlobInfo, error) {
// Stat returns information about a file in the backend.
func (be *MemoryBackend) Stat(h backend.Handle) (backend.BlobInfo, error) {
be.m.Lock()
defer be.m.Unlock()
@ -183,7 +140,8 @@ func memStat(be *MemoryBackend, h backend.Handle) (backend.BlobInfo, error) {
return backend.BlobInfo{Size: int64(len(e))}, nil
}
func memRemove(be *MemoryBackend, t backend.Type, name string) error {
// Remove deletes a file from the backend.
func (be *MemoryBackend) Remove(t backend.Type, name string) error {
be.m.Lock()
defer be.m.Unlock()
@ -198,7 +156,8 @@ func memRemove(be *MemoryBackend, t backend.Type, name string) error {
return nil
}
func memList(be *MemoryBackend, t backend.Type, done <-chan struct{}) <-chan string {
// List returns a channel which yields entries from the backend.
func (be *MemoryBackend) List(t backend.Type, done <-chan struct{}) <-chan string {
be.m.Lock()
defer be.m.Unlock()
@ -227,3 +186,22 @@ func memList(be *MemoryBackend, t backend.Type, done <-chan struct{}) <-chan str
return ch
}
// Location returns the location of the backend (RAM).
func (be *MemoryBackend) Location() string {
return "RAM"
}
// Delete removes all data in the backend.
func (be *MemoryBackend) Delete() error {
be.m.Lock()
defer be.m.Unlock()
be.data = make(memMap)
return nil
}
// Close closes the backend.
func (be *MemoryBackend) Close() error {
return nil
}

View File

@ -1,103 +0,0 @@
package backend
import "github.com/pkg/errors"
// MockBackend implements a backend whose functions can be specified. This
// should only be used for tests.
type MockBackend struct {
CloseFn func() error
LoadFn func(h Handle, p []byte, off int64) (int, error)
SaveFn func(h Handle, p []byte) error
StatFn func(h Handle) (BlobInfo, error)
ListFn func(Type, <-chan struct{}) <-chan string
RemoveFn func(Type, string) error
TestFn func(Type, string) (bool, error)
DeleteFn func() error
LocationFn func() string
}
// Close the backend.
func (m *MockBackend) Close() error {
if m.CloseFn == nil {
return nil
}
return m.CloseFn()
}
// Location returns a location string.
func (m *MockBackend) Location() string {
if m.LocationFn == nil {
return ""
}
return m.LocationFn()
}
// Load loads data from the backend.
func (m *MockBackend) Load(h Handle, p []byte, off int64) (int, error) {
if m.LoadFn == nil {
return 0, errors.New("not implemented")
}
return m.LoadFn(h, p, off)
}
// Save data in the backend.
func (m *MockBackend) Save(h Handle, p []byte) error {
if m.SaveFn == nil {
return errors.New("not implemented")
}
return m.SaveFn(h, p)
}
// Stat an object in the backend.
func (m *MockBackend) Stat(h Handle) (BlobInfo, error) {
if m.StatFn == nil {
return BlobInfo{}, errors.New("not implemented")
}
return m.StatFn(h)
}
// List items of type t.
func (m *MockBackend) List(t Type, done <-chan struct{}) <-chan string {
if m.ListFn == nil {
ch := make(chan string)
close(ch)
return ch
}
return m.ListFn(t, done)
}
// Remove data from the backend.
func (m *MockBackend) Remove(t Type, name string) error {
if m.RemoveFn == nil {
return errors.New("not implemented")
}
return m.RemoveFn(t, name)
}
// Test for the existence of a specific item.
func (m *MockBackend) Test(t Type, name string) (bool, error) {
if m.TestFn == nil {
return false, errors.New("not implemented")
}
return m.TestFn(t, name)
}
// Delete all data.
func (m *MockBackend) Delete() error {
if m.DeleteFn == nil {
return errors.New("not implemented")
}
return m.DeleteFn()
}
// Make sure that MockBackend implements the backend interface.
var _ Backend = &MockBackend{}

View File

@ -581,7 +581,7 @@ func (c *Checker) checkTree(id backend.ID, tree *restic.Tree) (errs []error) {
var blobs []backend.ID
for _, node := range tree.Nodes {
switch node.Type {
switch node.FileType {
case "file":
if node.Content == nil {
errs = append(errs, Error{TreeID: id, Err: errors.Errorf("file %q has nil blob list", node.Name)})
@ -609,7 +609,7 @@ func (c *Checker) checkTree(id backend.ID, tree *restic.Tree) (errs []error) {
// nothing to check
default:
errs = append(errs, Error{TreeID: id, Err: errors.Errorf("node %q with invalid type %q", node.Name, node.Type)})
errs = append(errs, Error{TreeID: id, Err: errors.Errorf("node %q with invalid type %q", node.Name, node.FileType)})
}
if node.Name == "" {

View File

@ -18,7 +18,7 @@ func FindUsedBlobs(repo *repository.Repository, treeID backend.ID, blobs pack.Bl
}
for _, node := range tree.Nodes {
switch node.Type {
switch node.FileType {
case "file":
for _, blob := range node.Content {
blobs.Insert(pack.Handle{ID: blob, Type: pack.Data})

View File

@ -51,7 +51,7 @@ func newDir(repo *repository.Repository, node *restic.Node, ownerIsRoot bool) (*
// replaceSpecialNodes replaces nodes with name "." and "/" by their contents.
// Otherwise, the node is returned.
func replaceSpecialNodes(repo *repository.Repository, node *restic.Node) ([]*restic.Node, error) {
if node.Type != "dir" || node.Subtree == nil {
if node.FileType != "dir" || node.Subtree == nil {
return []*restic.Node{node}, nil
}
@ -124,7 +124,7 @@ func (d *dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {
for _, node := range d.items {
var typ fuse.DirentType
switch node.Type {
switch node.FileType {
case "dir":
typ = fuse.DT_Dir
case "file":
@ -150,7 +150,7 @@ func (d *dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
debug.Log("dir.Lookup", " Lookup(%v) -> not found", name)
return nil, fuse.ENOENT
}
switch node.Type {
switch node.FileType {
case "dir":
return newDir(d.repo, node, d.ownerIsRoot)
case "file":
@ -158,7 +158,7 @@ func (d *dir) Lookup(ctx context.Context, name string) (fs.Node, error) {
case "symlink":
return newLink(d.repo, node, d.ownerIsRoot)
default:
debug.Log("dir.Lookup", " node %v has unknown type %v", name, node.Type)
debug.Log("dir.Lookup", " node %v has unknown type %v", name, node.FileType)
return nil, fuse.ENOENT
}
}

49
src/restic/handle.go Normal file
View File

@ -0,0 +1,49 @@
package restic
import (
"fmt"
"github.com/pkg/errors"
)
// Handle is used to store and access data in a backend.
type Handle struct {
FileType FileType
Name string
}
func (h Handle) String() string {
name := h.Name
if len(name) > 10 {
name = name[:10]
}
return fmt.Sprintf("<%s/%s>", h.FileType, name)
}
// Valid returns an error if h is not valid.
func (h Handle) Valid() error {
if h.FileType == "" {
return errors.New("type is empty")
}
switch h.FileType {
case DataFile:
case KeyFile:
case LockFile:
case SnapshotFile:
case IndexFile:
case ConfigFile:
default:
return errors.Errorf("invalid Type %q", h.FileType)
}
if h.FileType == ConfigFile {
return nil
}
if h.Name == "" {
return errors.New("invalid Name")
}
return nil
}

28
src/restic/handle_test.go Normal file
View File

@ -0,0 +1,28 @@
package restic
import "testing"
var handleTests = []struct {
h Handle
valid bool
}{
{Handle{Name: "foo"}, false},
{Handle{FileType: "foobar"}, false},
{Handle{FileType: ConfigFile, Name: ""}, true},
{Handle{FileType: DataFile, Name: ""}, false},
{Handle{FileType: "", Name: "x"}, false},
{Handle{FileType: LockFile, Name: "010203040506"}, true},
}
func TestHandleValid(t *testing.T) {
for i, test := range handleTests {
err := test.h.Valid()
if err != nil && test.valid {
t.Errorf("test %v failed: error returned for valid handle: %v", i, err)
}
if !test.valid && err == nil {
t.Errorf("test %v failed: expected error for invalid handle not found", i)
}
}
}

106
src/restic/mock/backend.go Normal file
View File

@ -0,0 +1,106 @@
package mock
import (
"restic"
"github.com/pkg/errors"
)
// Backend implements a mock backend.
type Backend struct {
CloseFn func() error
LoadFn func(h restic.Handle, p []byte, off int64) (int, error)
SaveFn func(h restic.Handle, p []byte) error
StatFn func(h restic.Handle) (restic.BlobInfo, error)
ListFn func(restic.FileType, <-chan struct{}) <-chan string
RemoveFn func(restic.FileType, string) error
TestFn func(restic.FileType, string) (bool, error)
DeleteFn func() error
LocationFn func() string
}
// Close the backend.
func (m *Backend) Close() error {
if m.CloseFn == nil {
return nil
}
return m.CloseFn()
}
// Location returns a location string.
func (m *Backend) Location() string {
if m.LocationFn == nil {
return ""
}
return m.LocationFn()
}
// Load loads data from the backend.
func (m *Backend) Load(h restic.Handle, p []byte, off int64) (int, error) {
if m.LoadFn == nil {
return 0, errors.New("not implemented")
}
return m.LoadFn(h, p, off)
}
// Save data in the backend.
func (m *Backend) Save(h restic.Handle, p []byte) error {
if m.SaveFn == nil {
return errors.New("not implemented")
}
return m.SaveFn(h, p)
}
// Stat an object in the backend.
func (m *Backend) Stat(h restic.Handle) (restic.BlobInfo, error) {
if m.StatFn == nil {
return restic.BlobInfo{}, errors.New("not implemented")
}
return m.StatFn(h)
}
// List items of type t.
func (m *Backend) List(t restic.FileType, done <-chan struct{}) <-chan string {
if m.ListFn == nil {
ch := make(chan string)
close(ch)
return ch
}
return m.ListFn(t, done)
}
// Remove data from the backend.
func (m *Backend) Remove(t restic.FileType, name string) error {
if m.RemoveFn == nil {
return errors.New("not implemented")
}
return m.RemoveFn(t, name)
}
// Test for the existence of a specific item.
func (m *Backend) Test(t restic.FileType, name string) (bool, error) {
if m.TestFn == nil {
return false, errors.New("not implemented")
}
return m.TestFn(t, name)
}
// Delete all data.
func (m *Backend) Delete() error {
if m.DeleteFn == nil {
return errors.New("not implemented")
}
return m.DeleteFn()
}
// Make sure that Backend implements the backend interface.
var _ restic.Backend = &Backend{}

View File

@ -24,7 +24,7 @@ import (
// Node is a file, directory or other item in a backup.
type Node struct {
Name string `json:"name"`
Type string `json:"type"`
FileType string `json:"type"`
Mode os.FileMode `json:"mode,omitempty"`
ModTime time.Time `json:"mtime,omitempty"`
AccessTime time.Time `json:"atime,omitempty"`
@ -51,7 +51,7 @@ type Node struct {
}
func (node Node) String() string {
switch node.Type {
switch node.FileType {
case "file":
return fmt.Sprintf("%s %5d %5d %6d %s %s",
node.Mode, node.UID, node.GID, node.Size, node.ModTime, node.Name)
@ -60,7 +60,7 @@ func (node Node) String() string {
node.Mode|os.ModeDir, node.UID, node.GID, node.Size, node.ModTime, node.Name)
}
return fmt.Sprintf("<Node(%s) %s>", node.Type, node.Name)
return fmt.Sprintf("<Node(%s) %s>", node.FileType, node.Name)
}
func (node Node) Tree() *Tree {
@ -77,8 +77,8 @@ func NodeFromFileInfo(path string, fi os.FileInfo) (*Node, error) {
ModTime: fi.ModTime(),
}
node.Type = nodeTypeFromFileInfo(fi)
if node.Type == "file" {
node.FileType = nodeTypeFromFileInfo(fi)
if node.FileType == "file" {
node.Size = uint64(fi.Size())
}
@ -111,7 +111,7 @@ func nodeTypeFromFileInfo(fi os.FileInfo) string {
func (node *Node) CreateAt(path string, repo *repository.Repository) error {
debug.Log("Node.CreateAt", "create node %v at %v", node.Name, path)
switch node.Type {
switch node.FileType {
case "dir":
if err := node.createDirAt(path); err != nil {
return err
@ -139,7 +139,7 @@ func (node *Node) CreateAt(path string, repo *repository.Repository) error {
case "socket":
return nil
default:
return errors.Errorf("filetype %q not implemented!\n", node.Type)
return errors.Errorf("filetype %q not implemented!\n", node.FileType)
}
err := node.restoreMetadata(path)
@ -158,14 +158,14 @@ func (node Node) restoreMetadata(path string) error {
return errors.Wrap(err, "Lchown")
}
if node.Type != "symlink" {
if node.FileType != "symlink" {
err = fs.Chmod(path, node.Mode)
if err != nil {
return errors.Wrap(err, "Chmod")
}
}
if node.Type != "dir" {
if node.FileType != "dir" {
err = node.RestoreTimestamps(path)
if err != nil {
debug.Log("Node.restoreMetadata", "error restoring timestamps for dir %v: %v", path, err)
@ -182,7 +182,7 @@ func (node Node) RestoreTimestamps(path string) error {
syscall.NsecToTimespec(node.ModTime.UnixNano()),
}
if node.Type == "symlink" {
if node.FileType == "symlink" {
return node.restoreSymlinkTimestamps(path, utimes)
}
@ -287,7 +287,7 @@ func (node Node) Equals(other Node) bool {
if node.Name != other.Name {
return false
}
if node.Type != other.Type {
if node.FileType != other.FileType {
return false
}
if node.Mode != other.Mode {
@ -375,13 +375,13 @@ func (node Node) sameContent(other Node) bool {
}
func (node *Node) isNewer(path string, fi os.FileInfo) bool {
if node.Type != "file" {
if node.FileType != "file" {
debug.Log("node.isNewer", "node %v is newer: not file", path)
return true
}
tpe := nodeTypeFromFileInfo(fi)
if node.Name != fi.Name() || node.Type != tpe {
if node.Name != fi.Name() || node.FileType != tpe {
debug.Log("node.isNewer", "node %v is newer: name or type changed", path)
return true
}
@ -469,7 +469,7 @@ func (node *Node) fillExtra(path string, fi os.FileInfo) error {
return err
}
switch node.Type {
switch node.FileType {
case "file":
node.Size = uint64(stat.size())
node.Links = uint64(stat.nlink())
@ -484,7 +484,7 @@ func (node *Node) fillExtra(path string, fi os.FileInfo) error {
case "fifo":
case "socket":
default:
err = errors.Errorf("invalid node type %q", node.Type)
err = errors.Errorf("invalid node type %q", node.FileType)
}
return err

View File

@ -74,7 +74,7 @@ func parseTime(s string) time.Time {
var nodeTests = []restic.Node{
restic.Node{
Name: "testFile",
Type: "file",
FileType: "file",
Content: []backend.ID{},
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@ -85,7 +85,7 @@ var nodeTests = []restic.Node{
},
restic.Node{
Name: "testSuidFile",
Type: "file",
FileType: "file",
Content: []backend.ID{},
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@ -96,7 +96,7 @@ var nodeTests = []restic.Node{
},
restic.Node{
Name: "testSuidFile2",
Type: "file",
FileType: "file",
Content: []backend.ID{},
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@ -107,7 +107,7 @@ var nodeTests = []restic.Node{
},
restic.Node{
Name: "testSticky",
Type: "file",
FileType: "file",
Content: []backend.ID{},
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@ -118,7 +118,7 @@ var nodeTests = []restic.Node{
},
restic.Node{
Name: "testDir",
Type: "dir",
FileType: "dir",
Subtree: nil,
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@ -129,7 +129,7 @@ var nodeTests = []restic.Node{
},
restic.Node{
Name: "testSymlink",
Type: "symlink",
FileType: "symlink",
LinkTarget: "invalid",
UID: uint32(os.Getuid()),
GID: uint32(os.Getgid()),
@ -156,10 +156,10 @@ func TestNodeRestoreAt(t *testing.T) {
nodePath := filepath.Join(tempdir, test.Name)
OK(t, test.CreateAt(nodePath, nil))
if test.Type == "symlink" && runtime.GOOS == "windows" {
if test.FileType == "symlink" && runtime.GOOS == "windows" {
continue
}
if test.Type == "dir" {
if test.FileType == "dir" {
OK(t, test.RestoreTimestamps(nodePath))
}
@ -170,25 +170,25 @@ func TestNodeRestoreAt(t *testing.T) {
OK(t, err)
Assert(t, test.Name == n2.Name,
"%v: name doesn't match (%v != %v)", test.Type, test.Name, n2.Name)
Assert(t, test.Type == n2.Type,
"%v: type doesn't match (%v != %v)", test.Type, test.Type, n2.Type)
"%v: name doesn't match (%v != %v)", test.FileType, test.Name, n2.Name)
Assert(t, test.FileType == n2.FileType,
"%v: type doesn't match (%v != %v)", test.FileType, test.FileType, n2.FileType)
Assert(t, test.Size == n2.Size,
"%v: size doesn't match (%v != %v)", test.Size, test.Size, n2.Size)
if runtime.GOOS != "windows" {
Assert(t, test.UID == n2.UID,
"%v: UID doesn't match (%v != %v)", test.Type, test.UID, n2.UID)
"%v: UID doesn't match (%v != %v)", test.FileType, test.UID, n2.UID)
Assert(t, test.GID == n2.GID,
"%v: GID doesn't match (%v != %v)", test.Type, test.GID, n2.GID)
if test.Type != "symlink" {
"%v: GID doesn't match (%v != %v)", test.FileType, test.GID, n2.GID)
if test.FileType != "symlink" {
Assert(t, test.Mode == n2.Mode,
"%v: mode doesn't match (0%o != 0%o)", test.Type, test.Mode, n2.Mode)
"%v: mode doesn't match (0%o != 0%o)", test.FileType, test.Mode, n2.Mode)
}
}
AssertFsTimeEqual(t, "AccessTime", test.Type, test.AccessTime, n2.AccessTime)
AssertFsTimeEqual(t, "ModTime", test.Type, test.ModTime, n2.ModTime)
AssertFsTimeEqual(t, "AccessTime", test.FileType, test.AccessTime, n2.AccessTime)
AssertFsTimeEqual(t, "ModTime", test.FileType, test.ModTime, n2.ModTime)
}
}

13
src/restic/repository.go Normal file
View File

@ -0,0 +1,13 @@
package restic
import "restic/repository"
// Repository stores data in a backend. It provides high-level functions and
// transparently encrypts/decrypts data.
type Repository interface {
// Backend returns the backend used by the repository
Backend() Backend
SetIndex(*repository.MasterIndex)
}

View File

@ -58,7 +58,7 @@ func (res *Restorer) restoreTo(dst string, dir string, treeID backend.ID) error
}
}
if node.Type == "dir" {
if node.FileType == "dir" {
if node.Subtree == nil {
return errors.Errorf("Dir without subtree in tree %v", treeID.Str())
}

View File

@ -110,10 +110,10 @@ func (fs fakeFileSystem) saveTree(seed int64, depth int) backend.ID {
id := fs.saveTree(treeSeed, depth-1)
node := &Node{
Name: fmt.Sprintf("dir-%v", treeSeed),
Type: "dir",
Mode: 0755,
Subtree: &id,
Name: fmt.Sprintf("dir-%v", treeSeed),
FileType: "dir",
Mode: 0755,
Subtree: &id,
}
tree.Nodes = append(tree.Nodes, node)
@ -124,10 +124,10 @@ func (fs fakeFileSystem) saveTree(seed int64, depth int) backend.ID {
fileSize := (maxFileSize / maxSeed) * fileSeed
node := &Node{
Name: fmt.Sprintf("file-%v", fileSeed),
Type: "file",
Mode: 0644,
Size: uint64(fileSize),
Name: fmt.Sprintf("file-%v", fileSeed),
FileType: "file",
Mode: 0644,
Size: uint64(fileSize),
}
node.Content = fs.saveFile(fakeFile(fs.t, fileSeed, fileSize))
@ -195,11 +195,11 @@ func TestCreateSnapshot(t testing.TB, repo *repository.Repository, at time.Time,
}
// TestResetRepository removes all packs and indexes from the repository.
func TestResetRepository(t testing.TB, repo *repository.Repository) {
func TestResetRepository(t testing.TB, repo Repository) {
done := make(chan struct{})
defer close(done)
for _, tpe := range []backend.Type{backend.Snapshot, backend.Index, backend.Data} {
for _, tpe := range []FileType{SnapshotFile, IndexFile, DataFile} {
for id := range repo.Backend().List(tpe, done) {
err := repo.Backend().Remove(tpe, id)
if err != nil {

View File

@ -97,7 +97,7 @@ func (t Tree) Find(name string) (*Node, error) {
// Subtrees returns a slice of all subtree IDs of the tree.
func (t Tree) Subtrees() (trees backend.IDs) {
for _, node := range t.Nodes {
if node.Type == "dir" && node.Subtree != nil {
if node.FileType == "dir" && node.Subtree != nil {
trees = append(trees, *node.Subtree)
}
}

View File

@ -73,7 +73,7 @@ func (tw *TreeWalker) walk(path string, tree *Tree, done chan struct{}) {
// load all subtrees in parallel
results := make([]<-chan loadTreeResult, len(tree.Nodes))
for i, node := range tree.Nodes {
if node.Type == "dir" {
if node.FileType == "dir" {
resCh := make(chan loadTreeResult, 1)
tw.ch <- loadTreeJob{
id: *node.Subtree,
@ -88,7 +88,7 @@ func (tw *TreeWalker) walk(path string, tree *Tree, done chan struct{}) {
p := filepath.Join(path, node.Name)
var job WalkTreeJob
if node.Type == "dir" {
if node.FileType == "dir" {
if results[i] == nil {
panic("result chan should not be nil")
}