mirror of
https://github.com/octoleo/syncthing.git
synced 2024-11-09 14:50:56 +00:00
126 lines
2.2 KiB
Go
126 lines
2.2 KiB
Go
|
package flags
|
||
|
|
||
|
import (
|
||
|
"reflect"
|
||
|
)
|
||
|
|
||
|
// Set the value of an option to the specified value. An error will be returned
|
||
|
// if the specified value could not be converted to the corresponding option
|
||
|
// value type.
|
||
|
func (option *Option) set(value *string) error {
|
||
|
if option.isFunc() {
|
||
|
return option.call(value)
|
||
|
} else if value != nil {
|
||
|
return convert(*value, option.value, option.tag)
|
||
|
} else {
|
||
|
return convert("", option.value, option.tag)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (option *Option) canCli() bool {
|
||
|
return option.ShortName != 0 || len(option.LongName) != 0
|
||
|
}
|
||
|
|
||
|
func (option *Option) canArgument() bool {
|
||
|
if u := option.isUnmarshaler(); u != nil {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
return !option.isBool()
|
||
|
}
|
||
|
|
||
|
func (option *Option) clear() {
|
||
|
tp := option.value.Type()
|
||
|
|
||
|
switch tp.Kind() {
|
||
|
case reflect.Func:
|
||
|
// Skip
|
||
|
case reflect.Map:
|
||
|
// Empty the map
|
||
|
option.value.Set(reflect.MakeMap(tp))
|
||
|
default:
|
||
|
zeroval := reflect.Zero(tp)
|
||
|
option.value.Set(zeroval)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (option *Option) isUnmarshaler() Unmarshaler {
|
||
|
v := option.value
|
||
|
|
||
|
for {
|
||
|
if !v.CanInterface() {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
i := v.Interface()
|
||
|
|
||
|
if u, ok := i.(Unmarshaler); ok {
|
||
|
return u
|
||
|
}
|
||
|
|
||
|
if !v.CanAddr() {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
v = v.Addr()
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (option *Option) isBool() bool {
|
||
|
tp := option.value.Type()
|
||
|
|
||
|
for {
|
||
|
switch tp.Kind() {
|
||
|
case reflect.Bool:
|
||
|
return true
|
||
|
case reflect.Slice:
|
||
|
return (tp.Elem().Kind() == reflect.Bool)
|
||
|
case reflect.Func:
|
||
|
return tp.NumIn() == 0
|
||
|
case reflect.Ptr:
|
||
|
tp = tp.Elem()
|
||
|
default:
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
func (option *Option) isFunc() bool {
|
||
|
return option.value.Type().Kind() == reflect.Func
|
||
|
}
|
||
|
|
||
|
func (option *Option) call(value *string) error {
|
||
|
var retval []reflect.Value
|
||
|
|
||
|
if value == nil {
|
||
|
retval = option.value.Call(nil)
|
||
|
} else {
|
||
|
tp := option.value.Type().In(0)
|
||
|
|
||
|
val := reflect.New(tp)
|
||
|
val = reflect.Indirect(val)
|
||
|
|
||
|
if err := convert(*value, val, option.tag); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
retval = option.value.Call([]reflect.Value{val})
|
||
|
}
|
||
|
|
||
|
if len(retval) == 1 && retval[0].Type() == reflect.TypeOf((*error)(nil)).Elem() {
|
||
|
if retval[0].Interface() == nil {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
return retval[0].Interface().(error)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|