2
2
mirror of https://github.com/octoleo/restic.git synced 2024-06-15 23:32:21 +00:00

backend: Hardcode backend scheme in Factory

Our ParseConfig implementations always expect a specific scheme, thus no
other scheme would work.
This commit is contained in:
Michael Eischer 2023-06-08 17:32:43 +02:00
parent 705ad51bcc
commit 50e0d5e6b5
14 changed files with 43 additions and 29 deletions

View File

@ -100,15 +100,15 @@ var internalGlobalCtx context.Context
func init() { func init() {
backends := location.NewRegistry() backends := location.NewRegistry()
backends.Register("b2", b2.NewFactory()) backends.Register(azure.NewFactory())
backends.Register("local", local.NewFactory()) backends.Register(b2.NewFactory())
backends.Register("sftp", sftp.NewFactory()) backends.Register(gs.NewFactory())
backends.Register("s3", s3.NewFactory()) backends.Register(local.NewFactory())
backends.Register("gs", gs.NewFactory()) backends.Register(rclone.NewFactory())
backends.Register("azure", azure.NewFactory()) backends.Register(rest.NewFactory())
backends.Register("swift", swift.NewFactory()) backends.Register(s3.NewFactory())
backends.Register("rest", rest.NewFactory()) backends.Register(sftp.NewFactory())
backends.Register("rclone", rclone.NewFactory()) backends.Register(swift.NewFactory())
globalOptions.backends = backends globalOptions.backends = backends
var cancel context.CancelFunc var cancel context.CancelFunc

View File

@ -45,7 +45,7 @@ const defaultListMaxItems = 5000
var _ restic.Backend = &Backend{} var _ restic.Backend = &Backend{}
func NewFactory() location.Factory { func NewFactory() location.Factory {
return location.NewHTTPBackendFactory(ParseConfig, location.NoPassword, Create, Open) return location.NewHTTPBackendFactory("azure", ParseConfig, location.NoPassword, Create, Open)
} }
func open(cfg Config, rt http.RoundTripper) (*Backend, error) { func open(cfg Config, rt http.RoundTripper) (*Backend, error) {

View File

@ -38,7 +38,7 @@ const defaultListMaxItems = 10 * 1000
var _ restic.Backend = &b2Backend{} var _ restic.Backend = &b2Backend{}
func NewFactory() location.Factory { func NewFactory() location.Factory {
return location.NewHTTPBackendFactory(ParseConfig, location.NoPassword, Create, Open) return location.NewHTTPBackendFactory("b2", ParseConfig, location.NoPassword, Create, Open)
} }
type sniffingRoundTripper struct { type sniffingRoundTripper struct {

View File

@ -49,7 +49,7 @@ type Backend struct {
var _ restic.Backend = &Backend{} var _ restic.Backend = &Backend{}
func NewFactory() location.Factory { func NewFactory() location.Factory {
return location.NewHTTPBackendFactory(ParseConfig, location.NoPassword, Create, Open) return location.NewHTTPBackendFactory("gs", ParseConfig, location.NoPassword, Create, Open)
} }
func getStorageClient(rt http.RoundTripper) (*storage.Client, error) { func getStorageClient(rt http.RoundTripper) (*storage.Client, error) {

View File

@ -31,7 +31,7 @@ type Local struct {
var _ restic.Backend = &Local{} var _ restic.Backend = &Local{}
func NewFactory() location.Factory { func NewFactory() location.Factory {
return location.NewLimitedBackendFactory(ParseConfig, location.NoPassword, limiter.WrapBackendConstructor(Create), limiter.WrapBackendConstructor(Open)) return location.NewLimitedBackendFactory("local", ParseConfig, location.NoPassword, limiter.WrapBackendConstructor(Create), limiter.WrapBackendConstructor(Open))
} }
const defaultLayout = "default" const defaultLayout = "default"

View File

@ -10,8 +10,8 @@ import (
func TestStripPassword(t *testing.T) { func TestStripPassword(t *testing.T) {
registry := location.NewRegistry() registry := location.NewRegistry()
registry.Register("test", registry.Register(
location.NewHTTPBackendFactory[any, restic.Backend](nil, location.NewHTTPBackendFactory[any, restic.Backend]("test", nil,
func(s string) string { func(s string) string {
return "cleaned" return "cleaned"
}, nil, nil, }, nil, nil,

View File

@ -14,6 +14,7 @@ type testConfig struct {
func testFactory() location.Factory { func testFactory() location.Factory {
return location.NewHTTPBackendFactory[testConfig, restic.Backend]( return location.NewHTTPBackendFactory[testConfig, restic.Backend](
"local",
func(s string) (*testConfig, error) { func(s string) (*testConfig, error) {
return &testConfig{loc: s}, nil return &testConfig{loc: s}, nil
}, nil, nil, nil, }, nil, nil, nil,
@ -22,12 +23,12 @@ func testFactory() location.Factory {
func TestParse(t *testing.T) { func TestParse(t *testing.T) {
registry := location.NewRegistry() registry := location.NewRegistry()
registry.Register("test", testFactory()) registry.Register(testFactory())
path := "test:example" path := "local:example"
u, err := location.Parse(registry, path) u, err := location.Parse(registry, path)
test.OK(t, err) test.OK(t, err)
test.Equals(t, "test", u.Scheme) test.Equals(t, "local", u.Scheme)
test.Equals(t, &testConfig{loc: path}, u.Config) test.Equals(t, &testConfig{loc: path}, u.Config)
} }
@ -43,7 +44,7 @@ func TestParseFallback(t *testing.T) {
} }
registry := location.NewRegistry() registry := location.NewRegistry()
registry.Register("local", testFactory()) registry.Register(testFactory())
for _, path := range fallbackTests { for _, path := range fallbackTests {
t.Run(path, func(t *testing.T) { t.Run(path, func(t *testing.T) {

View File

@ -18,11 +18,11 @@ func NewRegistry() *Registry {
} }
} }
func (r *Registry) Register(scheme string, factory Factory) { func (r *Registry) Register(factory Factory) {
if r.factories[scheme] != nil { if r.factories[factory.Scheme()] != nil {
panic("duplicate backend") panic("duplicate backend")
} }
r.factories[scheme] = factory r.factories[factory.Scheme()] = factory
} }
func (r *Registry) Lookup(scheme string) Factory { func (r *Registry) Lookup(scheme string) Factory {
@ -30,6 +30,7 @@ func (r *Registry) Lookup(scheme string) Factory {
} }
type Factory interface { type Factory interface {
Scheme() string
ParseConfig(s string) (interface{}, error) ParseConfig(s string) (interface{}, error)
StripPassword(s string) string StripPassword(s string) string
Create(ctx context.Context, cfg interface{}, rt http.RoundTripper, lim limiter.Limiter) (restic.Backend, error) Create(ctx context.Context, cfg interface{}, rt http.RoundTripper, lim limiter.Limiter) (restic.Backend, error)
@ -37,12 +38,17 @@ type Factory interface {
} }
type genericBackendFactory[C any, T restic.Backend] struct { type genericBackendFactory[C any, T restic.Backend] struct {
scheme string
parseConfigFn func(s string) (*C, error) parseConfigFn func(s string) (*C, error)
stripPasswordFn func(s string) string stripPasswordFn func(s string) string
createFn func(ctx context.Context, cfg C, rt http.RoundTripper, lim limiter.Limiter) (T, error) createFn func(ctx context.Context, cfg C, rt http.RoundTripper, lim limiter.Limiter) (T, error)
openFn func(ctx context.Context, cfg C, rt http.RoundTripper, lim limiter.Limiter) (T, error) openFn func(ctx context.Context, cfg C, rt http.RoundTripper, lim limiter.Limiter) (T, error)
} }
func (f *genericBackendFactory[C, T]) Scheme() string {
return f.scheme
}
func (f *genericBackendFactory[C, T]) ParseConfig(s string) (interface{}, error) { func (f *genericBackendFactory[C, T]) ParseConfig(s string) (interface{}, error) {
return f.parseConfigFn(s) return f.parseConfigFn(s)
} }
@ -59,12 +65,15 @@ func (f *genericBackendFactory[C, T]) Open(ctx context.Context, cfg interface{},
return f.openFn(ctx, *cfg.(*C), rt, lim) return f.openFn(ctx, *cfg.(*C), rt, lim)
} }
func NewHTTPBackendFactory[C any, T restic.Backend](parseConfigFn func(s string) (*C, error), func NewHTTPBackendFactory[C any, T restic.Backend](
scheme string,
parseConfigFn func(s string) (*C, error),
stripPasswordFn func(s string) string, stripPasswordFn func(s string) string,
createFn func(ctx context.Context, cfg C, rt http.RoundTripper) (T, error), createFn func(ctx context.Context, cfg C, rt http.RoundTripper) (T, error),
openFn func(ctx context.Context, cfg C, rt http.RoundTripper) (T, error)) Factory { openFn func(ctx context.Context, cfg C, rt http.RoundTripper) (T, error)) Factory {
return &genericBackendFactory[C, T]{ return &genericBackendFactory[C, T]{
scheme: scheme,
parseConfigFn: parseConfigFn, parseConfigFn: parseConfigFn,
stripPasswordFn: stripPasswordFn, stripPasswordFn: stripPasswordFn,
createFn: func(ctx context.Context, cfg C, rt http.RoundTripper, _ limiter.Limiter) (T, error) { createFn: func(ctx context.Context, cfg C, rt http.RoundTripper, _ limiter.Limiter) (T, error) {
@ -76,12 +85,15 @@ func NewHTTPBackendFactory[C any, T restic.Backend](parseConfigFn func(s string)
} }
} }
func NewLimitedBackendFactory[C any, T restic.Backend](parseConfigFn func(s string) (*C, error), func NewLimitedBackendFactory[C any, T restic.Backend](
scheme string,
parseConfigFn func(s string) (*C, error),
stripPasswordFn func(s string) string, stripPasswordFn func(s string) string,
createFn func(ctx context.Context, cfg C, lim limiter.Limiter) (T, error), createFn func(ctx context.Context, cfg C, lim limiter.Limiter) (T, error),
openFn func(ctx context.Context, cfg C, lim limiter.Limiter) (T, error)) Factory { openFn func(ctx context.Context, cfg C, lim limiter.Limiter) (T, error)) Factory {
return &genericBackendFactory[C, T]{ return &genericBackendFactory[C, T]{
scheme: scheme,
parseConfigFn: parseConfigFn, parseConfigFn: parseConfigFn,
stripPasswordFn: stripPasswordFn, stripPasswordFn: stripPasswordFn,
createFn: func(ctx context.Context, cfg C, _ http.RoundTripper, lim limiter.Limiter) (T, error) { createFn: func(ctx context.Context, cfg C, _ http.RoundTripper, lim limiter.Limiter) (T, error) {

View File

@ -27,6 +27,7 @@ func NewFactory() location.Factory {
be := New() be := New()
return location.NewHTTPBackendFactory[struct{}, *MemoryBackend]( return location.NewHTTPBackendFactory[struct{}, *MemoryBackend](
"mem",
func(s string) (*struct{}, error) { func(s string) (*struct{}, error) {
return &struct{}{}, nil return &struct{}{}, nil
}, },

View File

@ -38,7 +38,7 @@ type Backend struct {
} }
func NewFactory() location.Factory { func NewFactory() location.Factory {
return location.NewLimitedBackendFactory(ParseConfig, location.NoPassword, Create, Open) return location.NewLimitedBackendFactory("rclone", ParseConfig, location.NoPassword, Create, Open)
} }
// run starts command with args and initializes the StdioConn. // run starts command with args and initializes the StdioConn.

View File

@ -31,7 +31,7 @@ type Backend struct {
} }
func NewFactory() location.Factory { func NewFactory() location.Factory {
return location.NewHTTPBackendFactory(ParseConfig, StripPassword, Create, Open) return location.NewHTTPBackendFactory("rest", ParseConfig, StripPassword, Create, Open)
} }
// the REST API protocol version is decided by HTTP request headers, these are the constants. // the REST API protocol version is decided by HTTP request headers, these are the constants.

View File

@ -33,7 +33,7 @@ type Backend struct {
var _ restic.Backend = &Backend{} var _ restic.Backend = &Backend{}
func NewFactory() location.Factory { func NewFactory() location.Factory {
return location.NewHTTPBackendFactory(ParseConfig, location.NoPassword, Create, Open) return location.NewHTTPBackendFactory("s3", ParseConfig, location.NoPassword, Create, Open)
} }
const defaultLayout = "default" const defaultLayout = "default"

View File

@ -44,7 +44,7 @@ type SFTP struct {
var _ restic.Backend = &SFTP{} var _ restic.Backend = &SFTP{}
func NewFactory() location.Factory { func NewFactory() location.Factory {
return location.NewLimitedBackendFactory(ParseConfig, location.NoPassword, limiter.WrapBackendConstructor(Create), limiter.WrapBackendConstructor(Open)) return location.NewLimitedBackendFactory("sftp", ParseConfig, location.NoPassword, limiter.WrapBackendConstructor(Create), limiter.WrapBackendConstructor(Open))
} }
const defaultLayout = "default" const defaultLayout = "default"

View File

@ -36,7 +36,7 @@ type beSwift struct {
var _ restic.Backend = &beSwift{} var _ restic.Backend = &beSwift{}
func NewFactory() location.Factory { func NewFactory() location.Factory {
return location.NewHTTPBackendFactory(ParseConfig, location.NoPassword, Open, Open) return location.NewHTTPBackendFactory("swift", ParseConfig, location.NoPassword, Open, Open)
} }
// Open opens the swift backend at a container in region. The container is // Open opens the swift backend at a container in region. The container is