This commit is contained in:
Alexander Neumann 2018-05-14 23:21:24 +02:00
parent 8d21bb92db
commit abb1dc4eb6
5 changed files with 97 additions and 55 deletions

View File

@ -27,9 +27,25 @@ type Config struct {
// Backend configures a backend.
type Backend struct {
Type string `hcl:"type"`
User string `hcl:"user" valid_for:"sftp"`
Host string `hcl:"host" valid_for:"sftp"`
Path string `hcl:"path" valid_for:"sftp,local"`
*BackendLocal `hcl:"-" json:"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.
@ -166,58 +182,49 @@ func parseBackends(root *ast.ObjectList) (map[string]Backend, error) {
be.Type = "local"
}
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)
var target interface{}
switch be.Type {
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
innerBlock, ok := obj.Val.(*ast.ObjectType)
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)
}
// check valid fields
err = validateObjects(innerBlock.List, validBackendFieldNames(be.Type))
// check allowed types
err = validateObjects(innerBlock.List, listTags(target, "hcl"))
if err != nil {
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
}
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.
func Load(filename string) (Config, error) {
buf, err := ioutil.ReadFile(filename)
@ -351,3 +358,8 @@ func ApplyEnv(cfg interface{}, env []string) error {
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")
}

View File

@ -100,6 +100,22 @@ func TestInvalidConfigs(t *testing.T) {
}`,
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 {

View File

@ -5,21 +5,29 @@
"Backends": {
"local": {
"Type": "local",
"User": "",
"Host": "",
"Path": "/foo/bar"
"local": {
"Type": "local",
"Path": "/foo/bar"
},
"sftp": null
},
"local2": {
"Type": "local",
"User": "",
"Host": "",
"Path": "/foo/bar"
"local": {
"Type": "",
"Path": "/foo/bar"
},
"sftp": null
},
"sftp": {
"Type": "sftp",
"User": "foo",
"Host": "bar",
"Path": "/foo/bar"
"local": null,
"sftp": {
"Type": "sftp",
"User": "foo",
"Host": "bar",
"Path": "/foo/bar"
}
}
},
"Backup": {

View File

@ -5,15 +5,19 @@
"Backends": {
"bar": {
"Type": "local",
"User": "",
"Host": "",
"Path": "/srv/data/repo"
"local": {
"Type": "",
"Path": "/srv/data/repo"
},
"sftp": null
},
"foo": {
"Type": "local",
"User": "",
"Host": "",
"Path": "/srv/data/repo"
"local": {
"Type": "local",
"Path": "/srv/data/repo"
},
"sftp": null
}
},
"Backup": {

View File

@ -5,9 +5,11 @@
"Backends": {
"test": {
"Type": "local",
"User": "",
"Host": "",
"Path": "/foo/bar/baz"
"local": {
"Type": "local",
"Path": "/foo/bar/baz"
},
"sftp": null
}
},
"Backup": {