diff --git a/src/restic/backend/layout.go b/src/restic/backend/layout.go index a6087c502..23685a470 100644 --- a/src/restic/backend/layout.go +++ b/src/restic/backend/layout.go @@ -108,6 +108,10 @@ func hasSubdirBackendFile(fs Filesystem, dir string) (bool, error) { return false, nil } +// ErrLayoutDetectionFailed is returned by DetectLayout() when the layout +// cannot be detected automatically. +var ErrLayoutDetectionFailed = errors.New("auto-detecting the filesystem layout failed") + // DetectLayout tries to find out which layout is used in a local (or sftp) // filesystem at the given path. If repo is nil, an instance of LocalFilesystem // is used. @@ -164,12 +168,12 @@ func DetectLayout(repo Filesystem, dir string) (Layout, error) { }, nil } - return nil, errors.New("auto-detecting the filesystem layout failed") + return nil, ErrLayoutDetectionFailed } // ParseLayout parses the config string and returns a Layout. When layout is -// the empty string, DetectLayout is used. -func ParseLayout(repo Filesystem, layout, path string) (l Layout, err error) { +// the empty string, DetectLayout is used. If that fails, defaultLayout is used. +func ParseLayout(repo Filesystem, layout, defaultLayout, path string) (l Layout, err error) { debug.Log("parse layout string %q for backend at %v", layout, path) switch layout { case "default": @@ -188,7 +192,12 @@ func ParseLayout(repo Filesystem, layout, path string) (l Layout, err error) { Join: repo.Join, } case "": - return DetectLayout(repo, path) + l, err = DetectLayout(repo, path) + + // use the default layout if auto detection failed + if errors.Cause(err) == ErrLayoutDetectionFailed && defaultLayout != "" { + return ParseLayout(repo, defaultLayout, "", path) + } default: return nil, errors.Errorf("unknown backend layout string %q, may be one of default/cloud/s3", layout) } diff --git a/src/restic/backend/layout_test.go b/src/restic/backend/layout_test.go index e336f8178..dc1c231b9 100644 --- a/src/restic/backend/layout_test.go +++ b/src/restic/backend/layout_test.go @@ -258,20 +258,21 @@ func TestParseLayout(t *testing.T) { defer cleanup() var tests = []struct { - layoutName string - want string + layoutName string + defaultLayoutName string + want string }{ - {"default", "*backend.DefaultLayout"}, - {"cloud", "*backend.CloudLayout"}, - {"s3", "*backend.S3Layout"}, - {"", "*backend.CloudLayout"}, + {"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(&LocalFilesystem{}, test.layoutName, filepath.Join(path, "repo")) + layout, err := ParseLayout(&LocalFilesystem{}, test.layoutName, test.defaultLayoutName, filepath.Join(path, "repo")) if err != nil { t.Fatal(err) } @@ -303,7 +304,7 @@ func TestParseLayoutInvalid(t *testing.T) { for _, name := range invalidNames { t.Run(name, func(t *testing.T) { - layout, err := ParseLayout(nil, name, path) + layout, err := ParseLayout(nil, name, "", path) if err == nil { t.Fatalf("expected error not found for layout name %v, layout is %v", name, layout) }