mirror of
https://github.com/restic/restic.git
synced 2026-06-24 17:44:17 +00:00
backend: Unify backend construction using factory and registry
This unified construction removes most backend-specific code from global.go. The backend registry will also enable integration tests to use custom backends if necessary.
This commit is contained in:
@@ -87,9 +87,9 @@ func runInit(ctx context.Context, opts InitOptions, gopts GlobalOptions, args []
|
||||
return err
|
||||
}
|
||||
|
||||
be, err := create(ctx, repo, gopts.extended)
|
||||
be, err := create(ctx, repo, gopts, gopts.extended)
|
||||
if err != nil {
|
||||
return errors.Fatalf("create repository at %s failed: %v\n", location.StripPassword(gopts.Repo), err)
|
||||
return errors.Fatalf("create repository at %s failed: %v\n", location.StripPassword(gopts.backends, gopts.Repo), err)
|
||||
}
|
||||
|
||||
s, err := repository.New(be, repository.Options{
|
||||
@@ -102,11 +102,11 @@ func runInit(ctx context.Context, opts InitOptions, gopts GlobalOptions, args []
|
||||
|
||||
err = s.Init(ctx, version, gopts.password, chunkerPolynomial)
|
||||
if err != nil {
|
||||
return errors.Fatalf("create key in repository at %s failed: %v\n", location.StripPassword(gopts.Repo), err)
|
||||
return errors.Fatalf("create key in repository at %s failed: %v\n", location.StripPassword(gopts.backends, gopts.Repo), err)
|
||||
}
|
||||
|
||||
if !gopts.JSON {
|
||||
Verbosef("created restic repository %v at %s", s.Config().ID[:10], location.StripPassword(gopts.Repo))
|
||||
Verbosef("created restic repository %v at %s", s.Config().ID[:10], location.StripPassword(gopts.backends, gopts.Repo))
|
||||
if opts.CopyChunkerParameters && chunkerPolynomial != nil {
|
||||
Verbosef(" with chunker parameters copied from secondary repository\n")
|
||||
} else {
|
||||
@@ -121,7 +121,7 @@ func runInit(ctx context.Context, opts InitOptions, gopts GlobalOptions, args []
|
||||
status := initSuccess{
|
||||
MessageType: "initialized",
|
||||
ID: s.Config().ID,
|
||||
Repository: location.StripPassword(gopts.Repo),
|
||||
Repository: location.StripPassword(gopts.backends, gopts.Repo),
|
||||
}
|
||||
return json.NewEncoder(globalOptions.stdout).Encode(status)
|
||||
}
|
||||
|
||||
+26
-50
@@ -75,6 +75,7 @@ type GlobalOptions struct {
|
||||
stdout io.Writer
|
||||
stderr io.Writer
|
||||
|
||||
backends *location.Registry
|
||||
backendTestHook, backendInnerTestHook backendWrapper
|
||||
|
||||
// verbosity is set as follows:
|
||||
@@ -98,6 +99,18 @@ var isReadingPassword bool
|
||||
var internalGlobalCtx context.Context
|
||||
|
||||
func init() {
|
||||
backends := location.NewRegistry()
|
||||
backends.Register("b2", b2.NewFactory())
|
||||
backends.Register("local", local.NewFactory())
|
||||
backends.Register("sftp", sftp.NewFactory())
|
||||
backends.Register("s3", s3.NewFactory())
|
||||
backends.Register("gs", gs.NewFactory())
|
||||
backends.Register("azure", azure.NewFactory())
|
||||
backends.Register("swift", swift.NewFactory())
|
||||
backends.Register("rest", rest.NewFactory())
|
||||
backends.Register("rclone", rclone.NewFactory())
|
||||
globalOptions.backends = backends
|
||||
|
||||
var cancel context.CancelFunc
|
||||
internalGlobalCtx, cancel = context.WithCancel(context.Background())
|
||||
AddCleanupHandler(func(code int) (int, error) {
|
||||
@@ -554,8 +567,8 @@ func parseConfig(loc location.Location, opts options.Options) (interface{}, erro
|
||||
|
||||
// Open the backend specified by a location config.
|
||||
func open(ctx context.Context, s string, gopts GlobalOptions, opts options.Options) (restic.Backend, error) {
|
||||
debug.Log("parsing location %v", location.StripPassword(s))
|
||||
loc, err := location.Parse(s)
|
||||
debug.Log("parsing location %v", location.StripPassword(gopts.backends, s))
|
||||
loc, err := location.Parse(gopts.backends, s)
|
||||
if err != nil {
|
||||
return nil, errors.Fatalf("parsing repository location failed: %v", err)
|
||||
}
|
||||
@@ -576,32 +589,14 @@ func open(ctx context.Context, s string, gopts GlobalOptions, opts options.Optio
|
||||
lim := limiter.NewStaticLimiter(gopts.Limits)
|
||||
rt = lim.Transport(rt)
|
||||
|
||||
switch loc.Scheme {
|
||||
case "local":
|
||||
be, err = local.Open(ctx, *cfg.(*local.Config))
|
||||
case "sftp":
|
||||
be, err = sftp.Open(ctx, *cfg.(*sftp.Config))
|
||||
case "s3":
|
||||
be, err = s3.Open(ctx, *cfg.(*s3.Config), rt)
|
||||
case "gs":
|
||||
be, err = gs.Open(ctx, *cfg.(*gs.Config), rt)
|
||||
case "azure":
|
||||
be, err = azure.Open(ctx, *cfg.(*azure.Config), rt)
|
||||
case "swift":
|
||||
be, err = swift.Open(ctx, *cfg.(*swift.Config), rt)
|
||||
case "b2":
|
||||
be, err = b2.Open(ctx, *cfg.(*b2.Config), rt)
|
||||
case "rest":
|
||||
be, err = rest.Open(ctx, *cfg.(*rest.Config), rt)
|
||||
case "rclone":
|
||||
be, err = rclone.Open(ctx, *cfg.(*rclone.Config), lim)
|
||||
|
||||
default:
|
||||
factory := gopts.backends.Lookup(loc.Scheme)
|
||||
if factory == nil {
|
||||
return nil, errors.Fatalf("invalid backend: %q", loc.Scheme)
|
||||
}
|
||||
|
||||
be, err = factory.Open(ctx, cfg, rt, lim)
|
||||
if err != nil {
|
||||
return nil, errors.Fatalf("unable to open repository at %v: %v", location.StripPassword(s), err)
|
||||
return nil, errors.Fatalf("unable to open repository at %v: %v", location.StripPassword(gopts.backends, s), err)
|
||||
}
|
||||
|
||||
// wrap with debug logging and connection limiting
|
||||
@@ -623,7 +618,7 @@ func open(ctx context.Context, s string, gopts GlobalOptions, opts options.Optio
|
||||
// check if config is there
|
||||
fi, err := be.Stat(ctx, restic.Handle{Type: restic.ConfigFile})
|
||||
if err != nil {
|
||||
return nil, errors.Fatalf("unable to open config file: %v\nIs there a repository at the following location?\n%v", err, location.StripPassword(s))
|
||||
return nil, errors.Fatalf("unable to open config file: %v\nIs there a repository at the following location?\n%v", err, location.StripPassword(gopts.backends, s))
|
||||
}
|
||||
|
||||
if fi.Size == 0 {
|
||||
@@ -634,9 +629,9 @@ func open(ctx context.Context, s string, gopts GlobalOptions, opts options.Optio
|
||||
}
|
||||
|
||||
// Create the backend specified by URI.
|
||||
func create(ctx context.Context, s string, opts options.Options) (restic.Backend, error) {
|
||||
func create(ctx context.Context, s string, gopts GlobalOptions, opts options.Options) (restic.Backend, error) {
|
||||
debug.Log("parsing location %v", s)
|
||||
loc, err := location.Parse(s)
|
||||
loc, err := location.Parse(gopts.backends, s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -651,31 +646,12 @@ func create(ctx context.Context, s string, opts options.Options) (restic.Backend
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var be restic.Backend
|
||||
switch loc.Scheme {
|
||||
case "local":
|
||||
be, err = local.Create(ctx, *cfg.(*local.Config))
|
||||
case "sftp":
|
||||
be, err = sftp.Create(ctx, *cfg.(*sftp.Config))
|
||||
case "s3":
|
||||
be, err = s3.Create(ctx, *cfg.(*s3.Config), rt)
|
||||
case "gs":
|
||||
be, err = gs.Create(ctx, *cfg.(*gs.Config), rt)
|
||||
case "azure":
|
||||
be, err = azure.Create(ctx, *cfg.(*azure.Config), rt)
|
||||
case "swift":
|
||||
be, err = swift.Open(ctx, *cfg.(*swift.Config), rt)
|
||||
case "b2":
|
||||
be, err = b2.Create(ctx, *cfg.(*b2.Config), rt)
|
||||
case "rest":
|
||||
be, err = rest.Create(ctx, *cfg.(*rest.Config), rt)
|
||||
case "rclone":
|
||||
be, err = rclone.Create(ctx, *cfg.(*rclone.Config))
|
||||
default:
|
||||
debug.Log("invalid repository scheme: %v", s)
|
||||
return nil, errors.Fatalf("invalid scheme %q", loc.Scheme)
|
||||
factory := gopts.backends.Lookup(loc.Scheme)
|
||||
if factory == nil {
|
||||
return nil, errors.Fatalf("invalid backend: %q", loc.Scheme)
|
||||
}
|
||||
|
||||
be, err := factory.Create(ctx, cfg, rt, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -206,6 +206,8 @@ func withTestEnvironment(t testing.TB) (env *testEnvironment, cleanup func()) {
|
||||
|
||||
// replace this hook with "nil" if listing a filetype more than once is necessary
|
||||
backendTestHook: func(r restic.Backend) (restic.Backend, error) { return newOrderedListOnceBackend(r), nil },
|
||||
// start with default set of backends
|
||||
backends: globalOptions.backends,
|
||||
}
|
||||
|
||||
// always overwrite global options
|
||||
|
||||
Reference in New Issue
Block a user