diff --git a/internal/backend/azure/azure.go b/internal/backend/azure/azure.go index 737cf0e14..1c844f97f 100644 --- a/internal/backend/azure/azure.go +++ b/internal/backend/azure/azure.go @@ -125,13 +125,10 @@ func open(cfg Config, rt http.RoundTripper) (*Backend, error) { } be := &Backend{ - container: client, - cfg: cfg, - connections: cfg.Connections, - Layout: &layout.DefaultLayout{ - Path: cfg.Prefix, - Join: path.Join, - }, + container: client, + cfg: cfg, + connections: cfg.Connections, + Layout: layout.NewDefaultLayout(cfg.Prefix, path.Join), listMaxItems: defaultListMaxItems, } diff --git a/internal/backend/b2/b2.go b/internal/backend/b2/b2.go index 9717cdd0e..3ef2bcbe3 100644 --- a/internal/backend/b2/b2.go +++ b/internal/backend/b2/b2.go @@ -107,13 +107,10 @@ func Open(ctx context.Context, cfg Config, rt http.RoundTripper) (backend.Backen } be := &b2Backend{ - client: client, - bucket: bucket, - cfg: cfg, - Layout: &layout.DefaultLayout{ - Join: path.Join, - Path: cfg.Prefix, - }, + client: client, + bucket: bucket, + cfg: cfg, + Layout: layout.NewDefaultLayout(cfg.Prefix, path.Join), listMaxItems: defaultListMaxItems, canDelete: true, } @@ -143,13 +140,10 @@ func Create(ctx context.Context, cfg Config, rt http.RoundTripper) (backend.Back } be := &b2Backend{ - client: client, - bucket: bucket, - cfg: cfg, - Layout: &layout.DefaultLayout{ - Join: path.Join, - Path: cfg.Prefix, - }, + client: client, + bucket: bucket, + cfg: cfg, + Layout: layout.NewDefaultLayout(cfg.Prefix, path.Join), listMaxItems: defaultListMaxItems, } return be, nil diff --git a/internal/backend/gs/gs.go b/internal/backend/gs/gs.go index 0af226f5d..b4d4ecfd4 100644 --- a/internal/backend/gs/gs.go +++ b/internal/backend/gs/gs.go @@ -105,17 +105,14 @@ func open(cfg Config, rt http.RoundTripper) (*Backend, error) { } be := &Backend{ - gcsClient: gcsClient, - projectID: cfg.ProjectID, - connections: cfg.Connections, - bucketName: cfg.Bucket, - region: cfg.Region, - bucket: gcsClient.Bucket(cfg.Bucket), - prefix: cfg.Prefix, - Layout: &layout.DefaultLayout{ - Path: cfg.Prefix, - Join: path.Join, - }, + gcsClient: gcsClient, + projectID: cfg.ProjectID, + connections: cfg.Connections, + bucketName: cfg.Bucket, + region: cfg.Region, + bucket: gcsClient.Bucket(cfg.Bucket), + prefix: cfg.Prefix, + Layout: layout.NewDefaultLayout(cfg.Prefix, path.Join), listMaxItems: defaultListMaxItems, } diff --git a/internal/backend/layout/layout_default.go b/internal/backend/layout/layout_default.go index 3f73a941d..d2c4634d3 100644 --- a/internal/backend/layout/layout_default.go +++ b/internal/backend/layout/layout_default.go @@ -11,8 +11,8 @@ import ( // subdirs, two characters each (taken from the first two characters of the // file name). type DefaultLayout struct { - Path string - Join func(...string) string + path string + join func(...string) string } var defaultLayoutPaths = map[backend.FileType]string{ @@ -25,8 +25,8 @@ var defaultLayoutPaths = map[backend.FileType]string{ func NewDefaultLayout(path string, join func(...string) string) *DefaultLayout { return &DefaultLayout{ - Path: path, - Join: join, + path: path, + join: join, } } @@ -44,32 +44,32 @@ func (l *DefaultLayout) Dirname(h backend.Handle) string { p := defaultLayoutPaths[h.Type] if h.Type == backend.PackFile && len(h.Name) > 2 { - p = l.Join(p, h.Name[:2]) + "/" + p = l.join(p, h.Name[:2]) + "/" } - return l.Join(l.Path, p) + "/" + return l.join(l.path, p) + "/" } // Filename returns a path to a file, including its name. func (l *DefaultLayout) Filename(h backend.Handle) string { name := h.Name if h.Type == backend.ConfigFile { - return l.Join(l.Path, "config") + return l.join(l.path, "config") } - return l.Join(l.Dirname(h), name) + return l.join(l.Dirname(h), name) } // Paths returns all directory names needed for a repo. func (l *DefaultLayout) Paths() (dirs []string) { for _, p := range defaultLayoutPaths { - dirs = append(dirs, l.Join(l.Path, p)) + dirs = append(dirs, l.join(l.path, p)) } // also add subdirs for i := 0; i < 256; i++ { subdir := hex.EncodeToString([]byte{byte(i)}) - dirs = append(dirs, l.Join(l.Path, defaultLayoutPaths[backend.PackFile], subdir)) + dirs = append(dirs, l.join(l.path, defaultLayoutPaths[backend.PackFile], subdir)) } return dirs @@ -81,6 +81,6 @@ func (l *DefaultLayout) Basedir(t backend.FileType) (dirname string, subdirs boo subdirs = true } - dirname = l.Join(l.Path, defaultLayoutPaths[t]) + dirname = l.join(l.path, defaultLayoutPaths[t]) return } diff --git a/internal/backend/layout/layout_rest.go b/internal/backend/layout/layout_rest.go index 822dd4a7e..78fc6c826 100644 --- a/internal/backend/layout/layout_rest.go +++ b/internal/backend/layout/layout_rest.go @@ -1,18 +1,24 @@ package layout import ( + "path" + "github.com/restic/restic/internal/backend" ) // RESTLayout implements the default layout for the REST protocol. type RESTLayout struct { - URL string - Path string - Join func(...string) string + url string } var restLayoutPaths = defaultLayoutPaths +func NewRESTLayout(url string) *RESTLayout { + return &RESTLayout{ + url: url, + } +} + func (l *RESTLayout) String() string { return "" } @@ -25,10 +31,10 @@ func (l *RESTLayout) Name() string { // Dirname returns the directory path for a given file type and name. func (l *RESTLayout) Dirname(h backend.Handle) string { if h.Type == backend.ConfigFile { - return l.URL + l.Join(l.Path, "/") + return l.url + "/" } - return l.URL + l.Join(l.Path, "/", restLayoutPaths[h.Type]) + "/" + return l.url + path.Join("/", restLayoutPaths[h.Type]) + "/" } // Filename returns a path to a file, including its name. @@ -39,18 +45,18 @@ func (l *RESTLayout) Filename(h backend.Handle) string { name = "config" } - return l.URL + l.Join(l.Path, "/", restLayoutPaths[h.Type], name) + return l.url + path.Join("/", restLayoutPaths[h.Type], name) } // Paths returns all directory names func (l *RESTLayout) Paths() (dirs []string) { for _, p := range restLayoutPaths { - dirs = append(dirs, l.URL+l.Join(l.Path, p)) + dirs = append(dirs, l.url+path.Join("/", p)) } return dirs } // Basedir returns the base dir name for files of type t. func (l *RESTLayout) Basedir(t backend.FileType) (dirname string, subdirs bool) { - return l.URL + l.Join(l.Path, restLayoutPaths[t]), false + return l.url + path.Join("/", restLayoutPaths[t]), false } diff --git a/internal/backend/layout/layout_test.go b/internal/backend/layout/layout_test.go index de5ae7d69..af5105c20 100644 --- a/internal/backend/layout/layout_test.go +++ b/internal/backend/layout/layout_test.go @@ -6,6 +6,7 @@ import ( "path/filepath" "reflect" "sort" + "strings" "testing" "github.com/restic/restic/internal/backend" @@ -97,8 +98,8 @@ func TestDefaultLayout(t *testing.T) { t.Run("Paths", func(t *testing.T) { l := &DefaultLayout{ - Path: tempdir, - Join: filepath.Join, + path: tempdir, + join: filepath.Join, } dirs := l.Paths() @@ -126,8 +127,8 @@ func TestDefaultLayout(t *testing.T) { for _, test := range tests { t.Run(fmt.Sprintf("%v/%v", test.Type, test.Handle.Name), func(t *testing.T) { l := &DefaultLayout{ - Path: test.path, - Join: test.join, + path: test.path, + join: test.join, } filename := l.Filename(test.Handle) @@ -139,7 +140,7 @@ func TestDefaultLayout(t *testing.T) { } func TestRESTLayout(t *testing.T) { - path := rtest.TempDir(t) + url := `https://hostname.foo` var tests = []struct { backend.Handle @@ -147,44 +148,43 @@ func TestRESTLayout(t *testing.T) { }{ { backend.Handle{Type: backend.PackFile, Name: "0123456"}, - filepath.Join(path, "data", "0123456"), + strings.Join([]string{url, "data", "0123456"}, "/"), }, { backend.Handle{Type: backend.ConfigFile, Name: "CFG"}, - filepath.Join(path, "config"), + strings.Join([]string{url, "config"}, "/"), }, { backend.Handle{Type: backend.SnapshotFile, Name: "123456"}, - filepath.Join(path, "snapshots", "123456"), + strings.Join([]string{url, "snapshots", "123456"}, "/"), }, { backend.Handle{Type: backend.IndexFile, Name: "123456"}, - filepath.Join(path, "index", "123456"), + strings.Join([]string{url, "index", "123456"}, "/"), }, { backend.Handle{Type: backend.LockFile, Name: "123456"}, - filepath.Join(path, "locks", "123456"), + strings.Join([]string{url, "locks", "123456"}, "/"), }, { backend.Handle{Type: backend.KeyFile, Name: "123456"}, - filepath.Join(path, "keys", "123456"), + strings.Join([]string{url, "keys", "123456"}, "/"), }, } l := &RESTLayout{ - Path: path, - Join: filepath.Join, + url: url, } t.Run("Paths", func(t *testing.T) { dirs := l.Paths() want := []string{ - filepath.Join(path, "data"), - filepath.Join(path, "snapshots"), - filepath.Join(path, "index"), - filepath.Join(path, "locks"), - filepath.Join(path, "keys"), + strings.Join([]string{url, "data"}, "/"), + strings.Join([]string{url, "snapshots"}, "/"), + strings.Join([]string{url, "index"}, "/"), + strings.Join([]string{url, "locks"}, "/"), + strings.Join([]string{url, "keys"}, "/"), } sort.Strings(want) @@ -213,19 +213,19 @@ func TestRESTLayoutURLs(t *testing.T) { dir string }{ { - &RESTLayout{URL: "https://hostname.foo", Path: "", Join: path.Join}, + &RESTLayout{url: "https://hostname.foo"}, backend.Handle{Type: backend.PackFile, Name: "foobar"}, "https://hostname.foo/data/foobar", "https://hostname.foo/data/", }, { - &RESTLayout{URL: "https://hostname.foo:1234/prefix/repo", Path: "/", Join: path.Join}, + &RESTLayout{url: "https://hostname.foo:1234/prefix/repo"}, backend.Handle{Type: backend.LockFile, Name: "foobar"}, "https://hostname.foo:1234/prefix/repo/locks/foobar", "https://hostname.foo:1234/prefix/repo/locks/", }, { - &RESTLayout{URL: "https://hostname.foo:1234/prefix/repo", Path: "/", Join: path.Join}, + &RESTLayout{url: "https://hostname.foo:1234/prefix/repo"}, backend.Handle{Type: backend.ConfigFile, Name: "foobar"}, "https://hostname.foo:1234/prefix/repo/config", "https://hostname.foo:1234/prefix/repo/", diff --git a/internal/backend/rest/rest.go b/internal/backend/rest/rest.go index d0a08175b..7bdedff39 100644 --- a/internal/backend/rest/rest.go +++ b/internal/backend/rest/rest.go @@ -8,7 +8,6 @@ import ( "io" "net/http" "net/url" - "path" "strings" "github.com/restic/restic/internal/backend" @@ -66,7 +65,7 @@ func Open(_ context.Context, cfg Config, rt http.RoundTripper) (*Backend, error) be := &Backend{ url: cfg.URL, client: http.Client{Transport: rt}, - Layout: &layout.RESTLayout{URL: url, Join: path.Join}, + Layout: layout.NewRESTLayout(url), connections: cfg.Connections, } diff --git a/internal/backend/swift/swift.go b/internal/backend/swift/swift.go index e6412d0bf..dfa2055cd 100644 --- a/internal/backend/swift/swift.go +++ b/internal/backend/swift/swift.go @@ -72,10 +72,7 @@ func Open(ctx context.Context, cfg Config, rt http.RoundTripper) (backend.Backen connections: cfg.Connections, container: cfg.Container, prefix: cfg.Prefix, - Layout: &layout.DefaultLayout{ - Path: cfg.Prefix, - Join: path.Join, - }, + Layout: layout.NewDefaultLayout(cfg.Prefix, path.Join), } // Authenticate if needed