summaryrefslogtreecommitdiff
path: root/parse.go
diff options
context:
space:
mode:
Diffstat (limited to 'parse.go')
-rw-r--r--parse.go78
1 files changed, 66 insertions, 12 deletions
diff --git a/parse.go b/parse.go
index b58b51e..74b9175 100644
--- a/parse.go
+++ b/parse.go
@@ -2,6 +2,7 @@ package arguments
import (
"fmt"
+ "log"
"os"
"reflect"
"strconv"
@@ -82,6 +83,7 @@ func extractSpec(t reflect.Type) ([]*spec, error) {
// Get the scalar type for this field
scalarType := field.Type
+ log.Println(field.Name, field.Type, field.Type.Kind())
if scalarType.Kind() == reflect.Slice {
spec.multiple = true
scalarType = scalarType.Elem()
@@ -133,14 +135,17 @@ func extractSpec(t reflect.Type) ([]*spec, error) {
// processArgs processes arguments using a pre-constructed spec
func processArgs(dest reflect.Value, specs []*spec, args []string) error {
- // construct a map from arg name to spec
- specByName := make(map[string]*spec)
+ // construct a map from --option to spec
+ optionMap := make(map[string]*spec)
for _, spec := range specs {
+ if spec.positional {
+ continue
+ }
if spec.long != "" {
- specByName[spec.long] = spec
+ optionMap[spec.long] = spec
}
if spec.short != "" {
- specByName[spec.short] = spec
+ optionMap[spec.short] = spec
}
}
@@ -170,7 +175,7 @@ func processArgs(dest reflect.Value, specs []*spec, args []string) error {
}
// lookup the spec for this option
- spec, ok := specByName[opt]
+ spec, ok := optionMap[opt]
if !ok {
return fmt.Errorf("unknown argument %s", arg)
}
@@ -180,13 +185,17 @@ func processArgs(dest reflect.Value, specs []*spec, args []string) error {
if spec.multiple {
var values []string
if value == "" {
- for i++; i < len(args) && !strings.HasPrefix(args[i], "-"); i++ {
- values = append(values, args[i])
+ for i+1 < len(args) && !strings.HasPrefix(args[i+1], "-") {
+ values = append(values, args[i+1])
+ i++
}
} else {
values = append(values, value)
}
- setSlice(dest, spec, values)
+ err := setSlice(dest.Field(spec.index), values)
+ if err != nil {
+ return fmt.Errorf("error processing %s: %v", arg, err)
+ }
continue
}
@@ -209,13 +218,38 @@ func processArgs(dest reflect.Value, specs []*spec, args []string) error {
return fmt.Errorf("error processing %s: %v", arg, err)
}
}
+
+ // process positionals
+ for _, spec := range specs {
+ label := strings.ToLower(spec.field.Name)
+ if spec.positional {
+ if spec.multiple {
+ err := setSlice(dest.Field(spec.index), positionals)
+ if err != nil {
+ return fmt.Errorf("error processing %s: %v", label, err)
+ }
+ positionals = nil
+ } else if len(positionals) > 0 {
+ err := setScalar(dest.Field(spec.index), positionals[0])
+ if err != nil {
+ return fmt.Errorf("error processing %s: %v", label, err)
+ }
+ positionals = positionals[1:]
+ } else if spec.required {
+ return fmt.Errorf("%s is required", label)
+ }
+ }
+ }
+ if len(positionals) > 0 {
+ return fmt.Errorf("too many positional arguments at '%s'", positionals[0])
+ }
return nil
}
// validate an argument spec after arguments have been parse
func validate(spec []*spec) error {
for _, arg := range spec {
- if arg.required && !arg.wasPresent {
+ if !arg.positional && arg.required && !arg.wasPresent {
return fmt.Errorf("--%s is required", strings.ToLower(arg.field.Name))
}
}
@@ -223,15 +257,35 @@ func validate(spec []*spec) error {
}
// parse a value as the apropriate type and store it in the struct
-func setSlice(dest reflect.Value, spec *spec, values []string) error {
- // TODO
+func setSlice(dest reflect.Value, values []string) error {
+ if !dest.CanSet() {
+ return fmt.Errorf("field is not writable")
+ }
+
+ var ptr bool
+ elem := dest.Type().Elem()
+ if elem.Kind() == reflect.Ptr {
+ ptr = true
+ elem = elem.Elem()
+ }
+
+ for _, s := range values {
+ v := reflect.New(elem)
+ if err := setScalar(v.Elem(), s); err != nil {
+ return err
+ }
+ if ptr {
+ v = v.Addr()
+ }
+ dest.Set(reflect.Append(dest, v.Elem()))
+ }
return nil
}
// set a value from a string
func setScalar(v reflect.Value, s string) error {
if !v.CanSet() {
- return fmt.Errorf("field is not writable")
+ return fmt.Errorf("field is not exported")
}
switch v.Kind() {