forked from TrueCloudLab/restic
wip
This commit is contained in:
parent
8d21bb92db
commit
abb1dc4eb6
5 changed files with 97 additions and 55 deletions
|
@ -27,9 +27,25 @@ type Config struct {
|
||||||
// Backend configures a backend.
|
// Backend configures a backend.
|
||||||
type Backend struct {
|
type Backend struct {
|
||||||
Type string `hcl:"type"`
|
Type string `hcl:"type"`
|
||||||
User string `hcl:"user" valid_for:"sftp"`
|
|
||||||
Host string `hcl:"host" valid_for:"sftp"`
|
*BackendLocal `hcl:"-" json:"local"`
|
||||||
Path string `hcl:"path" valid_for:"sftp,local"`
|
*BackendSFTP `hcl:"-" json:"sftp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BackendLocal configures a local backend.
|
||||||
|
type BackendLocal struct {
|
||||||
|
Type string `hcl:"type"`
|
||||||
|
|
||||||
|
Path string `hcl:"path"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BackendSFTP configures an sftp backend.
|
||||||
|
type BackendSFTP struct {
|
||||||
|
Type string `hcl:"type"`
|
||||||
|
|
||||||
|
User string `hcl:"user"`
|
||||||
|
Host string `hcl:"host"`
|
||||||
|
Path string `hcl:"path"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backup sets the options for the "backup" command.
|
// Backup sets the options for the "backup" command.
|
||||||
|
@ -166,58 +182,49 @@ func parseBackends(root *ast.ObjectList) (map[string]Backend, error) {
|
||||||
be.Type = "local"
|
be.Type = "local"
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := backends[name]; ok {
|
var target interface{}
|
||||||
return nil, errors.Errorf("backend %q at line %v, column %v already configured",
|
switch be.Type {
|
||||||
name, obj.Pos().Line, obj.Pos().Column)
|
case "local":
|
||||||
|
be.BackendLocal = &BackendLocal{}
|
||||||
|
target = be.BackendLocal
|
||||||
|
case "sftp":
|
||||||
|
be.BackendSFTP = &BackendSFTP{}
|
||||||
|
target = be.BackendSFTP
|
||||||
|
default:
|
||||||
|
return nil, errors.Errorf("unknown backend type %q at line %v, column %v",
|
||||||
|
be.Type, obj.Pos().Line, obj.Pos().Column)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check structure of the backend object
|
// check structure of the backend object
|
||||||
innerBlock, ok := obj.Val.(*ast.ObjectType)
|
innerBlock, ok := obj.Val.(*ast.ObjectType)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.Errorf("unable to verify structure of backend %q at line %v, column %v already configured",
|
return nil, errors.Errorf("unable to verify structure of backend %q at line %v, column %v",
|
||||||
name, obj.Pos().Line, obj.Pos().Column)
|
name, obj.Pos().Line, obj.Pos().Column)
|
||||||
}
|
}
|
||||||
|
|
||||||
// check valid fields
|
// check allowed types
|
||||||
err = validateObjects(innerBlock.List, validBackendFieldNames(be.Type))
|
err = validateObjects(innerBlock.List, listTags(target, "hcl"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = hcl.DecodeObject(target, innerBlock)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Errorf("parsing backend %q (type %s) at line %v, column %v failed: %v",
|
||||||
|
name, be.Type, obj.Pos().Line, obj.Pos().Column, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := backends[name]; ok {
|
||||||
|
return nil, errors.Errorf("backend %q at line %v, column %v already configured",
|
||||||
|
name, obj.Pos().Line, obj.Pos().Column)
|
||||||
|
}
|
||||||
|
|
||||||
backends[name] = be
|
backends[name] = be
|
||||||
}
|
}
|
||||||
|
|
||||||
return backends, nil
|
return backends, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// validBackendFieldNames returns a set of names of valid options for the backend type be.
|
|
||||||
func validBackendFieldNames(be string) map[string]struct{} {
|
|
||||||
target := Backend{}
|
|
||||||
vi := reflect.ValueOf(target)
|
|
||||||
|
|
||||||
attr := make(map[string]struct{})
|
|
||||||
for i := 0; i < vi.NumField(); i++ {
|
|
||||||
typeField := vi.Type().Field(i)
|
|
||||||
tag := typeField.Tag.Get("valid_for")
|
|
||||||
name := typeField.Tag.Get("hcl")
|
|
||||||
|
|
||||||
if tag == "" {
|
|
||||||
// if the tag is not specified, it's valid for all backend types
|
|
||||||
attr[name] = struct{}{}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, v := range strings.Split(tag, ",") {
|
|
||||||
if be == v {
|
|
||||||
attr[name] = struct{}{}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return attr
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load loads a config from a file.
|
// Load loads a config from a file.
|
||||||
func Load(filename string) (Config, error) {
|
func Load(filename string) (Config, error) {
|
||||||
buf, err := ioutil.ReadFile(filename)
|
buf, err := ioutil.ReadFile(filename)
|
||||||
|
@ -351,3 +358,8 @@ func ApplyEnv(cfg interface{}, env []string) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ApplyOptions takes a list of Options and applies them to the config.
|
||||||
|
func ApplyOptions(cfg interface{}, opts map[string]string) error {
|
||||||
|
return errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
|
@ -100,6 +100,22 @@ func TestInvalidConfigs(t *testing.T) {
|
||||||
}`,
|
}`,
|
||||||
err: `unknown option "user"`,
|
err: `unknown option "user"`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
config: `backend "foo" {
|
||||||
|
path = "/foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
backend "foo" {
|
||||||
|
path = "/bar"
|
||||||
|
}`,
|
||||||
|
err: `backend "foo" already configured`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
config: `backend "foo" {
|
||||||
|
type = "xxx"
|
||||||
|
}`,
|
||||||
|
err: `unknown backend type "xxx"`,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
|
26
internal/ui/config/testdata/all.golden
vendored
26
internal/ui/config/testdata/all.golden
vendored
|
@ -5,21 +5,29 @@
|
||||||
"Backends": {
|
"Backends": {
|
||||||
"local": {
|
"local": {
|
||||||
"Type": "local",
|
"Type": "local",
|
||||||
"User": "",
|
"local": {
|
||||||
"Host": "",
|
"Type": "local",
|
||||||
"Path": "/foo/bar"
|
"Path": "/foo/bar"
|
||||||
|
},
|
||||||
|
"sftp": null
|
||||||
},
|
},
|
||||||
"local2": {
|
"local2": {
|
||||||
"Type": "local",
|
"Type": "local",
|
||||||
"User": "",
|
"local": {
|
||||||
"Host": "",
|
"Type": "",
|
||||||
"Path": "/foo/bar"
|
"Path": "/foo/bar"
|
||||||
|
},
|
||||||
|
"sftp": null
|
||||||
},
|
},
|
||||||
"sftp": {
|
"sftp": {
|
||||||
"Type": "sftp",
|
"Type": "sftp",
|
||||||
"User": "foo",
|
"local": null,
|
||||||
"Host": "bar",
|
"sftp": {
|
||||||
"Path": "/foo/bar"
|
"Type": "sftp",
|
||||||
|
"User": "foo",
|
||||||
|
"Host": "bar",
|
||||||
|
"Path": "/foo/bar"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Backup": {
|
"Backup": {
|
||||||
|
|
16
internal/ui/config/testdata/backend-local.golden
vendored
16
internal/ui/config/testdata/backend-local.golden
vendored
|
@ -5,15 +5,19 @@
|
||||||
"Backends": {
|
"Backends": {
|
||||||
"bar": {
|
"bar": {
|
||||||
"Type": "local",
|
"Type": "local",
|
||||||
"User": "",
|
"local": {
|
||||||
"Host": "",
|
"Type": "",
|
||||||
"Path": "/srv/data/repo"
|
"Path": "/srv/data/repo"
|
||||||
|
},
|
||||||
|
"sftp": null
|
||||||
},
|
},
|
||||||
"foo": {
|
"foo": {
|
||||||
"Type": "local",
|
"Type": "local",
|
||||||
"User": "",
|
"local": {
|
||||||
"Host": "",
|
"Type": "local",
|
||||||
"Path": "/srv/data/repo"
|
"Path": "/srv/data/repo"
|
||||||
|
},
|
||||||
|
"sftp": null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Backup": {
|
"Backup": {
|
||||||
|
|
|
@ -5,9 +5,11 @@
|
||||||
"Backends": {
|
"Backends": {
|
||||||
"test": {
|
"test": {
|
||||||
"Type": "local",
|
"Type": "local",
|
||||||
"User": "",
|
"local": {
|
||||||
"Host": "",
|
"Type": "local",
|
||||||
"Path": "/foo/bar/baz"
|
"Path": "/foo/bar/baz"
|
||||||
|
},
|
||||||
|
"sftp": null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Backup": {
|
"Backup": {
|
||||||
|
|
Loading…
Reference in a new issue