diff options
| author | Alex Flint <[email protected]> | 2015-10-31 17:05:14 -0700 |
|---|---|---|
| committer | Alex Flint <[email protected]> | 2015-10-31 17:05:14 -0700 |
| commit | 8397a40f4cafd39c553df848854e022d33149fa5 (patch) | |
| tree | 1fa29ba484cac0114c072ed8da44e785c2c901d6 /parse.go | |
| parent | 408290f7c2a968a0de255813e125a9ebb0a9dda6 (diff) | |
positional arguments working
Diffstat (limited to 'parse.go')
| -rw-r--r-- | parse.go | 78 |
1 files changed, 66 insertions, 12 deletions
@@ -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() { |
