backend/layout: unexport fields and simplify rest layout

This commit is contained in:
Michael Eischer 2024-08-26 21:15:58 +02:00
parent 6024597028
commit af989aab4e
8 changed files with 68 additions and 78 deletions

View file

@ -128,10 +128,7 @@ func open(cfg Config, rt http.RoundTripper) (*Backend, error) {
container: client, container: client,
cfg: cfg, cfg: cfg,
connections: cfg.Connections, connections: cfg.Connections,
Layout: &layout.DefaultLayout{ Layout: layout.NewDefaultLayout(cfg.Prefix, path.Join),
Path: cfg.Prefix,
Join: path.Join,
},
listMaxItems: defaultListMaxItems, listMaxItems: defaultListMaxItems,
} }

View file

@ -110,10 +110,7 @@ func Open(ctx context.Context, cfg Config, rt http.RoundTripper) (backend.Backen
client: client, client: client,
bucket: bucket, bucket: bucket,
cfg: cfg, cfg: cfg,
Layout: &layout.DefaultLayout{ Layout: layout.NewDefaultLayout(cfg.Prefix, path.Join),
Join: path.Join,
Path: cfg.Prefix,
},
listMaxItems: defaultListMaxItems, listMaxItems: defaultListMaxItems,
canDelete: true, canDelete: true,
} }
@ -146,10 +143,7 @@ func Create(ctx context.Context, cfg Config, rt http.RoundTripper) (backend.Back
client: client, client: client,
bucket: bucket, bucket: bucket,
cfg: cfg, cfg: cfg,
Layout: &layout.DefaultLayout{ Layout: layout.NewDefaultLayout(cfg.Prefix, path.Join),
Join: path.Join,
Path: cfg.Prefix,
},
listMaxItems: defaultListMaxItems, listMaxItems: defaultListMaxItems,
} }
return be, nil return be, nil

View file

@ -112,10 +112,7 @@ func open(cfg Config, rt http.RoundTripper) (*Backend, error) {
region: cfg.Region, region: cfg.Region,
bucket: gcsClient.Bucket(cfg.Bucket), bucket: gcsClient.Bucket(cfg.Bucket),
prefix: cfg.Prefix, prefix: cfg.Prefix,
Layout: &layout.DefaultLayout{ Layout: layout.NewDefaultLayout(cfg.Prefix, path.Join),
Path: cfg.Prefix,
Join: path.Join,
},
listMaxItems: defaultListMaxItems, listMaxItems: defaultListMaxItems,
} }

View file

@ -11,8 +11,8 @@ import (
// subdirs, two characters each (taken from the first two characters of the // subdirs, two characters each (taken from the first two characters of the
// file name). // file name).
type DefaultLayout struct { type DefaultLayout struct {
Path string path string
Join func(...string) string join func(...string) string
} }
var defaultLayoutPaths = map[backend.FileType]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 { func NewDefaultLayout(path string, join func(...string) string) *DefaultLayout {
return &DefaultLayout{ return &DefaultLayout{
Path: path, path: path,
Join: join, join: join,
} }
} }
@ -44,32 +44,32 @@ func (l *DefaultLayout) Dirname(h backend.Handle) string {
p := defaultLayoutPaths[h.Type] p := defaultLayoutPaths[h.Type]
if h.Type == backend.PackFile && len(h.Name) > 2 { 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. // Filename returns a path to a file, including its name.
func (l *DefaultLayout) Filename(h backend.Handle) string { func (l *DefaultLayout) Filename(h backend.Handle) string {
name := h.Name name := h.Name
if h.Type == backend.ConfigFile { 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. // Paths returns all directory names needed for a repo.
func (l *DefaultLayout) Paths() (dirs []string) { func (l *DefaultLayout) Paths() (dirs []string) {
for _, p := range defaultLayoutPaths { for _, p := range defaultLayoutPaths {
dirs = append(dirs, l.Join(l.Path, p)) dirs = append(dirs, l.join(l.path, p))
} }
// also add subdirs // also add subdirs
for i := 0; i < 256; i++ { for i := 0; i < 256; i++ {
subdir := hex.EncodeToString([]byte{byte(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 return dirs
@ -81,6 +81,6 @@ func (l *DefaultLayout) Basedir(t backend.FileType) (dirname string, subdirs boo
subdirs = true subdirs = true
} }
dirname = l.Join(l.Path, defaultLayoutPaths[t]) dirname = l.join(l.path, defaultLayoutPaths[t])
return return
} }

View file

@ -1,18 +1,24 @@
package layout package layout
import ( import (
"path"
"github.com/restic/restic/internal/backend" "github.com/restic/restic/internal/backend"
) )
// RESTLayout implements the default layout for the REST protocol. // RESTLayout implements the default layout for the REST protocol.
type RESTLayout struct { type RESTLayout struct {
URL string url string
Path string
Join func(...string) string
} }
var restLayoutPaths = defaultLayoutPaths var restLayoutPaths = defaultLayoutPaths
func NewRESTLayout(url string) *RESTLayout {
return &RESTLayout{
url: url,
}
}
func (l *RESTLayout) String() string { func (l *RESTLayout) String() string {
return "<RESTLayout>" return "<RESTLayout>"
} }
@ -25,10 +31,10 @@ func (l *RESTLayout) Name() string {
// Dirname returns the directory path for a given file type and name. // Dirname returns the directory path for a given file type and name.
func (l *RESTLayout) Dirname(h backend.Handle) string { func (l *RESTLayout) Dirname(h backend.Handle) string {
if h.Type == backend.ConfigFile { 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. // Filename returns a path to a file, including its name.
@ -39,18 +45,18 @@ func (l *RESTLayout) Filename(h backend.Handle) string {
name = "config" 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 // Paths returns all directory names
func (l *RESTLayout) Paths() (dirs []string) { func (l *RESTLayout) Paths() (dirs []string) {
for _, p := range restLayoutPaths { for _, p := range restLayoutPaths {
dirs = append(dirs, l.URL+l.Join(l.Path, p)) dirs = append(dirs, l.url+path.Join("/", p))
} }
return dirs return dirs
} }
// Basedir returns the base dir name for files of type t. // Basedir returns the base dir name for files of type t.
func (l *RESTLayout) Basedir(t backend.FileType) (dirname string, subdirs bool) { 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
} }

View file

@ -6,6 +6,7 @@ import (
"path/filepath" "path/filepath"
"reflect" "reflect"
"sort" "sort"
"strings"
"testing" "testing"
"github.com/restic/restic/internal/backend" "github.com/restic/restic/internal/backend"
@ -97,8 +98,8 @@ func TestDefaultLayout(t *testing.T) {
t.Run("Paths", func(t *testing.T) { t.Run("Paths", func(t *testing.T) {
l := &DefaultLayout{ l := &DefaultLayout{
Path: tempdir, path: tempdir,
Join: filepath.Join, join: filepath.Join,
} }
dirs := l.Paths() dirs := l.Paths()
@ -126,8 +127,8 @@ func TestDefaultLayout(t *testing.T) {
for _, test := range tests { for _, test := range tests {
t.Run(fmt.Sprintf("%v/%v", test.Type, test.Handle.Name), func(t *testing.T) { t.Run(fmt.Sprintf("%v/%v", test.Type, test.Handle.Name), func(t *testing.T) {
l := &DefaultLayout{ l := &DefaultLayout{
Path: test.path, path: test.path,
Join: test.join, join: test.join,
} }
filename := l.Filename(test.Handle) filename := l.Filename(test.Handle)
@ -139,7 +140,7 @@ func TestDefaultLayout(t *testing.T) {
} }
func TestRESTLayout(t *testing.T) { func TestRESTLayout(t *testing.T) {
path := rtest.TempDir(t) url := `https://hostname.foo`
var tests = []struct { var tests = []struct {
backend.Handle backend.Handle
@ -147,44 +148,43 @@ func TestRESTLayout(t *testing.T) {
}{ }{
{ {
backend.Handle{Type: backend.PackFile, Name: "0123456"}, 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"}, backend.Handle{Type: backend.ConfigFile, Name: "CFG"},
filepath.Join(path, "config"), strings.Join([]string{url, "config"}, "/"),
}, },
{ {
backend.Handle{Type: backend.SnapshotFile, Name: "123456"}, 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"}, 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"}, 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"}, backend.Handle{Type: backend.KeyFile, Name: "123456"},
filepath.Join(path, "keys", "123456"), strings.Join([]string{url, "keys", "123456"}, "/"),
}, },
} }
l := &RESTLayout{ l := &RESTLayout{
Path: path, url: url,
Join: filepath.Join,
} }
t.Run("Paths", func(t *testing.T) { t.Run("Paths", func(t *testing.T) {
dirs := l.Paths() dirs := l.Paths()
want := []string{ want := []string{
filepath.Join(path, "data"), strings.Join([]string{url, "data"}, "/"),
filepath.Join(path, "snapshots"), strings.Join([]string{url, "snapshots"}, "/"),
filepath.Join(path, "index"), strings.Join([]string{url, "index"}, "/"),
filepath.Join(path, "locks"), strings.Join([]string{url, "locks"}, "/"),
filepath.Join(path, "keys"), strings.Join([]string{url, "keys"}, "/"),
} }
sort.Strings(want) sort.Strings(want)
@ -213,19 +213,19 @@ func TestRESTLayoutURLs(t *testing.T) {
dir string dir string
}{ }{
{ {
&RESTLayout{URL: "https://hostname.foo", Path: "", Join: path.Join}, &RESTLayout{url: "https://hostname.foo"},
backend.Handle{Type: backend.PackFile, Name: "foobar"}, backend.Handle{Type: backend.PackFile, Name: "foobar"},
"https://hostname.foo/data/foobar", "https://hostname.foo/data/foobar",
"https://hostname.foo/data/", "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"}, backend.Handle{Type: backend.LockFile, Name: "foobar"},
"https://hostname.foo:1234/prefix/repo/locks/foobar", "https://hostname.foo:1234/prefix/repo/locks/foobar",
"https://hostname.foo:1234/prefix/repo/locks/", "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"}, backend.Handle{Type: backend.ConfigFile, Name: "foobar"},
"https://hostname.foo:1234/prefix/repo/config", "https://hostname.foo:1234/prefix/repo/config",
"https://hostname.foo:1234/prefix/repo/", "https://hostname.foo:1234/prefix/repo/",

View file

@ -8,7 +8,6 @@ import (
"io" "io"
"net/http" "net/http"
"net/url" "net/url"
"path"
"strings" "strings"
"github.com/restic/restic/internal/backend" "github.com/restic/restic/internal/backend"
@ -66,7 +65,7 @@ func Open(_ context.Context, cfg Config, rt http.RoundTripper) (*Backend, error)
be := &Backend{ be := &Backend{
url: cfg.URL, url: cfg.URL,
client: http.Client{Transport: rt}, client: http.Client{Transport: rt},
Layout: &layout.RESTLayout{URL: url, Join: path.Join}, Layout: layout.NewRESTLayout(url),
connections: cfg.Connections, connections: cfg.Connections,
} }

View file

@ -72,10 +72,7 @@ func Open(ctx context.Context, cfg Config, rt http.RoundTripper) (backend.Backen
connections: cfg.Connections, connections: cfg.Connections,
container: cfg.Container, container: cfg.Container,
prefix: cfg.Prefix, prefix: cfg.Prefix,
Layout: &layout.DefaultLayout{ Layout: layout.NewDefaultLayout(cfg.Prefix, path.Join),
Path: cfg.Prefix,
Join: path.Join,
},
} }
// Authenticate if needed // Authenticate if needed