You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

138 lines
3.3 KiB
Go

package moon
import (
"fmt"
"os"
"reflect"
"strings"
)
func parseArgs(args []string, dest interface{}) (*Object, error) {
reqs, err := requirements(reflect.TypeOf(dest))
if err != nil {
return nil, fmt.Errorf("unable to parse args: bad requirements: %s", err)
}
out := Object{items: make(map[string]interface{})}
shorts := make(map[string]req, len(reqs))
longs := make(map[string]req, len(reqs))
for _, req := range reqs {
if req.short != "" {
shorts[req.short] = req
}
if req.long != "" {
longs[req.long] = req
}
}
for i := 1; i < len(args); i++ {
arg := args[i]
if arg == "help" {
showHelp(dest)
}
if arg == "--" {
break
}
if strings.HasPrefix(arg, "--") {
arg = strings.TrimPrefix(arg, "--")
var (
key string
val string
)
if strings.ContainsRune(arg, '=') {
parts := strings.SplitN(arg, "=", 2)
key, val = parts[0], parts[1]
} else {
key = arg
i++
if i >= len(args) {
return nil, fmt.Errorf("terminal arg %s is missing a value", key)
}
val = args[i]
}
req, ok := longs[key]
if !ok {
return nil, fmt.Errorf("unrecognized long opt: %s", key)
}
if req.t.Kind() == reflect.Bool {
out.items[req.name] = true
continue
}
// this is horrible
d, err := ReadString(fmt.Sprintf("%s: %s", key, val)) // :(
if err != nil {
return nil, fmt.Errorf("unable to parse cli argument %s: %s", key, err)
}
out.items[req.name] = d.items[key]
} else if strings.HasPrefix(arg, "-") {
arg = strings.TrimPrefix(arg, "-")
if strings.ContainsRune(arg, '=') {
runes := []rune(arg)
if len(runes) == 1 { // -=
// no clue what to do here
return nil, fmt.Errorf("unable to parse cli arguments: weird -=?")
}
if runes[1] != '=' {
return nil, fmt.Errorf("you may only use one short flag with an equals sign")
}
req, ok := shorts[string(runes[0])]
if !ok {
return nil, fmt.Errorf("unrecognized short opt: %c", runes[0])
}
d, err := ReadString(fmt.Sprintf("key: %s", runes[2:]))
if err != nil {
return nil, fmt.Errorf("unable to parse cli argument %c: %s", runes[0], err)
}
out.items[req.name] = d.items["key"]
} else {
runes := []rune(arg)
for j := 0; j < len(runes); j++ {
r := runes[j]
req, ok := shorts[string(r)]
if !ok {
return nil, fmt.Errorf("unrecognized short opt: %c", r)
}
if req.t.Kind() == reflect.Bool {
out.items[req.name] = true
continue
}
if j != len(runes)-1 {
// what a totally fucking preposterous error message
return nil, fmt.Errorf("illegal short opt: %c: a "+
"non-boolean short flag may only appear as the"+
" terminal option in a run of short opts", r)
}
i++
if i >= len(args) {
return nil, fmt.Errorf("arg %s is missing a value", req.name)
}
val := args[i]
d, err := ReadString(fmt.Sprintf("key: %s", val))
if err != nil {
return nil, fmt.Errorf("error parsing cli arg %s: %s", req.name, err)
}
out.items[req.name] = d.items["key"]
}
}
} else {
break
}
}
return &out, nil
}
func showHelp(dest interface{}) {
reqs, err := requirements(reflect.TypeOf(dest))
if err != nil {
panic(err)
}
for _, req := range reqs {
req.writeHelpLine(os.Stdout)
}
os.Exit(1)
}