parsing of short args

master
Jordan Orelli 10 years ago
parent ed40455f5d
commit 3e1fd7eef5

@ -2,7 +2,6 @@ package moon
import ( import (
"fmt" "fmt"
"log"
"os" "os"
"reflect" "reflect"
"strings" "strings"
@ -55,22 +54,69 @@ func parseArgs(args []string, dest interface{}) (map[string]interface{}, error)
req, ok := longs[key] req, ok := longs[key]
if !ok { if !ok {
// ignore unknown options silently? return nil, fmt.Errorf("unrecognized long opt: %s", key)
log.Printf("no such long opt: %s", key)
continue
} }
if req.t.Kind() == reflect.Bool { if req.t.Kind() == reflect.Bool {
out[key] = true out[req.name] = true
continue continue
} }
// this is horrible
d, err := ReadString(fmt.Sprintf("%s: %s", key, val)) // :( d, err := ReadString(fmt.Sprintf("%s: %s", key, val)) // :(
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to parse cli argument %s: %s", key, err) return nil, fmt.Errorf("unable to parse cli argument %s: %s", key, err)
} }
out[key] = d.items[key] out[req.name] = d.items[key]
} else if strings.HasPrefix(arg, "-") { } else if strings.HasPrefix(arg, "-") {
panic("i'm not doing short args yet") 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[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[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[req.name] = d.items["key"]
}
}
} else { } else {
break break
} }

@ -8,10 +8,13 @@ func TestArgs(t *testing.T) {
var one struct { var one struct {
Host string `name: host; short: h; default: localhost` Host string `name: host; short: h; default: localhost`
Port int `name: port; short: p; required: true` Port int `name: port; short: p; required: true`
User string `name: user; short: u`
ZipIt bool `name: zip; short: z`
Verbose bool `name: verbose; short: v`
UseSSL bool `name: ssl_enabled; long: ssl-enabled` UseSSL bool `name: ssl_enabled; long: ssl-enabled`
CertPath string `name: ssl_cert; long: ssl-cert` CertPath string `name: ssl_cert; long: ssl-cert`
} }
args := []string{"program", "--host=example.com", "--port", "9000"} args := []string{"program", "--host=example.com", "--port", "9000", "-u", "fart", "-zv"}
vals, err := parseArgs(args, &one) vals, err := parseArgs(args, &one)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
@ -25,4 +28,16 @@ func TestArgs(t *testing.T) {
if vals["port"] != 9000 { if vals["port"] != 9000 {
t.Errorf("expected port 9000, saw port %d", vals["port"]) t.Errorf("expected port 9000, saw port %d", vals["port"])
} }
if vals["user"] != "fart" {
t.Errorf("expected user 'fart', saw user '%s'", vals["user"])
}
if vals["zip"] != true {
t.Errorf("expected zip to be true, is false")
}
if vals["verbose"] != true {
t.Errorf("expected verbose to be true, is false")
}
} }

@ -60,8 +60,9 @@ func field2req(field reflect.StructField) (*req, error) {
t: field.Type, t: field.Type,
long: field.Name, long: field.Name,
} }
// 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 // this is called by Fill, so we have to do Fill's work by hand, otherwise
// they would be mutually recursive.
errors := map[string]error{ errors := map[string]error{
"name": doc.Get("name", &req.name), "name": doc.Get("name", &req.name),

Loading…
Cancel
Save