parent
407c5225bc
commit
0a2edd9fc4
@ -0,0 +1,92 @@
|
|||||||
|
package moon
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type req struct {
|
||||||
|
name string // name as it appears in moon config file. Defaults to the field name.
|
||||||
|
cliName string // name as it appears on the command line
|
||||||
|
help string // text given in help documentation
|
||||||
|
required bool // whether or not the option must be configured
|
||||||
|
d_fault interface{} // default value for when the option is missing
|
||||||
|
short string // short flag on the command line
|
||||||
|
long string // long flag on the command line
|
||||||
|
flag bool // whether or not the variable is a flag.
|
||||||
|
t reflect.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r req) validate() error {
|
||||||
|
if r.name == "" {
|
||||||
|
return fmt.Errorf("invalid requirement: requirement must have a name")
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.required && r.flag {
|
||||||
|
return fmt.Errorf("invalid requirement %s: a flag cannot be required", r.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.required && r.d_fault != nil {
|
||||||
|
return fmt.Errorf("invalid requirement %s: a required value cannot have a default", r.name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func field2req(field reflect.StructField) (*req, error) {
|
||||||
|
doc, err := ReadString(string(field.Tag))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to parse requirements for field %s: %s", field.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := req{
|
||||||
|
name: field.Name,
|
||||||
|
cliName: field.Name,
|
||||||
|
t: field.Type,
|
||||||
|
}
|
||||||
|
// it's really easy to cause infinite recursion here, since this is used by
|
||||||
|
// some of the higher up functions, so we're going to hack the document directly
|
||||||
|
|
||||||
|
errors := map[string]error{
|
||||||
|
"name": doc.Get("name", &req.name),
|
||||||
|
"cli_name": doc.Get("cli_name", &req.cliName),
|
||||||
|
"help": doc.Get("help", &req.help),
|
||||||
|
"required": doc.Get("required", &req.required),
|
||||||
|
"default": doc.Get("default", &req.d_fault),
|
||||||
|
"short": doc.Get("short", &req.short),
|
||||||
|
"long": doc.Get("long", &req.long),
|
||||||
|
"flag": doc.Get("flag", &req.flag),
|
||||||
|
}
|
||||||
|
|
||||||
|
for fname, err := range errors {
|
||||||
|
if err == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, ok := err.(NoValue); !ok {
|
||||||
|
return nil, fmt.Errorf("unable to parse requirement %s: %s", fname, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &req, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func requirements(dest interface{}) (map[string]req, error) {
|
||||||
|
dt := reflect.TypeOf(dest)
|
||||||
|
if dt.Kind() != reflect.Ptr {
|
||||||
|
return nil, fmt.Errorf("destination is of type %v; a pointer type is required", dt)
|
||||||
|
}
|
||||||
|
|
||||||
|
dv := reflect.ValueOf(dest).Elem()
|
||||||
|
n := dv.NumField()
|
||||||
|
out := make(map[string]req, dv.NumField())
|
||||||
|
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
field := dv.Type().Field(i)
|
||||||
|
req, err := field2req(field)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to gather requireents for field %s: %s", field.Name, err)
|
||||||
|
}
|
||||||
|
out[field.Name] = *req
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
Loading…
Reference in New Issue