forked from TrueCloudLab/restic
backend: let ParseConfig return a Config pointer
In order to change the backend initialization in `global.go` to be able to generically call cfg.ApplyEnvironment() for supported backends, the `interface{}` returned by `ParseConfig` must contain a pointer to the configuration. An alternative would be to use reflection to convert the type from `interface{}(Config)` to `interface{}(*Config)` (from value to pointer type). However, this would just complicate the type mess further.
This commit is contained in:
parent
25a0be7f26
commit
f903db492c
26 changed files with 165 additions and 146 deletions
|
@ -540,8 +540,8 @@ func parseConfig(loc location.Location, opts options.Options) (interface{}, erro
|
|||
|
||||
switch loc.Scheme {
|
||||
case "local":
|
||||
cfg := loc.Config.(local.Config)
|
||||
if err := opts.Apply(loc.Scheme, &cfg); err != nil {
|
||||
cfg := loc.Config.(*local.Config)
|
||||
if err := opts.Apply(loc.Scheme, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -549,8 +549,8 @@ func parseConfig(loc location.Location, opts options.Options) (interface{}, erro
|
|||
return cfg, nil
|
||||
|
||||
case "sftp":
|
||||
cfg := loc.Config.(sftp.Config)
|
||||
if err := opts.Apply(loc.Scheme, &cfg); err != nil {
|
||||
cfg := loc.Config.(*sftp.Config)
|
||||
if err := opts.Apply(loc.Scheme, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -558,12 +558,12 @@ func parseConfig(loc location.Location, opts options.Options) (interface{}, erro
|
|||
return cfg, nil
|
||||
|
||||
case "s3":
|
||||
cfg := loc.Config.(s3.Config)
|
||||
cfg := loc.Config.(*s3.Config)
|
||||
|
||||
if err := s3.ApplyEnvironment(&cfg); err != nil {
|
||||
if err := s3.ApplyEnvironment(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := opts.Apply(loc.Scheme, &cfg); err != nil {
|
||||
if err := opts.Apply(loc.Scheme, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -571,12 +571,12 @@ func parseConfig(loc location.Location, opts options.Options) (interface{}, erro
|
|||
return cfg, nil
|
||||
|
||||
case "gs":
|
||||
cfg := loc.Config.(gs.Config)
|
||||
cfg := loc.Config.(*gs.Config)
|
||||
|
||||
if err := gs.ApplyEnvironment(&cfg); err != nil {
|
||||
if err := gs.ApplyEnvironment(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := opts.Apply(loc.Scheme, &cfg); err != nil {
|
||||
if err := opts.Apply(loc.Scheme, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -584,12 +584,12 @@ func parseConfig(loc location.Location, opts options.Options) (interface{}, erro
|
|||
return cfg, nil
|
||||
|
||||
case "azure":
|
||||
cfg := loc.Config.(azure.Config)
|
||||
cfg := loc.Config.(*azure.Config)
|
||||
|
||||
if err := azure.ApplyEnvironment(&cfg); err != nil {
|
||||
if err := azure.ApplyEnvironment(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := opts.Apply(loc.Scheme, &cfg); err != nil {
|
||||
if err := opts.Apply(loc.Scheme, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -597,13 +597,13 @@ func parseConfig(loc location.Location, opts options.Options) (interface{}, erro
|
|||
return cfg, nil
|
||||
|
||||
case "swift":
|
||||
cfg := loc.Config.(swift.Config)
|
||||
cfg := loc.Config.(*swift.Config)
|
||||
|
||||
if err := swift.ApplyEnvironment("", &cfg); err != nil {
|
||||
if err := swift.ApplyEnvironment("", cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := opts.Apply(loc.Scheme, &cfg); err != nil {
|
||||
if err := opts.Apply(loc.Scheme, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -611,28 +611,28 @@ func parseConfig(loc location.Location, opts options.Options) (interface{}, erro
|
|||
return cfg, nil
|
||||
|
||||
case "b2":
|
||||
cfg := loc.Config.(b2.Config)
|
||||
cfg := loc.Config.(*b2.Config)
|
||||
|
||||
if err := b2.ApplyEnvironment(&cfg); err != nil {
|
||||
if err := b2.ApplyEnvironment(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := opts.Apply(loc.Scheme, &cfg); err != nil {
|
||||
if err := opts.Apply(loc.Scheme, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
debug.Log("opening b2 repository at %#v", cfg)
|
||||
return cfg, nil
|
||||
case "rest":
|
||||
cfg := loc.Config.(rest.Config)
|
||||
if err := opts.Apply(loc.Scheme, &cfg); err != nil {
|
||||
cfg := loc.Config.(*rest.Config)
|
||||
if err := opts.Apply(loc.Scheme, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
debug.Log("opening rest repository at %#v", cfg)
|
||||
return cfg, nil
|
||||
case "rclone":
|
||||
cfg := loc.Config.(rclone.Config)
|
||||
if err := opts.Apply(loc.Scheme, &cfg); err != nil {
|
||||
cfg := loc.Config.(*rclone.Config)
|
||||
if err := opts.Apply(loc.Scheme, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
@ -669,23 +669,23 @@ func open(ctx context.Context, s string, gopts GlobalOptions, opts options.Optio
|
|||
|
||||
switch loc.Scheme {
|
||||
case "local":
|
||||
be, err = local.Open(ctx, cfg.(local.Config))
|
||||
be, err = local.Open(ctx, *cfg.(*local.Config))
|
||||
case "sftp":
|
||||
be, err = sftp.Open(ctx, cfg.(sftp.Config))
|
||||
be, err = sftp.Open(ctx, *cfg.(*sftp.Config))
|
||||
case "s3":
|
||||
be, err = s3.Open(ctx, cfg.(s3.Config), rt)
|
||||
be, err = s3.Open(ctx, *cfg.(*s3.Config), rt)
|
||||
case "gs":
|
||||
be, err = gs.Open(cfg.(gs.Config), rt)
|
||||
be, err = gs.Open(*cfg.(*gs.Config), rt)
|
||||
case "azure":
|
||||
be, err = azure.Open(ctx, cfg.(azure.Config), rt)
|
||||
be, err = azure.Open(ctx, *cfg.(*azure.Config), rt)
|
||||
case "swift":
|
||||
be, err = swift.Open(ctx, cfg.(swift.Config), rt)
|
||||
be, err = swift.Open(ctx, *cfg.(*swift.Config), rt)
|
||||
case "b2":
|
||||
be, err = b2.Open(ctx, cfg.(b2.Config), rt)
|
||||
be, err = b2.Open(ctx, *cfg.(*b2.Config), rt)
|
||||
case "rest":
|
||||
be, err = rest.Open(cfg.(rest.Config), rt)
|
||||
be, err = rest.Open(*cfg.(*rest.Config), rt)
|
||||
case "rclone":
|
||||
be, err = rclone.Open(cfg.(rclone.Config), lim)
|
||||
be, err = rclone.Open(*cfg.(*rclone.Config), lim)
|
||||
|
||||
default:
|
||||
return nil, errors.Fatalf("invalid backend: %q", loc.Scheme)
|
||||
|
@ -745,23 +745,23 @@ func create(ctx context.Context, s string, opts options.Options) (restic.Backend
|
|||
var be restic.Backend
|
||||
switch loc.Scheme {
|
||||
case "local":
|
||||
be, err = local.Create(ctx, cfg.(local.Config))
|
||||
be, err = local.Create(ctx, *cfg.(*local.Config))
|
||||
case "sftp":
|
||||
be, err = sftp.Create(ctx, cfg.(sftp.Config))
|
||||
be, err = sftp.Create(ctx, *cfg.(*sftp.Config))
|
||||
case "s3":
|
||||
be, err = s3.Create(ctx, cfg.(s3.Config), rt)
|
||||
be, err = s3.Create(ctx, *cfg.(*s3.Config), rt)
|
||||
case "gs":
|
||||
be, err = gs.Create(ctx, cfg.(gs.Config), rt)
|
||||
be, err = gs.Create(ctx, *cfg.(*gs.Config), rt)
|
||||
case "azure":
|
||||
be, err = azure.Create(ctx, cfg.(azure.Config), rt)
|
||||
be, err = azure.Create(ctx, *cfg.(*azure.Config), rt)
|
||||
case "swift":
|
||||
be, err = swift.Open(ctx, cfg.(swift.Config), rt)
|
||||
be, err = swift.Open(ctx, *cfg.(*swift.Config), rt)
|
||||
case "b2":
|
||||
be, err = b2.Create(ctx, cfg.(b2.Config), rt)
|
||||
be, err = b2.Create(ctx, *cfg.(*b2.Config), rt)
|
||||
case "rest":
|
||||
be, err = rest.Create(ctx, cfg.(rest.Config), rt)
|
||||
be, err = rest.Create(ctx, *cfg.(*rest.Config), rt)
|
||||
case "rclone":
|
||||
be, err = rclone.Create(ctx, cfg.(rclone.Config))
|
||||
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)
|
||||
|
|
|
@ -29,10 +29,10 @@ func newAzureTestSuite(t testing.TB) *test.Suite[azure.Config] {
|
|||
MinimalData: true,
|
||||
|
||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||
NewConfig: func() (azure.Config, error) {
|
||||
NewConfig: func() (*azure.Config, error) {
|
||||
cfg, err := azure.ParseConfig(os.Getenv("RESTIC_TEST_AZURE_REPOSITORY"))
|
||||
if err != nil {
|
||||
return azure.Config{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg.AccountName = os.Getenv("RESTIC_TEST_AZURE_ACCOUNT_NAME")
|
||||
|
@ -150,7 +150,7 @@ func TestUploadLargeFile(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
be, err := azure.Create(ctx, cfg, tr)
|
||||
be, err := azure.Create(ctx, *cfg, tr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -34,9 +34,9 @@ func init() {
|
|||
|
||||
// ParseConfig parses the string s and extracts the azure config. The
|
||||
// configuration format is azure:containerName:/[prefix].
|
||||
func ParseConfig(s string) (Config, error) {
|
||||
func ParseConfig(s string) (*Config, error) {
|
||||
if !strings.HasPrefix(s, "azure:") {
|
||||
return Config{}, errors.New("azure: invalid format")
|
||||
return nil, errors.New("azure: invalid format")
|
||||
}
|
||||
|
||||
// strip prefix "azure:"
|
||||
|
@ -46,13 +46,13 @@ func ParseConfig(s string) (Config, error) {
|
|||
// remainder as prefix
|
||||
container, prefix, colon := strings.Cut(s, ":")
|
||||
if !colon {
|
||||
return Config{}, errors.New("azure: invalid format: bucket name or path not found")
|
||||
return nil, errors.New("azure: invalid format: bucket name or path not found")
|
||||
}
|
||||
prefix = strings.TrimPrefix(path.Clean(prefix), "/")
|
||||
cfg := NewConfig()
|
||||
cfg.Container = container
|
||||
cfg.Prefix = prefix
|
||||
return cfg, nil
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// ApplyEnvironment saves values from the environment to the config.
|
||||
|
|
|
@ -30,10 +30,10 @@ func newB2TestSuite(t testing.TB) *test.Suite[b2.Config] {
|
|||
WaitForDelayedRemoval: 10 * time.Second,
|
||||
|
||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||
NewConfig: func() (b2.Config, error) {
|
||||
NewConfig: func() (*b2.Config, error) {
|
||||
cfg, err := b2.ParseConfig(os.Getenv("RESTIC_TEST_B2_REPOSITORY"))
|
||||
if err != nil {
|
||||
return b2.Config{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg.AccountID = os.Getenv("RESTIC_TEST_B2_ACCOUNT_ID")
|
||||
|
|
|
@ -59,15 +59,15 @@ func checkBucketName(name string) error {
|
|||
// ParseConfig parses the string s and extracts the b2 config. The supported
|
||||
// configuration format is b2:bucketname/prefix. If no prefix is given the
|
||||
// prefix "restic" will be used.
|
||||
func ParseConfig(s string) (Config, error) {
|
||||
func ParseConfig(s string) (*Config, error) {
|
||||
if !strings.HasPrefix(s, "b2:") {
|
||||
return Config{}, errors.New("invalid format, want: b2:bucket-name[:path]")
|
||||
return nil, errors.New("invalid format, want: b2:bucket-name[:path]")
|
||||
}
|
||||
|
||||
s = s[3:]
|
||||
bucket, prefix, _ := strings.Cut(s, ":")
|
||||
if err := checkBucketName(bucket); err != nil {
|
||||
return Config{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(prefix) > 0 {
|
||||
|
@ -78,7 +78,7 @@ func ParseConfig(s string) (Config, error) {
|
|||
cfg.Bucket = bucket
|
||||
cfg.Prefix = prefix
|
||||
|
||||
return cfg, nil
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// ApplyEnvironment saves values from the environment to the config.
|
||||
|
|
|
@ -35,9 +35,9 @@ func init() {
|
|||
|
||||
// ParseConfig parses the string s and extracts the gcs config. The
|
||||
// supported configuration format is gs:bucketName:/[prefix].
|
||||
func ParseConfig(s string) (Config, error) {
|
||||
func ParseConfig(s string) (*Config, error) {
|
||||
if !strings.HasPrefix(s, "gs:") {
|
||||
return Config{}, errors.New("gs: invalid format")
|
||||
return nil, errors.New("gs: invalid format")
|
||||
}
|
||||
|
||||
// strip prefix "gs:"
|
||||
|
@ -47,7 +47,7 @@ func ParseConfig(s string) (Config, error) {
|
|||
// remainder as prefix
|
||||
bucket, prefix, colon := strings.Cut(s, ":")
|
||||
if !colon {
|
||||
return Config{}, errors.New("gs: invalid format: bucket name or path not found")
|
||||
return nil, errors.New("gs: invalid format: bucket name or path not found")
|
||||
}
|
||||
|
||||
prefix = strings.TrimPrefix(path.Clean(prefix), "/")
|
||||
|
@ -55,7 +55,7 @@ func ParseConfig(s string) (Config, error) {
|
|||
cfg := NewConfig()
|
||||
cfg.Bucket = bucket
|
||||
cfg.Prefix = prefix
|
||||
return cfg, nil
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// ApplyEnvironment saves values from the environment to the config.
|
||||
|
|
|
@ -26,10 +26,10 @@ func newGSTestSuite(t testing.TB) *test.Suite[gs.Config] {
|
|||
MinimalData: true,
|
||||
|
||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||
NewConfig: func() (gs.Config, error) {
|
||||
NewConfig: func() (*gs.Config, error) {
|
||||
cfg, err := gs.ParseConfig(os.Getenv("RESTIC_TEST_GS_REPOSITORY"))
|
||||
if err != nil {
|
||||
return gs.Config{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg.ProjectID = os.Getenv("RESTIC_TEST_GS_PROJECT_ID")
|
||||
|
|
|
@ -27,12 +27,12 @@ func init() {
|
|||
}
|
||||
|
||||
// ParseConfig parses a local backend config.
|
||||
func ParseConfig(s string) (Config, error) {
|
||||
func ParseConfig(s string) (*Config, error) {
|
||||
if !strings.HasPrefix(s, "local:") {
|
||||
return Config{}, errors.New(`invalid format, prefix "local" not found`)
|
||||
return nil, errors.New(`invalid format, prefix "local" not found`)
|
||||
}
|
||||
|
||||
cfg := NewConfig()
|
||||
cfg.Path = s[6:]
|
||||
return cfg, nil
|
||||
return &cfg, nil
|
||||
}
|
||||
|
|
18
internal/backend/local/config_test.go
Normal file
18
internal/backend/local/config_test.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package local
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/restic/restic/internal/backend/test"
|
||||
)
|
||||
|
||||
var configTests = []test.ConfigTestData[Config]{
|
||||
{S: "local:/some/path", Cfg: Config{
|
||||
Path: "/some/path",
|
||||
Connections: 2,
|
||||
}},
|
||||
}
|
||||
|
||||
func TestParseConfig(t *testing.T) {
|
||||
test.ParseConfigTester(t, ParseConfig, configTests)
|
||||
}
|
|
@ -15,7 +15,7 @@ import (
|
|||
func newTestSuite(t testing.TB) *test.Suite[local.Config] {
|
||||
return &test.Suite[local.Config]{
|
||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||
NewConfig: func() (local.Config, error) {
|
||||
NewConfig: func() (*local.Config, error) {
|
||||
dir, err := os.MkdirTemp(rtest.TestTempDir, "restic-test-local-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -23,7 +23,7 @@ func newTestSuite(t testing.TB) *test.Suite[local.Config] {
|
|||
|
||||
t.Logf("create new backend at %v", dir)
|
||||
|
||||
cfg := local.Config{
|
||||
cfg := &local.Config{
|
||||
Path: dir,
|
||||
Connections: 2,
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ type parser struct {
|
|||
stripPassword func(string) string
|
||||
}
|
||||
|
||||
func configToAny[C any](parser func(string) (C, error)) func(string) (interface{}, error) {
|
||||
func configToAny[C any](parser func(string) (*C, error)) func(string) (interface{}, error) {
|
||||
return func(s string) (interface{}, error) {
|
||||
return parser(s)
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"local:/srv/repo",
|
||||
Location{Scheme: "local",
|
||||
Config: local.Config{
|
||||
Config: &local.Config{
|
||||
Path: "/srv/repo",
|
||||
Connections: 2,
|
||||
},
|
||||
|
@ -38,7 +38,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"local:dir1/dir2",
|
||||
Location{Scheme: "local",
|
||||
Config: local.Config{
|
||||
Config: &local.Config{
|
||||
Path: "dir1/dir2",
|
||||
Connections: 2,
|
||||
},
|
||||
|
@ -47,7 +47,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"local:dir1/dir2",
|
||||
Location{Scheme: "local",
|
||||
Config: local.Config{
|
||||
Config: &local.Config{
|
||||
Path: "dir1/dir2",
|
||||
Connections: 2,
|
||||
},
|
||||
|
@ -56,7 +56,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"dir1/dir2",
|
||||
Location{Scheme: "local",
|
||||
Config: local.Config{
|
||||
Config: &local.Config{
|
||||
Path: "dir1/dir2",
|
||||
Connections: 2,
|
||||
},
|
||||
|
@ -65,7 +65,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"/dir1/dir2",
|
||||
Location{Scheme: "local",
|
||||
Config: local.Config{
|
||||
Config: &local.Config{
|
||||
Path: "/dir1/dir2",
|
||||
Connections: 2,
|
||||
},
|
||||
|
@ -74,7 +74,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"local:../dir1/dir2",
|
||||
Location{Scheme: "local",
|
||||
Config: local.Config{
|
||||
Config: &local.Config{
|
||||
Path: "../dir1/dir2",
|
||||
Connections: 2,
|
||||
},
|
||||
|
@ -83,7 +83,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"/dir1/dir2",
|
||||
Location{Scheme: "local",
|
||||
Config: local.Config{
|
||||
Config: &local.Config{
|
||||
Path: "/dir1/dir2",
|
||||
Connections: 2,
|
||||
},
|
||||
|
@ -92,7 +92,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"/dir1:foobar/dir2",
|
||||
Location{Scheme: "local",
|
||||
Config: local.Config{
|
||||
Config: &local.Config{
|
||||
Path: "/dir1:foobar/dir2",
|
||||
Connections: 2,
|
||||
},
|
||||
|
@ -101,7 +101,7 @@ var parseTests = []struct {
|
|||
{
|
||||
`\dir1\foobar\dir2`,
|
||||
Location{Scheme: "local",
|
||||
Config: local.Config{
|
||||
Config: &local.Config{
|
||||
Path: `\dir1\foobar\dir2`,
|
||||
Connections: 2,
|
||||
},
|
||||
|
@ -110,7 +110,7 @@ var parseTests = []struct {
|
|||
{
|
||||
`c:\dir1\foobar\dir2`,
|
||||
Location{Scheme: "local",
|
||||
Config: local.Config{
|
||||
Config: &local.Config{
|
||||
Path: `c:\dir1\foobar\dir2`,
|
||||
Connections: 2,
|
||||
},
|
||||
|
@ -119,7 +119,7 @@ var parseTests = []struct {
|
|||
{
|
||||
`C:\Users\appveyor\AppData\Local\Temp\1\restic-test-879453535\repo`,
|
||||
Location{Scheme: "local",
|
||||
Config: local.Config{
|
||||
Config: &local.Config{
|
||||
Path: `C:\Users\appveyor\AppData\Local\Temp\1\restic-test-879453535\repo`,
|
||||
Connections: 2,
|
||||
},
|
||||
|
@ -128,7 +128,7 @@ var parseTests = []struct {
|
|||
{
|
||||
`c:/dir1/foobar/dir2`,
|
||||
Location{Scheme: "local",
|
||||
Config: local.Config{
|
||||
Config: &local.Config{
|
||||
Path: `c:/dir1/foobar/dir2`,
|
||||
Connections: 2,
|
||||
},
|
||||
|
@ -137,7 +137,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"sftp:user@host:/srv/repo",
|
||||
Location{Scheme: "sftp",
|
||||
Config: sftp.Config{
|
||||
Config: &sftp.Config{
|
||||
User: "user",
|
||||
Host: "host",
|
||||
Path: "/srv/repo",
|
||||
|
@ -148,7 +148,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"sftp:host:/srv/repo",
|
||||
Location{Scheme: "sftp",
|
||||
Config: sftp.Config{
|
||||
Config: &sftp.Config{
|
||||
User: "",
|
||||
Host: "host",
|
||||
Path: "/srv/repo",
|
||||
|
@ -159,7 +159,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"sftp://user@host/srv/repo",
|
||||
Location{Scheme: "sftp",
|
||||
Config: sftp.Config{
|
||||
Config: &sftp.Config{
|
||||
User: "user",
|
||||
Host: "host",
|
||||
Path: "srv/repo",
|
||||
|
@ -170,7 +170,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"sftp://user@host//srv/repo",
|
||||
Location{Scheme: "sftp",
|
||||
Config: sftp.Config{
|
||||
Config: &sftp.Config{
|
||||
User: "user",
|
||||
Host: "host",
|
||||
Path: "/srv/repo",
|
||||
|
@ -182,7 +182,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"s3://eu-central-1/bucketname",
|
||||
Location{Scheme: "s3",
|
||||
Config: s3.Config{
|
||||
Config: &s3.Config{
|
||||
Endpoint: "eu-central-1",
|
||||
Bucket: "bucketname",
|
||||
Prefix: "",
|
||||
|
@ -193,7 +193,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"s3://hostname.foo/bucketname",
|
||||
Location{Scheme: "s3",
|
||||
Config: s3.Config{
|
||||
Config: &s3.Config{
|
||||
Endpoint: "hostname.foo",
|
||||
Bucket: "bucketname",
|
||||
Prefix: "",
|
||||
|
@ -204,7 +204,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"s3://hostname.foo/bucketname/prefix/directory",
|
||||
Location{Scheme: "s3",
|
||||
Config: s3.Config{
|
||||
Config: &s3.Config{
|
||||
Endpoint: "hostname.foo",
|
||||
Bucket: "bucketname",
|
||||
Prefix: "prefix/directory",
|
||||
|
@ -215,7 +215,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"s3:eu-central-1/repo",
|
||||
Location{Scheme: "s3",
|
||||
Config: s3.Config{
|
||||
Config: &s3.Config{
|
||||
Endpoint: "eu-central-1",
|
||||
Bucket: "repo",
|
||||
Prefix: "",
|
||||
|
@ -226,7 +226,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"s3:eu-central-1/repo/prefix/directory",
|
||||
Location{Scheme: "s3",
|
||||
Config: s3.Config{
|
||||
Config: &s3.Config{
|
||||
Endpoint: "eu-central-1",
|
||||
Bucket: "repo",
|
||||
Prefix: "prefix/directory",
|
||||
|
@ -237,7 +237,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"s3:https://hostname.foo/repo",
|
||||
Location{Scheme: "s3",
|
||||
Config: s3.Config{
|
||||
Config: &s3.Config{
|
||||
Endpoint: "hostname.foo",
|
||||
Bucket: "repo",
|
||||
Prefix: "",
|
||||
|
@ -248,7 +248,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"s3:https://hostname.foo/repo/prefix/directory",
|
||||
Location{Scheme: "s3",
|
||||
Config: s3.Config{
|
||||
Config: &s3.Config{
|
||||
Endpoint: "hostname.foo",
|
||||
Bucket: "repo",
|
||||
Prefix: "prefix/directory",
|
||||
|
@ -259,7 +259,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"s3:http://hostname.foo/repo",
|
||||
Location{Scheme: "s3",
|
||||
Config: s3.Config{
|
||||
Config: &s3.Config{
|
||||
Endpoint: "hostname.foo",
|
||||
Bucket: "repo",
|
||||
Prefix: "",
|
||||
|
@ -271,7 +271,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"swift:container17:/",
|
||||
Location{Scheme: "swift",
|
||||
Config: swift.Config{
|
||||
Config: &swift.Config{
|
||||
Container: "container17",
|
||||
Prefix: "",
|
||||
Connections: 5,
|
||||
|
@ -281,7 +281,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"swift:container17:/prefix97",
|
||||
Location{Scheme: "swift",
|
||||
Config: swift.Config{
|
||||
Config: &swift.Config{
|
||||
Container: "container17",
|
||||
Prefix: "prefix97",
|
||||
Connections: 5,
|
||||
|
@ -291,7 +291,7 @@ var parseTests = []struct {
|
|||
{
|
||||
"rest:http://hostname.foo:1234/",
|
||||
Location{Scheme: "rest",
|
||||
Config: rest.Config{
|
||||
Config: &rest.Config{
|
||||
URL: parseURL("http://hostname.foo:1234/"),
|
||||
Connections: 5,
|
||||
},
|
||||
|
@ -299,7 +299,7 @@ var parseTests = []struct {
|
|||
},
|
||||
{
|
||||
"b2:bucketname:/prefix", Location{Scheme: "b2",
|
||||
Config: b2.Config{
|
||||
Config: &b2.Config{
|
||||
Bucket: "bucketname",
|
||||
Prefix: "prefix",
|
||||
Connections: 5,
|
||||
|
@ -308,7 +308,7 @@ var parseTests = []struct {
|
|||
},
|
||||
{
|
||||
"b2:bucketname", Location{Scheme: "b2",
|
||||
Config: b2.Config{
|
||||
Config: &b2.Config{
|
||||
Bucket: "bucketname",
|
||||
Prefix: "",
|
||||
Connections: 5,
|
||||
|
|
|
@ -18,8 +18,9 @@ type memConfig struct {
|
|||
func newTestSuite() *test.Suite[*memConfig] {
|
||||
return &test.Suite[*memConfig]{
|
||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||
NewConfig: func() (*memConfig, error) {
|
||||
return &memConfig{}, nil
|
||||
NewConfig: func() (**memConfig, error) {
|
||||
cfg := &memConfig{}
|
||||
return &cfg, nil
|
||||
},
|
||||
|
||||
// CreateFn is a function that creates a temporary repository for the tests.
|
||||
|
|
|
@ -17,11 +17,11 @@ func newTestSuite(t testing.TB) *test.Suite[rclone.Config] {
|
|||
|
||||
return &test.Suite[rclone.Config]{
|
||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||
NewConfig: func() (rclone.Config, error) {
|
||||
NewConfig: func() (*rclone.Config, error) {
|
||||
t.Logf("use backend at %v", dir)
|
||||
cfg := rclone.NewConfig()
|
||||
cfg.Remote = dir
|
||||
return cfg, nil
|
||||
return &cfg, nil
|
||||
},
|
||||
|
||||
// CreateFn is a function that creates a temporary repository for the tests.
|
||||
|
|
|
@ -34,13 +34,13 @@ func NewConfig() Config {
|
|||
}
|
||||
|
||||
// ParseConfig parses the string s and extracts the remote server URL.
|
||||
func ParseConfig(s string) (Config, error) {
|
||||
func ParseConfig(s string) (*Config, error) {
|
||||
if !strings.HasPrefix(s, "rclone:") {
|
||||
return Config{}, errors.New("invalid rclone backend specification")
|
||||
return nil, errors.New("invalid rclone backend specification")
|
||||
}
|
||||
|
||||
s = s[7:]
|
||||
cfg := NewConfig()
|
||||
cfg.Remote = s
|
||||
return cfg, nil
|
||||
return &cfg, nil
|
||||
}
|
||||
|
|
|
@ -26,21 +26,21 @@ func NewConfig() Config {
|
|||
}
|
||||
|
||||
// ParseConfig parses the string s and extracts the REST server URL.
|
||||
func ParseConfig(s string) (Config, error) {
|
||||
func ParseConfig(s string) (*Config, error) {
|
||||
if !strings.HasPrefix(s, "rest:") {
|
||||
return Config{}, errors.New("invalid REST backend specification")
|
||||
return nil, errors.New("invalid REST backend specification")
|
||||
}
|
||||
|
||||
s = prepareURL(s)
|
||||
|
||||
u, err := url.Parse(s)
|
||||
if err != nil {
|
||||
return Config{}, errors.WithStack(err)
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
cfg := NewConfig()
|
||||
cfg.URL = u
|
||||
return cfg, nil
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// StripPassword removes the password from the URL
|
||||
|
|
|
@ -77,10 +77,10 @@ func newTestSuite(_ context.Context, t testing.TB, url *url.URL, minimalData boo
|
|||
MinimalData: minimalData,
|
||||
|
||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||
NewConfig: func() (rest.Config, error) {
|
||||
NewConfig: func() (*rest.Config, error) {
|
||||
cfg := rest.NewConfig()
|
||||
cfg.URL = url
|
||||
return cfg, nil
|
||||
return &cfg, nil
|
||||
},
|
||||
|
||||
// CreateFn is a function that creates a temporary repository for the tests.
|
||||
|
|
|
@ -45,7 +45,7 @@ func init() {
|
|||
// supported configuration formats are s3://host/bucketname/prefix and
|
||||
// s3:host/bucketname/prefix. The host can also be a valid s3 region
|
||||
// name. If no prefix is given the prefix "restic" will be used.
|
||||
func ParseConfig(s string) (Config, error) {
|
||||
func ParseConfig(s string) (*Config, error) {
|
||||
switch {
|
||||
case strings.HasPrefix(s, "s3:http"):
|
||||
// assume that a URL has been specified, parse it and
|
||||
|
@ -53,11 +53,11 @@ func ParseConfig(s string) (Config, error) {
|
|||
// bucket name and prefix
|
||||
url, err := url.Parse(s[3:])
|
||||
if err != nil {
|
||||
return Config{}, errors.WithStack(err)
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
if url.Path == "" {
|
||||
return Config{}, errors.New("s3: bucket name not found")
|
||||
return nil, errors.New("s3: bucket name not found")
|
||||
}
|
||||
|
||||
bucket, path, _ := strings.Cut(url.Path[1:], "/")
|
||||
|
@ -67,7 +67,7 @@ func ParseConfig(s string) (Config, error) {
|
|||
case strings.HasPrefix(s, "s3:"):
|
||||
s = s[3:]
|
||||
default:
|
||||
return Config{}, errors.New("s3: invalid format")
|
||||
return nil, errors.New("s3: invalid format")
|
||||
}
|
||||
// use the first entry of the path as the endpoint and the
|
||||
// remainder as bucket name and prefix
|
||||
|
@ -76,9 +76,9 @@ func ParseConfig(s string) (Config, error) {
|
|||
return createConfig(endpoint, bucket, prefix, false)
|
||||
}
|
||||
|
||||
func createConfig(endpoint, bucket, prefix string, useHTTP bool) (Config, error) {
|
||||
func createConfig(endpoint, bucket, prefix string, useHTTP bool) (*Config, error) {
|
||||
if endpoint == "" {
|
||||
return Config{}, errors.New("s3: invalid format, host/region or bucket name not found")
|
||||
return nil, errors.New("s3: invalid format, host/region or bucket name not found")
|
||||
}
|
||||
|
||||
if prefix != "" {
|
||||
|
@ -90,7 +90,7 @@ func createConfig(endpoint, bucket, prefix string, useHTTP bool) (Config, error)
|
|||
cfg.UseHTTP = useHTTP
|
||||
cfg.Bucket = bucket
|
||||
cfg.Prefix = prefix
|
||||
return cfg, nil
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// ApplyEnvironment saves values from the environment to the config.
|
||||
|
|
|
@ -128,7 +128,7 @@ func newMinioTestSuite(ctx context.Context, t testing.TB) *test.Suite[MinioTestC
|
|||
|
||||
return &test.Suite[MinioTestConfig]{
|
||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||
NewConfig: func() (MinioTestConfig, error) {
|
||||
NewConfig: func() (*MinioTestConfig, error) {
|
||||
cfg := MinioTestConfig{}
|
||||
|
||||
cfg.tempdir = rtest.TempDir(t)
|
||||
|
@ -142,7 +142,7 @@ func newMinioTestSuite(ctx context.Context, t testing.TB) *test.Suite[MinioTestC
|
|||
cfg.Config.UseHTTP = true
|
||||
cfg.Config.KeyID = key
|
||||
cfg.Config.Secret = options.NewSecretString(secret)
|
||||
return cfg, nil
|
||||
return &cfg, nil
|
||||
},
|
||||
|
||||
// CreateFn is a function that creates a temporary repository for the tests.
|
||||
|
@ -224,10 +224,10 @@ func newS3TestSuite(t testing.TB) *test.Suite[s3.Config] {
|
|||
MinimalData: true,
|
||||
|
||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||
NewConfig: func() (s3.Config, error) {
|
||||
NewConfig: func() (*s3.Config, error) {
|
||||
cfg, err := s3.ParseConfig(os.Getenv("RESTIC_TEST_S3_REPOSITORY"))
|
||||
if err != nil {
|
||||
return s3.Config{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg.KeyID = os.Getenv("RESTIC_TEST_S3_KEY")
|
||||
|
|
|
@ -35,14 +35,14 @@ func init() {
|
|||
// and sftp:user@host:directory. The directory will be path Cleaned and can
|
||||
// be an absolute path if it starts with a '/' (e.g.
|
||||
// sftp://user@host//absolute and sftp:user@host:/absolute).
|
||||
func ParseConfig(s string) (Config, error) {
|
||||
func ParseConfig(s string) (*Config, error) {
|
||||
var user, host, port, dir string
|
||||
switch {
|
||||
case strings.HasPrefix(s, "sftp://"):
|
||||
// parse the "sftp://user@host/path" url format
|
||||
url, err := url.Parse(s)
|
||||
if err != nil {
|
||||
return Config{}, errors.WithStack(err)
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
if url.User != nil {
|
||||
user = url.User.Username()
|
||||
|
@ -51,7 +51,7 @@ func ParseConfig(s string) (Config, error) {
|
|||
port = url.Port()
|
||||
dir = url.Path
|
||||
if dir == "" {
|
||||
return Config{}, errors.Errorf("invalid backend %q, no directory specified", s)
|
||||
return nil, errors.Errorf("invalid backend %q, no directory specified", s)
|
||||
}
|
||||
|
||||
dir = dir[1:]
|
||||
|
@ -63,7 +63,7 @@ func ParseConfig(s string) (Config, error) {
|
|||
var colon bool
|
||||
host, dir, colon = strings.Cut(s, ":")
|
||||
if !colon {
|
||||
return Config{}, errors.New("sftp: invalid format, hostname or path not found")
|
||||
return nil, errors.New("sftp: invalid format, hostname or path not found")
|
||||
}
|
||||
// split user and host at the "@"
|
||||
data := strings.SplitN(host, "@", 3)
|
||||
|
@ -75,12 +75,12 @@ func ParseConfig(s string) (Config, error) {
|
|||
host = data[1]
|
||||
}
|
||||
default:
|
||||
return Config{}, errors.New(`invalid format, does not start with "sftp:"`)
|
||||
return nil, errors.New(`invalid format, does not start with "sftp:"`)
|
||||
}
|
||||
|
||||
p := path.Clean(dir)
|
||||
if strings.HasPrefix(p, "~") {
|
||||
return Config{}, errors.New("sftp path starts with the tilde (~) character, that fails for most sftp servers.\nUse a relative directory, most servers interpret this as relative to the user's home directory")
|
||||
return nil, errors.New("sftp path starts with the tilde (~) character, that fails for most sftp servers.\nUse a relative directory, most servers interpret this as relative to the user's home directory")
|
||||
}
|
||||
|
||||
cfg := NewConfig()
|
||||
|
@ -89,5 +89,5 @@ func ParseConfig(s string) (Config, error) {
|
|||
cfg.Port = port
|
||||
cfg.Path = p
|
||||
|
||||
return cfg, nil
|
||||
return &cfg, nil
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ var sftpServer = findSFTPServerBinary()
|
|||
func newTestSuite(t testing.TB) *test.Suite[sftp.Config] {
|
||||
return &test.Suite[sftp.Config]{
|
||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||
NewConfig: func() (sftp.Config, error) {
|
||||
NewConfig: func() (*sftp.Config, error) {
|
||||
dir, err := os.MkdirTemp(rtest.TestTempDir, "restic-test-sftp-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
@ -40,7 +40,7 @@ func newTestSuite(t testing.TB) *test.Suite[sftp.Config] {
|
|||
|
||||
t.Logf("create new backend at %v", dir)
|
||||
|
||||
cfg := sftp.Config{
|
||||
cfg := &sftp.Config{
|
||||
Path: dir,
|
||||
Command: fmt.Sprintf("%q -e", sftpServer),
|
||||
Connections: 5,
|
||||
|
|
|
@ -50,19 +50,19 @@ func NewConfig() Config {
|
|||
}
|
||||
|
||||
// ParseConfig parses the string s and extract swift's container name and prefix.
|
||||
func ParseConfig(s string) (Config, error) {
|
||||
func ParseConfig(s string) (*Config, error) {
|
||||
if !strings.HasPrefix(s, "swift:") {
|
||||
return Config{}, errors.New("invalid URL, expected: swift:container-name:/[prefix]")
|
||||
return nil, errors.New("invalid URL, expected: swift:container-name:/[prefix]")
|
||||
}
|
||||
s = strings.TrimPrefix(s, "swift:")
|
||||
|
||||
container, prefix, _ := strings.Cut(s, ":")
|
||||
if prefix == "" {
|
||||
return Config{}, errors.Errorf("prefix is empty")
|
||||
return nil, errors.Errorf("prefix is empty")
|
||||
}
|
||||
|
||||
if prefix[0] != '/' {
|
||||
return Config{}, errors.Errorf("prefix does not start with slash (/)")
|
||||
return nil, errors.Errorf("prefix does not start with slash (/)")
|
||||
}
|
||||
prefix = prefix[1:]
|
||||
|
||||
|
@ -70,7 +70,7 @@ func ParseConfig(s string) (Config, error) {
|
|||
cfg.Container = container
|
||||
cfg.Prefix = prefix
|
||||
|
||||
return cfg, nil
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
// ApplyEnvironment saves values from the environment to the config.
|
||||
|
|
|
@ -42,14 +42,14 @@ func newSwiftTestSuite(t testing.TB) *test.Suite[swift.Config] {
|
|||
},
|
||||
|
||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||
NewConfig: func() (swift.Config, error) {
|
||||
NewConfig: func() (*swift.Config, error) {
|
||||
cfg, err := swift.ParseConfig(os.Getenv("RESTIC_TEST_SWIFT"))
|
||||
if err != nil {
|
||||
return swift.Config{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = swift.ApplyEnvironment("RESTIC_TEST_", &cfg); err != nil {
|
||||
return swift.Config{}, err
|
||||
return nil, err
|
||||
}
|
||||
cfg.Prefix += fmt.Sprintf("/test-%d", time.Now().UnixNano())
|
||||
t.Logf("using prefix %v", cfg.Prefix)
|
||||
|
|
|
@ -11,7 +11,7 @@ type ConfigTestData[C comparable] struct {
|
|||
Cfg C
|
||||
}
|
||||
|
||||
func ParseConfigTester[C comparable](t *testing.T, parser func(s string) (C, error), tests []ConfigTestData[C]) {
|
||||
func ParseConfigTester[C comparable](t *testing.T, parser func(s string) (*C, error), tests []ConfigTestData[C]) {
|
||||
for i, test := range tests {
|
||||
t.Run(fmt.Sprint(i), func(t *testing.T) {
|
||||
cfg, err := parser(test.S)
|
||||
|
@ -19,9 +19,9 @@ func ParseConfigTester[C comparable](t *testing.T, parser func(s string) (C, err
|
|||
t.Fatalf("%s failed: %v", test.S, err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cfg, test.Cfg) {
|
||||
if !reflect.DeepEqual(*cfg, test.Cfg) {
|
||||
t.Fatalf("input: %s\n wrong config, want:\n %#v\ngot:\n %#v",
|
||||
test.S, test.Cfg, cfg)
|
||||
test.S, test.Cfg, *cfg)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -13,10 +13,10 @@ import (
|
|||
// Suite implements a test suite for restic backends.
|
||||
type Suite[C any] struct {
|
||||
// Config should be used to configure the backend.
|
||||
Config C
|
||||
Config *C
|
||||
|
||||
// NewConfig returns a config for a new temporary backend that will be used in tests.
|
||||
NewConfig func() (C, error)
|
||||
NewConfig func() (*C, error)
|
||||
|
||||
// CreateFn is a function that creates a temporary repository for the tests.
|
||||
Create func(cfg C) (restic.Backend, error)
|
||||
|
@ -61,7 +61,7 @@ func (s *Suite[C]) RunTests(t *testing.T) {
|
|||
}
|
||||
|
||||
if s.Cleanup != nil {
|
||||
if err = s.Cleanup(s.Config); err != nil {
|
||||
if err = s.Cleanup(*s.Config); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
@ -158,13 +158,13 @@ func (s *Suite[C]) RunBenchmarks(b *testing.B) {
|
|||
return
|
||||
}
|
||||
|
||||
if err = s.Cleanup(s.Config); err != nil {
|
||||
if err = s.Cleanup(*s.Config); err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Suite[C]) create(t testing.TB) restic.Backend {
|
||||
be, err := s.Create(s.Config)
|
||||
be, err := s.Create(*s.Config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ func (s *Suite[C]) create(t testing.TB) restic.Backend {
|
|||
}
|
||||
|
||||
func (s *Suite[C]) open(t testing.TB) restic.Backend {
|
||||
be, err := s.Open(s.Config)
|
||||
be, err := s.Open(*s.Config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ func (s *Suite[C]) TestCreateWithConfig(t *testing.T) {
|
|||
store(t, b, restic.ConfigFile, []byte("test config"))
|
||||
|
||||
// now create the backend again, this must fail
|
||||
_, err = s.Create(s.Config)
|
||||
_, err = s.Create(*s.Config)
|
||||
if err == nil {
|
||||
t.Fatalf("expected error not found for creating a backend with an existing config file")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue