Add layout name parser

This commit is contained in:
Alexander Neumann 2017-04-02 17:57:28 +02:00
parent c6b8ffbb61
commit 50dfa64a54
4 changed files with 106 additions and 12 deletions

View file

@ -108,8 +108,13 @@ func hasSubdirBackendFile(fs Filesystem, dir string) (bool, error) {
}
// DetectLayout tries to find out which layout is used in a local (or sftp)
// filesystem at the given path.
// filesystem at the given path. If repo is nil, an instance of LocalFilesystem
// is used.
func DetectLayout(repo Filesystem, dir string) (Layout, error) {
if repo == nil {
repo = &LocalFilesystem{}
}
// key file in the "keys" dir (DefaultLayout or CloudLayout)
foundKeysFile, err := hasBackendFile(repo, repo.Join(dir, defaultLayoutPaths[restic.KeyFile]))
if err != nil {
@ -148,3 +153,36 @@ func DetectLayout(repo Filesystem, dir string) (Layout, error) {
return nil, errors.New("auto-detecting the filesystem layout failed")
}
// ParseLayout parses the config string and returns a Layout. When layout is
// the empty string, DetectLayout is used. If repo is nil, an instance of LocalFilesystem
// is used.
func ParseLayout(repo Filesystem, layout, path string) (l Layout, err error) {
if repo == nil {
repo = &LocalFilesystem{}
}
switch layout {
case "default":
l = &DefaultLayout{
Path: path,
Join: repo.Join,
}
case "cloud":
l = &CloudLayout{
Path: path,
Join: repo.Join,
}
case "s3":
l = &S3Layout{
Path: path,
Join: repo.Join,
}
case "":
return DetectLayout(repo, path)
default:
return nil, errors.Errorf("unknown backend layout string %q, may be one of default/cloud/s3", layout)
}
return l, nil
}

View file

@ -229,10 +229,49 @@ func TestDetectLayout(t *testing.T) {
var fs = &LocalFilesystem{}
for _, test := range tests {
t.Run(test.filename, func(t *testing.T) {
SetupTarTestFixture(t, path, filepath.Join("testdata", test.filename))
for _, fs := range []Filesystem{fs, nil} {
t.Run(fmt.Sprintf("%v/fs-%T", test.filename, fs), func(t *testing.T) {
SetupTarTestFixture(t, path, filepath.Join("testdata", test.filename))
layout, err := DetectLayout(fs, filepath.Join(path, "repo"))
layout, err := DetectLayout(fs, filepath.Join(path, "repo"))
if err != nil {
t.Fatal(err)
}
if layout == nil {
t.Fatal("wanted some layout, but detect returned nil")
}
layoutName := fmt.Sprintf("%T", layout)
if layoutName != test.want {
t.Fatalf("want layout %v, got %v", test.want, layoutName)
}
RemoveAll(t, filepath.Join(path, "repo"))
})
}
}
}
func TestParseLayout(t *testing.T) {
path, cleanup := TempDir(t)
defer cleanup()
var tests = []struct {
layoutName string
want string
}{
{"default", "*backend.DefaultLayout"},
{"cloud", "*backend.CloudLayout"},
{"s3", "*backend.S3Layout"},
{"", "*backend.CloudLayout"},
}
SetupTarTestFixture(t, path, filepath.Join("testdata", "repo-layout-cloud.tar.gz"))
for _, test := range tests {
t.Run(test.layoutName, func(t *testing.T) {
layout, err := ParseLayout(nil, test.layoutName, filepath.Join(path, "repo"))
if err != nil {
t.Fatal(err)
}
@ -245,8 +284,24 @@ func TestDetectLayout(t *testing.T) {
if layoutName != test.want {
t.Fatalf("want layout %v, got %v", test.want, layoutName)
}
RemoveAll(t, filepath.Join(path, "repo"))
})
}
}
func TestParseLayoutInvalid(t *testing.T) {
path, cleanup := TempDir(t)
defer cleanup()
var invalidNames = []string{
"foo", "bar", "local",
}
for _, name := range invalidNames {
t.Run(name, func(t *testing.T) {
layout, err := ParseLayout(nil, name, path)
if err == nil {
t.Fatalf("expected error not found for layout name %v, layout is %v", name, layout)
}
})
}
}

View file

@ -8,7 +8,8 @@ import (
// Config holds all information needed to open a local repository.
type Config struct {
Path string
Path string
Layout string
}
// ParseConfig parses a local backend config.

View file

@ -24,13 +24,13 @@ var _ restic.Backend = &Local{}
// Open opens the local backend as specified by config.
func Open(cfg Config) (*Local, error) {
be := &Local{Config: cfg}
be.Layout = &backend.DefaultLayout{
Path: cfg.Path,
Join: filepath.Join,
l, err := backend.ParseLayout(nil, cfg.Layout, cfg.Path)
if err != nil {
return nil, err
}
be := &Local{Config: cfg, Layout: l}
// test if all necessary dirs are there
for _, d := range be.Paths() {
if _, err := fs.Stat(d); err != nil {