integrate kingpeon library to allow for custom commands via configuration

This commit is contained in:
Cory Bennett
2017-08-31 15:08:24 -07:00
parent b4d7845105
commit 301a61f2f1
11 changed files with 1260 additions and 1 deletions
+17
View File
@@ -8,6 +8,7 @@ import (
"runtime/debug"
"github.com/coryb/figtree"
"github.com/coryb/kingpeon"
"github.com/coryb/oreo"
jira "gopkg.in/Netflix-Skunkworks/go-jira.v1"
@@ -280,6 +281,22 @@ func main() {
jiracli.Register(app, registry)
// register custom commands
data := struct {
CustomCommands kingpeon.DynamicCommands `yaml:"custom-commands" json":custom-commands"`
}{}
if err := fig.LoadAllConfigs("config.yml", &data); err != nil {
log.Errorf("%s", err)
panic(jiracli.Exit{Code: 1})
}
if len(data.CustomCommands) > 0 {
tmp := map[string]interface{}{}
fig.LoadAllConfigs("config.yml", &tmp)
kingpeon.RegisterDynamicCommands(app, data.CustomCommands, jiracli.TemplateProcessor())
}
app.Terminate(func(status int) {
for _, arg := range os.Args {
if arg == "-h" || arg == "--help" || len(os.Args) == 1 {
+20 -1
View File
@@ -357,7 +357,26 @@ func (f *FigTree) populateEnv(data interface{}) {
if options.Kind() == reflect.Ptr {
options = reflect.ValueOf(options.Elem().Interface())
}
if options.Kind() == reflect.Struct {
if options.Kind() == reflect.Map {
for _, key := range options.MapKeys() {
if strKey, ok := key.Interface().(string); ok {
// first chunk up string so that `foo-bar` becomes ["foo", "bar"]
parts := strings.FieldsFunc(strKey, func(r rune) bool {
return !unicode.IsLetter(r) && !unicode.IsNumber(r)
})
// now for each chunk split again on camelcase so ["fooBar", "baz"]
// becomes ["foo", "Bar", "baz"]
allParts := []string{}
for _, part := range parts {
allParts = append(allParts, camelcase.Split(part)...)
}
name := strings.Join(allParts, "_")
envName := fmt.Sprintf("%s_%s", f.EnvPrefix, strings.ToUpper(name))
os.Setenv(envName, fmt.Sprintf("%v", options.MapIndex(key).Interface()))
}
}
} else if options.Kind() == reflect.Struct {
for i := 0; i < options.NumField(); i++ {
structField := options.Type().Field(i)
// PkgPath is empty for upper case (exported) field names.
+1
View File
@@ -0,0 +1 @@
language: go
+5
View File
@@ -0,0 +1,5 @@
test:
go get -t -v
go test
.PHONY: test
+4
View File
@@ -0,0 +1,4 @@
[![Build Status](https://travis-ci.org/coryb/kingpeon.svg?branch=master)](https://travis-ci.org/coryb/kingpeon)
[![GoDoc](https://godoc.org/github.com/coryb/kingpeon?status.png)](https://godoc.org/github.com/coryb/kingpeon)
Kingpeon is a Go library to generate [kingpin](https://godoc.org/gopkg.in/alecthomas/kingpin.v2) command usage from a configuration file. It is useful for creating allowing for user-defined aliases for Go command line tools.
+110
View File
@@ -0,0 +1,110 @@
package kingpeon
import (
"fmt"
"strings"
)
type DynamicCommandOpt struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Type DynamicCommandValueType `yaml:"type,omitempty" json:"type,omitempty"`
Help string `yaml:"help,omitempty" json:"help,omitempty"`
Short string `yaml:"short,omitempty" json:"short,omitempty"`
Required bool `yaml:"required,omitempty" json:"required,omitempty"`
Default interface{} `yaml:"default,omitempty" json:"default,omitempty"`
Hidden bool `yaml:"hidden,omitempty" json:"hidden,omitempty"`
Repeat bool `yaml:"repeat,omitempty" json:"repeat,omitempty"`
Enum []string `yaml:"enum,omitempty" json:"enum,omitempty"`
}
type DynamicCommandArg struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Help string `yaml:"help,omitempty" json:"help,omitempty"`
Type DynamicCommandValueType `yaml:"type,omitempty" json:"type,omitempty"`
Required bool `yaml:"required,omitempty" json:"required,omitempty"`
Default interface{} `yaml:"default,omitempty" json:"default,omitempty"`
Repeat bool `yaml:"repeat,omitempty" json:"repeat,omitempty"`
Enum []string `yaml:"enum,omitempty" json:"enum,omitempty"`
}
type DynamicCommand struct {
Name string `yaml:"name,omitempty" json:"name,omitempty"`
Options []DynamicCommandOpt `yaml:"options,omitempty" json:"options,omitempty"`
Args []DynamicCommandArg `yaml:"args,omitempty" json:"args,omitempty"`
Script string `yaml:"script,omitempty" json:"script,omitempty"`
Help string `yaml:"help,omitempty" json:"help,omitempty"`
Default bool `yaml:"default,omitempty" json:"default,omitempty"`
Hidden bool `yaml:"hidden,omitempty" json:"hidden,omitempty"`
Aliases []string `yaml:"aliases,omitempty" json:"aliases,omitempty"`
}
type DynamicCommands []DynamicCommand
type DynamicCommandValueType int
const (
DEFAULT DynamicCommandValueType = iota
BOOL
COUNTER
ENUM
FLOAT32
FLOAT64
INT8
INT16
INT32
INT64
INT
STRING
STRINGMAP
UINT8
UINT16
UINT32
UINT64
UINT
)
func (o *DynamicCommandValueType) UnmarshalYAML(unmarshal func(interface{}) error) error {
var optType string
if err := unmarshal(&optType); err != nil {
return err
}
switch strings.ToUpper(optType) {
case "BOOL":
*o = BOOL
case "COUNTER":
*o = COUNTER
case "ENUM":
*o = ENUM
case "FLOAT32":
*o = FLOAT32
case "FLOAT64":
*o = FLOAT64
case "INT8":
*o = INT8
case "INT16":
*o = INT16
case "INT32":
*o = INT32
case "INT64":
*o = INT64
case "INT":
*o = INT
case "STRING":
*o = STRING
case "STRINGMAP":
*o = STRINGMAP
case "UINT8":
*o = UINT8
case "UINT16":
*o = UINT16
case "UINT32":
*o = UINT32
case "UINT64":
*o = UINT64
case "UINT":
*o = UINT
default:
return fmt.Errorf("Unknown option type: %s", optType)
}
return nil
}
+12
View File
@@ -0,0 +1,12 @@
hash: 69f929047be51886aecd667c9eedf56f84e06024391695c787f5d2a82238b185
updated: 2017-08-28T14:04:17.250162442-07:00
imports:
- name: github.com/alecthomas/template
version: a0175ee3bccc567396460bf5acd36800cb10c49c
subpackages:
- parse
- name: github.com/alecthomas/units
version: 2efee857e7cfd4f3d0138cc3cbb1b4966962b93a
- name: gopkg.in/alecthomas/kingpin.v2
version: 1087e65c9441605df944fb12c33f0fe7072d18ca
testImports: []
+4
View File
@@ -0,0 +1,4 @@
package: github.com/coryb/kingpeon
import:
- package: gopkg.in/alecthomas/kingpin.v2
version: ^2.2.5
+590
View File
@@ -0,0 +1,590 @@
package kingpeon
import (
"bytes"
"fmt"
"os"
"os/exec"
"strings"
"syscall"
"text/template"
kingpin "gopkg.in/alecthomas/kingpin.v2"
)
// type so we can mock out how scripts are executed for testing
// it defaults to syscall.Exec
type runner func(string, []string, []string) error
func runDynamicCommand(run runner, dynamiccommand *DynamicCommand, t *template.Template) error {
buf := bytes.NewBufferString("")
t, err := t.Parse(dynamiccommand.Script)
if err != nil {
return err
}
err = t.Execute(buf, nil)
if err != nil {
return err
}
bin, err := exec.LookPath("sh")
if err != nil {
return err
}
cmd := []string{"sh", "-c", buf.String()}
return run(bin, cmd, os.Environ())
}
// either kingpin.Application or kingpin.CmdClause fit this interface
type kingpinAppOrCommand interface {
Command(string, string) *kingpin.CmdClause
GetCommand(string) *kingpin.CmdClause
}
func lookupCommand(app *kingpin.Application, command *DynamicCommand) *kingpin.CmdClause {
commandWords := strings.Fields(command.Name)
var appOrCmd kingpinAppOrCommand = app
if len(commandWords) > 1 {
for _, name := range commandWords[0 : len(commandWords)-1] {
tmp := appOrCmd.GetCommand(name)
if tmp == nil {
tmp = appOrCmd.Command(name, "")
}
appOrCmd = tmp
}
}
return appOrCmd.Command(commandWords[len(commandWords)-1], command.Help)
}
func RegisterDynamicCommands(app *kingpin.Application, commands DynamicCommands, t *template.Template) error {
return doRegisterDynamicCommands(syscall.Exec, app, commands, t)
}
func doRegisterDynamicCommands(run runner, app *kingpin.Application, commands DynamicCommands, t *template.Template) error {
args := map[string]interface{}{}
opts := map[string]interface{}{}
t = t.Funcs(map[string]interface{}{
"args": func() map[string]interface{} {
return args
},
"options": func() map[string]interface{} {
return opts
},
})
for _, command := range commands {
cmd := lookupCommand(app, &command)
for _, alt := range command.Aliases {
cmd = cmd.Alias(alt)
}
if command.Default {
cmd = cmd.Default()
}
if command.Hidden {
cmd = cmd.Hidden()
}
for _, opt := range command.Options {
cmdFlag := cmd.Flag(opt.Name, opt.Help)
if opt.Short != "" {
cmdFlag.Short(rune(opt.Short[0]))
}
if opt.Required {
cmdFlag.Required()
}
if opt.Default != "" {
opts[opt.Name] = opt.Default
}
if opt.Hidden {
cmdFlag.Hidden()
}
switch opt.Type {
case BOOL:
if opt.Repeat {
var val []bool
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).BoolListVar(&val)
} else {
var val bool
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).BoolVar(&val)
}
case COUNTER:
if opt.Repeat {
return fmt.Errorf("`type: COUNTER` and `repeat: true` not supported for %s", opt.Name)
} else {
var val int
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).CounterVar(&val)
}
case ENUM:
if opt.Repeat {
var val []string
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).EnumsVar(&val, opt.Enum...)
} else {
var val string
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).EnumVar(&val, opt.Enum...)
}
case FLOAT32:
if opt.Repeat {
var val []float32
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Float32ListVar(&val)
} else {
var val float32
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Float32Var(&val)
}
case FLOAT64:
if opt.Repeat {
var val []float64
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Float64ListVar(&val)
} else {
var val float64
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Float64Var(&val)
}
case INT8:
if opt.Repeat {
var val []int8
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Int8ListVar(&val)
} else {
var val int8
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Int8Var(&val)
}
case INT16:
if opt.Repeat {
var val []int16
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Int16ListVar(&val)
} else {
var val int16
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Int16Var(&val)
}
case INT32:
if opt.Repeat {
var val []int32
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Int32ListVar(&val)
} else {
var val int32
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Int32Var(&val)
}
case INT64:
if opt.Repeat {
var val []int64
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Int64ListVar(&val)
} else {
var val int64
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Int64Var(&val)
}
case INT:
if opt.Repeat {
var val []int
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).IntsVar(&val)
} else {
var val int
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).IntVar(&val)
}
case DEFAULT, STRING:
if opt.Repeat {
var val []string
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).StringsVar(&val)
} else {
var val string
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).StringVar(&val)
}
case STRINGMAP:
if opt.Repeat {
return fmt.Errorf("`type: STRINGMAP` and `repeat: true` not supported for %s", opt.Name)
} else {
val := make(map[string]string)
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).StringMapVar(&val)
}
case UINT8:
if opt.Repeat {
var val []uint8
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Uint8ListVar(&val)
} else {
var val uint8
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Uint8Var(&val)
}
case UINT16:
if opt.Repeat {
var val []uint16
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Uint16ListVar(&val)
} else {
var val uint16
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Uint16Var(&val)
}
case UINT32:
if opt.Repeat {
var val []uint32
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Uint32ListVar(&val)
} else {
var val uint32
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Uint32Var(&val)
}
case UINT64:
if opt.Repeat {
var val []uint64
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Uint64ListVar(&val)
} else {
var val uint64
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).Uint64Var(&val)
}
case UINT:
if opt.Repeat {
var val []uint
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).UintsVar(&val)
} else {
var val uint
cmdFlag.PreAction(func(_ *kingpin.ParseContext) error {
opts[opt.Name] = val
return nil
}).UintVar(&val)
}
}
}
for _, arg := range command.Args {
cmdArg := cmd.Arg(arg.Name, arg.Help)
if arg.Required {
cmdArg.Required()
}
if arg.Default != "" {
args[arg.Name] = arg.Default
}
switch arg.Type {
case BOOL:
if arg.Repeat {
var val []bool
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).BoolListVar(&val)
} else {
var val bool
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).BoolVar(&val)
}
case COUNTER:
if arg.Repeat {
return fmt.Errorf("`type: COUNTER` and `repeat: true` not supported for %s", arg.Name)
} else {
var val int
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).CounterVar(&val)
}
case ENUM:
if arg.Repeat {
var val []string
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).EnumsVar(&val, arg.Enum...)
} else {
var val string
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).EnumVar(&val, arg.Enum...)
}
case FLOAT32:
if arg.Repeat {
var val []float32
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Float32ListVar(&val)
} else {
var val float32
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Float32Var(&val)
}
case FLOAT64:
if arg.Repeat {
var val []float64
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Float64ListVar(&val)
} else {
var val float64
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Float64Var(&val)
}
case INT8:
if arg.Repeat {
var val []int8
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Int8ListVar(&val)
} else {
var val int8
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Int8Var(&val)
}
case INT16:
if arg.Repeat {
var val []int16
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Int16ListVar(&val)
} else {
var val int16
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Int16Var(&val)
}
case INT32:
if arg.Repeat {
var val []int32
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Int32ListVar(&val)
} else {
var val int32
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Int32Var(&val)
}
case INT64:
if arg.Repeat {
var val []int64
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Int64ListVar(&val)
} else {
var val int64
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Int64Var(&val)
}
case INT:
if arg.Repeat {
var val []int
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).IntsVar(&val)
} else {
var val int
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).IntVar(&val)
}
case DEFAULT, STRING:
if arg.Repeat {
var val []string
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).StringsVar(&val)
} else {
var val string
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).StringVar(&val)
}
case STRINGMAP:
if arg.Repeat {
return fmt.Errorf("`type: STRINGMAP` and `repeat: true` not supported for %s", arg.Name)
} else {
val := make(map[string]string)
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).StringMapVar(&val)
}
case UINT8:
if arg.Repeat {
var val []uint8
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Uint8ListVar(&val)
} else {
var val uint8
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Uint8Var(&val)
}
case UINT16:
if arg.Repeat {
var val []uint16
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Uint16ListVar(&val)
} else {
var val uint16
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Uint16Var(&val)
}
case UINT32:
if arg.Repeat {
var val []uint32
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Uint32ListVar(&val)
} else {
var val uint32
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Uint32Var(&val)
}
case UINT64:
if arg.Repeat {
var val []uint64
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Uint64ListVar(&val)
} else {
var val uint64
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).Uint64Var(&val)
}
case UINT:
if arg.Repeat {
var val []uint
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).UintsVar(&val)
} else {
var val uint
cmdArg.PreAction(func(_ *kingpin.ParseContext) error {
args[arg.Name] = val
return nil
}).UintVar(&val)
}
}
}
copy := command
cmd.Action(func(_ *kingpin.ParseContext) error {
return runDynamicCommand(run, &copy, t)
})
}
return nil
}
+208
View File
@@ -0,0 +1,208 @@
package kingpeon
import (
"io/ioutil"
"testing"
"text/template"
"github.com/stretchr/testify/assert"
kingpin "gopkg.in/alecthomas/kingpin.v2"
yaml "gopkg.in/yaml.v2"
)
func TestRegisterDynamicCommands(t *testing.T) {
data := struct {
DynamicCommands []DynamicCommand `yaml:"dynamic-commands"`
}{}
config, err := ioutil.ReadFile("./sample.yml")
assert.Nil(t, err)
err = yaml.Unmarshal(config, &data)
assert.Nil(t, err)
tmpl := template.New("test")
app := kingpin.New("kingpeon", "Testing Aliases")
var expectedShell string
run := func(bin string, cmd []string, env []string) error {
assert.Equal(t, "/bin/sh", bin)
assert.Equal(t, []string{"sh", "-c", expectedShell}, cmd)
assert.NotEmpty(t, env)
return nil
}
err = doRegisterDynamicCommands(run, app, data.DynamicCommands, tmpl)
assert.Nil(t, err)
expectedShell = "echo hello world"
_, err = app.Parse([]string{"echo"})
assert.Nil(t, err)
expectedShell = "echo -n hello world"
_, err = app.Parse([]string{"echo", "--no-newline"})
assert.Nil(t, err)
expectedShell = "echo hello test"
_, err = app.Parse([]string{"echo", "test", "--newline"})
assert.Nil(t, err)
expectedShell = "echo -n hello test"
_, err = app.Parse([]string{"echo", "test", "--no-newline"})
assert.Nil(t, err)
expectedShell = "echo true"
_, err = app.Parse([]string{"test", "bool", "arg", "true"})
assert.Nil(t, err)
expectedShell = "echo true"
_, err = app.Parse([]string{"test", "bool", "opt", "--BOOL"})
assert.Nil(t, err)
expectedShell = "echo 2"
_, err = app.Parse([]string{"test", "counter", "arg", "foo", "bar"})
assert.Nil(t, err)
expectedShell = "echo 2"
_, err = app.Parse([]string{"test", "counter", "opt", "--COUNTER", "--COUNTER"})
assert.Nil(t, err)
expectedShell = "echo foo"
_, err = app.Parse([]string{"test", "enum", "arg", "foo"})
assert.Nil(t, err)
expectedShell = "echo foo"
_, err = app.Parse([]string{"test", "enum", "opt", "--ENUM", "foo"})
assert.Nil(t, err)
_, err = app.Parse([]string{"test", "enum", "opt", "--ENUM", "bogus"})
assert.EqualError(t, err, "enum value must be one of foo,bar, got 'bogus'")
expectedShell = "echo 1.23"
_, err = app.Parse([]string{"test", "float32", "arg", "1.23"})
assert.Nil(t, err)
expectedShell = "echo 1.23"
_, err = app.Parse([]string{"test", "float32", "opt", "--FLOAT32", "1.23"})
assert.Nil(t, err)
expectedShell = "echo 1.23"
_, err = app.Parse([]string{"test", "float64", "arg", "1.23"})
assert.Nil(t, err)
expectedShell = "echo 1.23"
_, err = app.Parse([]string{"test", "float64", "opt", "--FLOAT64", "1.23"})
assert.Nil(t, err)
expectedShell = "echo 127"
_, err = app.Parse([]string{"test", "int8", "arg", "127"})
assert.Nil(t, err)
expectedShell = "echo 127"
_, err = app.Parse([]string{"test", "int8", "opt", "--INT8", "127"})
assert.Nil(t, err)
expectedShell = "echo 127"
_, err = app.Parse([]string{"test", "int8", "arg", "127"})
assert.Nil(t, err)
expectedShell = "echo 127"
_, err = app.Parse([]string{"test", "int8", "opt", "--INT8", "127"})
assert.Nil(t, err)
expectedShell = "echo 127"
_, err = app.Parse([]string{"test", "int16", "arg", "127"})
assert.Nil(t, err)
expectedShell = "echo 127"
_, err = app.Parse([]string{"test", "int16", "opt", "--INT16", "127"})
assert.Nil(t, err)
expectedShell = "echo 127"
_, err = app.Parse([]string{"test", "int32", "arg", "127"})
assert.Nil(t, err)
expectedShell = "echo 127"
_, err = app.Parse([]string{"test", "int32", "opt", "--INT32", "127"})
assert.Nil(t, err)
expectedShell = "echo 127"
_, err = app.Parse([]string{"test", "int64", "arg", "127"})
assert.Nil(t, err)
expectedShell = "echo 127"
_, err = app.Parse([]string{"test", "int64", "opt", "--INT64", "127"})
assert.Nil(t, err)
expectedShell = "echo 127"
_, err = app.Parse([]string{"test", "int", "arg", "127"})
assert.Nil(t, err)
expectedShell = "echo 127"
_, err = app.Parse([]string{"test", "int", "opt", "--INT", "127"})
assert.Nil(t, err)
expectedShell = "echo hello"
_, err = app.Parse([]string{"test", "string", "arg", "hello"})
assert.Nil(t, err)
expectedShell = "echo hello"
_, err = app.Parse([]string{"test", "string", "opt", "--STRING", "hello"})
assert.Nil(t, err)
expectedShell = "echo [abc: def][foo: bar]"
_, err = app.Parse([]string{"test", "stringmap", "arg", "foo=bar", "abc=def"})
assert.Nil(t, err)
expectedShell = "echo [abc: def][foo: bar]"
_, err = app.Parse([]string{"test", "stringmap", "opt", "--STRINGMAP", "foo=bar", "--STRINGMAP", "abc=def"})
assert.Nil(t, err)
expectedShell = "echo 255"
_, err = app.Parse([]string{"test", "uint8", "arg", "255"})
assert.Nil(t, err)
expectedShell = "echo 255"
_, err = app.Parse([]string{"test", "uint8", "opt", "--UINT8", "255"})
assert.Nil(t, err)
expectedShell = "echo 255"
_, err = app.Parse([]string{"test", "uint8", "arg", "255"})
assert.Nil(t, err)
expectedShell = "echo 255"
_, err = app.Parse([]string{"test", "uint8", "opt", "--UINT8", "255"})
assert.Nil(t, err)
expectedShell = "echo 255"
_, err = app.Parse([]string{"test", "uint16", "arg", "255"})
assert.Nil(t, err)
expectedShell = "echo 255"
_, err = app.Parse([]string{"test", "uint16", "opt", "--UINT16", "255"})
assert.Nil(t, err)
expectedShell = "echo 255"
_, err = app.Parse([]string{"test", "uint32", "arg", "255"})
assert.Nil(t, err)
expectedShell = "echo 255"
_, err = app.Parse([]string{"test", "uint32", "opt", "--UINT32", "255"})
assert.Nil(t, err)
expectedShell = "echo 255"
_, err = app.Parse([]string{"test", "uint64", "arg", "255"})
assert.Nil(t, err)
expectedShell = "echo 255"
_, err = app.Parse([]string{"test", "uint64", "opt", "--UINT64", "255"})
assert.Nil(t, err)
expectedShell = "echo 255"
_, err = app.Parse([]string{"test", "uint", "arg", "255"})
assert.Nil(t, err)
expectedShell = "echo 255"
_, err = app.Parse([]string{"test", "uint", "opt", "--UINT", "255"})
assert.Nil(t, err)
}
+289
View File
@@ -0,0 +1,289 @@
dynamic-commands:
- name: echo
help: echo stuff
script: |-
echo {{if not options.newline}}-n {{end}}hello {{args.WORD}}
args:
- name: WORD
default: world
options:
- name: newline
type: BOOL
default: true
- name: test bool arg
help: test bool arg
script: |-
echo {{args.BOOL}}
args:
- name: BOOL
type: BOOL
required: true
- name: test bool opt
help: test bool opt
script: |-
echo {{options.BOOL}}
options:
- name: BOOL
type: BOOL
required: true
- name: test counter arg
help: test counter arg
script: |-
echo {{args.COUNTER}}
args:
- name: COUNTER
type: COUNTER
required: true
- name: test counter opt
help: test counter opt
script: |-
echo {{options.COUNTER}}
options:
- name: COUNTER
type: COUNTER
required: true
- name: test enum arg
help: test enum arg
script: |-
echo {{args.ENUM}}
args:
- name: ENUM
type: ENUM
enum:
- foo
- bar
required: true
- name: test enum opt
help: test enum opt
script: |-
echo {{options.ENUM}}
options:
- name: ENUM
type: ENUM
enum:
- foo
- bar
required: true
- name: test float32 arg
help: test float32 arg
script: |-
echo {{args.FLOAT32}}
args:
- name: FLOAT32
type: FLOAT32
required: true
- name: test float32 opt
help: test float32 opt
script: |-
echo {{options.FLOAT32}}
options:
- name: FLOAT32
type: FLOAT32
required: true
- name: test float64 arg
help: test float64 arg
script: |-
echo {{args.FLOAT64}}
args:
- name: FLOAT64
type: FLOAT64
required: true
- name: test float64 opt
help: test float64 opt
script: |-
echo {{options.FLOAT64}}
options:
- name: FLOAT64
type: FLOAT64
required: true
- name: test int8 arg
help: test int8 arg
script: |-
echo {{args.INT8}}
args:
- name: INT8
type: INT8
required: true
- name: test int8 opt
help: test int8 opt
script: |-
echo {{options.INT8}}
options:
- name: INT8
type: INT8
required: true
- name: test int16 arg
help: test int16 arg
script: |-
echo {{args.INT16}}
args:
- name: INT16
type: INT16
required: true
- name: test int16 opt
help: test int16 opt
script: |-
echo {{options.INT16}}
options:
- name: INT16
type: INT16
required: true
- name: test int32 arg
help: test int32 arg
script: |-
echo {{args.INT32}}
args:
- name: INT32
type: INT32
required: true
- name: test int32 opt
help: test int32 opt
script: |-
echo {{options.INT32}}
options:
- name: INT32
type: INT32
required: true
- name: test int64 arg
help: test int64 arg
script: |-
echo {{args.INT64}}
args:
- name: INT64
type: INT64
required: true
- name: test int64 opt
help: test int64 opt
script: |-
echo {{options.INT64}}
options:
- name: INT64
type: INT64
required: true
- name: test int arg
help: test int arg
script: |-
echo {{args.INT}}
args:
- name: INT
type: INT
required: true
- name: test int opt
help: test int opt
script: |-
echo {{options.INT}}
options:
- name: INT
type: INT
required: true
- name: test string arg
help: test string arg
script: |-
echo {{args.STRING}}
args:
- name: STRING
required: true
- name: test string opt
help: test string opt
script: |-
echo {{options.STRING}}
options:
- name: STRING
required: true
- name: test stringmap arg
help: test stringmap arg
script: |-
echo {{range $key, $val := args.STRINGMAP}}[{{$key}}: {{$val}}]{{end}}
args:
- name: STRINGMAP
type: STRINGMAP
required: true
- name: test stringmap opt
help: test stringmap opt
script: |-
echo {{range $key, $val := options.STRINGMAP}}[{{$key}}: {{$val}}]{{end}}
options:
- name: STRINGMAP
type: STRINGMAP
required: true
- name: test uint8 arg
help: test uint8 arg
script: |-
echo {{args.UINT8}}
args:
- name: UINT8
type: UINT8
required: true
- name: test uint8 opt
help: test uint8 opt
script: |-
echo {{options.UINT8}}
options:
- name: UINT8
type: UINT8
required: true
- name: test uint16 arg
help: test uint16 arg
script: |-
echo {{args.UINT16}}
args:
- name: UINT16
type: UINT16
required: true
- name: test uint16 opt
help: test uint16 opt
script: |-
echo {{options.UINT16}}
options:
- name: UINT16
type: UINT16
required: true
- name: test uint32 arg
help: test uint32 arg
script: |-
echo {{args.UINT32}}
args:
- name: UINT32
type: UINT32
required: true
- name: test uint32 opt
help: test uint32 opt
script: |-
echo {{options.UINT32}}
options:
- name: UINT32
type: UINT32
required: true
- name: test uint64 arg
help: test uint64 arg
script: |-
echo {{args.UINT64}}
args:
- name: UINT64
type: UINT64
required: true
- name: test uint64 opt
help: test uint64 opt
script: |-
echo {{options.UINT64}}
options:
- name: UINT64
type: UINT64
required: true
- name: test uint arg
help: test uint arg
script: |-
echo {{args.UINT}}
args:
- name: UINT
type: UINT
required: true
- name: test uint opt
help: test uint opt
script: |-
echo {{options.UINT}}
options:
- name: UINT
type: UINT
required: true