Add flags library
This commit is contained in:
parent
9ee70725fe
commit
05facc0035
821
internal/flags/flag.go
Normal file
821
internal/flags/flag.go
Normal file
@ -0,0 +1,821 @@
|
||||
package flags
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Type uint
|
||||
|
||||
const (
|
||||
UnsetType Type = iota // Unset
|
||||
ArrayType // Array
|
||||
BooleanType // Boolean
|
||||
FloatType // Float
|
||||
IncrementType // Increment
|
||||
IntegerType // Integer
|
||||
MapType // Map
|
||||
StringType // String
|
||||
)
|
||||
|
||||
type FlagModifier func(f *Flag)
|
||||
type FlagProcessor func(f *Flag, v interface{}) (interface{}, error)
|
||||
type FlagCallback func(f *Flag) error
|
||||
|
||||
// Add long name aliases for flag
|
||||
func Alias(aliases ...string) FlagModifier {
|
||||
return func(f *Flag) {
|
||||
for _, a := range aliases {
|
||||
f.aliases = append(f.aliases, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set description of flag
|
||||
func Description(d string) FlagModifier {
|
||||
return func(f *Flag) {
|
||||
f.description = d
|
||||
}
|
||||
}
|
||||
|
||||
// Mark flag as being required
|
||||
func Required() FlagModifier {
|
||||
return func(f *Flag) {
|
||||
f.required = true
|
||||
}
|
||||
}
|
||||
|
||||
// Mark flag as being optional (default state)
|
||||
func Optional() FlagModifier {
|
||||
return func(f *Flag) {
|
||||
f.required = false
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent flag from being displayed
|
||||
func Hidden() FlagModifier {
|
||||
return func(f *Flag) {
|
||||
f.hidden = true
|
||||
}
|
||||
}
|
||||
|
||||
// Set default value for flag
|
||||
func DefaultValue(v interface{}) FlagModifier {
|
||||
return func(f *Flag) {
|
||||
f.typeCheck(v)
|
||||
f.defaultValue = v
|
||||
}
|
||||
}
|
||||
|
||||
// Set environment variable to read for flag value
|
||||
func EnvVar(name string) FlagModifier {
|
||||
return func(f *Flag) {
|
||||
f.envVar = name
|
||||
}
|
||||
}
|
||||
|
||||
// Set short name for flag
|
||||
func ShortName(n rune) FlagModifier {
|
||||
return func(f *Flag) {
|
||||
f.shortName = n
|
||||
}
|
||||
}
|
||||
|
||||
// Set the subtype of the flag (used for array and map types)
|
||||
func SetSubtype(t Type) FlagModifier {
|
||||
return func(f *Flag) {
|
||||
f.subkind = t
|
||||
}
|
||||
}
|
||||
|
||||
// Add a processor to be executed before the flag value is
|
||||
// set. The processor receives the current value to be set
|
||||
// into the flag. The value returned by the process will be
|
||||
// the value actually set into the flag.
|
||||
func AddProcessor(fn FlagProcessor) FlagModifier {
|
||||
return func(f *Flag) {
|
||||
f.processors = append(f.processors, fn)
|
||||
}
|
||||
}
|
||||
|
||||
// Add a callback to be executed when flag is visited before
|
||||
// the flag value is set. This can be used to modify the
|
||||
// final value set.
|
||||
func AddCallback(fn FlagCallback) FlagModifier {
|
||||
return func(f *Flag) {
|
||||
f.callbacks = append(f.callbacks, fn)
|
||||
}
|
||||
}
|
||||
|
||||
// Set value into custom pointer
|
||||
func customVar(v interface{}) FlagModifier {
|
||||
return func(f *Flag) {
|
||||
f.ptrTypeCheck(v)
|
||||
f.value = v
|
||||
f.ptr = true
|
||||
}
|
||||
}
|
||||
|
||||
type Flag struct {
|
||||
aliases []string // long name aliases
|
||||
called bool // mark if called via cli
|
||||
callbacks []FlagCallback // callback functions
|
||||
defaultValue interface{} // default value when not updated
|
||||
description string // description of flag
|
||||
envVar string // environment variable to check for value
|
||||
group *Group // group flag is attached to
|
||||
hidden bool // flag is hidden from display
|
||||
longName string // long name of flag
|
||||
matchedName string // long or short name matched for flag (includes aliases)
|
||||
processors []FlagProcessor // processor functions
|
||||
ptr bool // mark if value is pointer
|
||||
required bool // mark if flag requires value set
|
||||
shortName rune // short name of flag
|
||||
kind Type // data type of value
|
||||
subkind Type // data type of values within array or map type
|
||||
updated bool // value was updated (either by env var or cli)
|
||||
value interface{} // value for flag
|
||||
}
|
||||
|
||||
// Create a new flag
|
||||
func newFlag(
|
||||
name string, // long name of flag
|
||||
kind Type, // data type of the flag
|
||||
group *Group, // group flag is attached to
|
||||
modifiers ...FlagModifier, // any modifier functions
|
||||
) *Flag {
|
||||
if group == nil {
|
||||
panic("flag must be attached to group")
|
||||
}
|
||||
f := &Flag{
|
||||
longName: name,
|
||||
kind: kind,
|
||||
group: group,
|
||||
}
|
||||
group.flags = append(group.flags, f)
|
||||
for _, fn := range modifiers {
|
||||
fn(f)
|
||||
}
|
||||
if kind == BooleanType {
|
||||
Alias(fmt.Sprintf("no-%s", f.longName))(f)
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// List of aliases for this flag
|
||||
func (f *Flag) Aliases() []string {
|
||||
return f.aliases
|
||||
}
|
||||
|
||||
// Flag value was set via CLI
|
||||
func (f *Flag) Called() bool {
|
||||
return f.called
|
||||
}
|
||||
|
||||
// Flag name (long, short, aliases) matched on CLI
|
||||
func (f *Flag) CalledAs() string {
|
||||
return f.matchedName
|
||||
}
|
||||
|
||||
// Default value assigned to flag
|
||||
func (f *Flag) DefaultValue() interface{} {
|
||||
return f.defaultValue
|
||||
}
|
||||
|
||||
// Description of flag usage
|
||||
func (f *Flag) Description() string {
|
||||
return f.description
|
||||
}
|
||||
|
||||
// Environment variable name used to populate flag value
|
||||
func (f *Flag) EnvVar() string {
|
||||
return f.envVar
|
||||
}
|
||||
|
||||
// Group flag is attached to
|
||||
func (f *Flag) Group() *Group {
|
||||
return f.group
|
||||
}
|
||||
|
||||
// Flag is hidden from display
|
||||
func (f *Flag) Hidden() bool {
|
||||
return f.hidden
|
||||
}
|
||||
|
||||
// Long name of the flag
|
||||
func (f *Flag) LongName() string {
|
||||
return f.longName
|
||||
}
|
||||
|
||||
// Flag is required to be set
|
||||
func (f *Flag) Required() bool {
|
||||
return f.required
|
||||
}
|
||||
|
||||
// Short name of the flag
|
||||
func (f *Flag) ShortName() rune {
|
||||
return f.shortName
|
||||
}
|
||||
|
||||
// Flag value was set via CLI or environment variable
|
||||
func (f *Flag) Updated() bool {
|
||||
return f.updated
|
||||
}
|
||||
|
||||
// Value assigned to flag
|
||||
func (f *Flag) Value() interface{} {
|
||||
if f.ptr {
|
||||
switch f.kind {
|
||||
case ArrayType:
|
||||
switch f.subkind {
|
||||
case BooleanType:
|
||||
return *(f.value.(*[]bool))
|
||||
case FloatType:
|
||||
return *(f.value.(*[]float64))
|
||||
case IntegerType:
|
||||
return *(f.value.(*[]int64))
|
||||
case StringType:
|
||||
return *(f.value.(*[]string))
|
||||
default:
|
||||
panic("unsupported array subtype: " + f.subkind.String())
|
||||
}
|
||||
case BooleanType:
|
||||
return *(f.value.(*bool))
|
||||
case FloatType:
|
||||
return *(f.value.(*float64))
|
||||
case IncrementType, IntegerType:
|
||||
return *(f.value.(*int64))
|
||||
case MapType:
|
||||
switch f.subkind {
|
||||
case BooleanType:
|
||||
return *(f.value.(*map[string]bool))
|
||||
case FloatType:
|
||||
return *(f.value.(*map[string]float64))
|
||||
case IntegerType:
|
||||
return *(f.value.(*map[string]int64))
|
||||
case StringType:
|
||||
return *(f.value.(*map[string]string))
|
||||
default:
|
||||
panic("unsupported map subtype: " + f.subkind.String())
|
||||
}
|
||||
case StringType:
|
||||
return *(f.value.(*string))
|
||||
}
|
||||
}
|
||||
return f.value
|
||||
}
|
||||
|
||||
// Initialize the flag to make ready for parsing. This is called
|
||||
// by the Set before parsing.
|
||||
func (f *Flag) init() error {
|
||||
// if the value is already set, the flag has been previously
|
||||
// used so we should consider it invalid
|
||||
if f.updated || f.called {
|
||||
return fmt.Errorf("flag has already been used")
|
||||
}
|
||||
// If the value is a custom variable then we don't need to initialize
|
||||
if !f.ptr {
|
||||
// Now we want to initialize our value so it can
|
||||
// be modified as needed.
|
||||
switch f.kind {
|
||||
case ArrayType:
|
||||
switch f.subkind {
|
||||
case BooleanType:
|
||||
f.value = []bool{}
|
||||
case FloatType:
|
||||
f.value = []float64{}
|
||||
case IntegerType:
|
||||
f.value = []int64{}
|
||||
case StringType:
|
||||
f.value = []string{}
|
||||
default:
|
||||
panic("invalid subtype for array: " + f.subkind.String())
|
||||
}
|
||||
case BooleanType:
|
||||
var val bool
|
||||
f.value = val
|
||||
case FloatType:
|
||||
var val float64
|
||||
f.value = val
|
||||
case IncrementType, IntegerType:
|
||||
var val int64
|
||||
f.value = val
|
||||
case MapType:
|
||||
switch f.subkind {
|
||||
case BooleanType:
|
||||
f.value = map[string]bool{}
|
||||
case FloatType:
|
||||
f.value = map[string]float64{}
|
||||
case IntegerType:
|
||||
f.value = map[string]int64{}
|
||||
case StringType:
|
||||
f.value = map[string]string{}
|
||||
default:
|
||||
panic("invalid subtype for map: " + f.subkind.String())
|
||||
}
|
||||
case StringType:
|
||||
var val string
|
||||
f.value = val
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we have an environment variable configured, and if it
|
||||
// is set, then set the value into the flag
|
||||
if f.envVar != "" {
|
||||
if eval := os.Getenv(f.envVar); eval != "" {
|
||||
if err := f.setValue(eval); err != nil {
|
||||
return err
|
||||
}
|
||||
f.updated = true
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Marks the flag as being called from the CLI and sets
|
||||
// the flag name used.
|
||||
func (f *Flag) markCalled(name string) {
|
||||
defer func() {
|
||||
f.matchedName = name
|
||||
f.called = true
|
||||
f.updated = true
|
||||
}()
|
||||
if f.longName == name || string(f.shortName) == name {
|
||||
return
|
||||
}
|
||||
for _, n := range f.aliases {
|
||||
if n == name {
|
||||
return
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf(
|
||||
"matched flag name (%s) is not a valid name for this flag (%s)",
|
||||
name, f.longName))
|
||||
}
|
||||
|
||||
// Set a value into the flag
|
||||
func (f *Flag) setValue(v string) (err error) {
|
||||
switch f.kind {
|
||||
case ArrayType:
|
||||
err = f.setValueArray(v)
|
||||
case BooleanType:
|
||||
err = f.setValueBoolean(v)
|
||||
case FloatType:
|
||||
err = f.setValueFloat(v)
|
||||
case IncrementType:
|
||||
err = f.setValueIncrement(v)
|
||||
case MapType:
|
||||
err = f.setValueMap(v)
|
||||
case StringType:
|
||||
err = f.setValueString(v)
|
||||
default:
|
||||
err = fmt.Errorf("invalid type, cannot set value")
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, fn := range f.callbacks {
|
||||
if err = fn(f); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Set value into map type
|
||||
func (f *Flag) setValueMap(v string) (err error) {
|
||||
parts := strings.SplitN(v, "=", 2)
|
||||
if len(parts) != 2 {
|
||||
return fmt.Errorf("invalid value passed for map flag - %s", v)
|
||||
}
|
||||
key, value := parts[0], parts[1]
|
||||
val, err := f.convertValue(value)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, fn := range f.processors {
|
||||
if val, err = fn(f, val); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
switch f.subkind {
|
||||
case BooleanType:
|
||||
var m map[string]bool
|
||||
if f.ptr {
|
||||
m = *(f.value.(*map[string]bool))
|
||||
} else {
|
||||
m = f.value.(map[string]bool)
|
||||
}
|
||||
m[key] = val.(bool)
|
||||
case FloatType:
|
||||
var m map[string]float64
|
||||
if f.ptr {
|
||||
m = *(f.value.(*map[string]float64))
|
||||
} else {
|
||||
m = f.value.(map[string]float64)
|
||||
}
|
||||
m[key] = val.(float64)
|
||||
case IntegerType:
|
||||
var m map[string]int64
|
||||
if f.ptr {
|
||||
m = *(f.value.(*map[string]int64))
|
||||
} else {
|
||||
m = f.value.(map[string]int64)
|
||||
}
|
||||
m[key] = val.(int64)
|
||||
case StringType:
|
||||
var m map[string]string
|
||||
if f.ptr {
|
||||
m = *(f.value.(*map[string]string))
|
||||
} else {
|
||||
m = f.value.(map[string]string)
|
||||
}
|
||||
m[key] = val.(string)
|
||||
default:
|
||||
return fmt.Errorf("invalid subtype configured for map flag - %s", f.subkind.String())
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Set value into array type
|
||||
func (f *Flag) setValueArray(val string) (err error) {
|
||||
v, err := f.convertValue(val)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, fn := range f.processors {
|
||||
if v, err = fn(f, v); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch f.subkind {
|
||||
case BooleanType:
|
||||
var array []bool
|
||||
if f.ptr {
|
||||
array = *(f.value.(*[]bool))
|
||||
} else {
|
||||
array = f.value.([]bool)
|
||||
}
|
||||
newArray := make([]bool, len(array)+1)
|
||||
copy(newArray, array)
|
||||
newArray[len(newArray)-1] = v.(bool)
|
||||
if f.ptr {
|
||||
*(f.value.(*[]bool)) = newArray
|
||||
} else {
|
||||
f.value = newArray
|
||||
}
|
||||
case FloatType:
|
||||
var array []float64
|
||||
if f.ptr {
|
||||
array = *(f.value.(*[]float64))
|
||||
} else {
|
||||
array = f.value.([]float64)
|
||||
}
|
||||
newArray := make([]float64, len(array)+1)
|
||||
copy(newArray, array)
|
||||
newArray[len(newArray)-1] = v.(float64)
|
||||
if f.ptr {
|
||||
*(f.value.(*[]float64)) = newArray
|
||||
} else {
|
||||
f.value = newArray
|
||||
}
|
||||
case IntegerType:
|
||||
var array []int64
|
||||
if f.ptr {
|
||||
array = *(f.value.(*[]int64))
|
||||
} else {
|
||||
array = f.value.([]int64)
|
||||
}
|
||||
newArray := make([]int64, len(array)+1)
|
||||
copy(newArray, array)
|
||||
newArray[len(newArray)-1] = v.(int64)
|
||||
if f.ptr {
|
||||
*(f.value.(*[]int64)) = newArray
|
||||
} else {
|
||||
f.value = newArray
|
||||
}
|
||||
case StringType:
|
||||
var array []string
|
||||
if f.ptr {
|
||||
array = *(f.value.(*[]string))
|
||||
} else {
|
||||
array = f.value.([]string)
|
||||
}
|
||||
newArray := make([]string, len(array)+1)
|
||||
copy(newArray, array)
|
||||
newArray[len(newArray)-1] = v.(string)
|
||||
if f.ptr {
|
||||
*(f.value.(*[]string)) = newArray
|
||||
} else {
|
||||
f.value = newArray
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("invalid subtype configured for array flag - %s", f.subkind.String())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set value into boolean type
|
||||
func (f *Flag) setValueBoolean(val string) (err error) {
|
||||
v, err := f.convertValue(val)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, fn := range f.processors {
|
||||
if v, err = fn(f, v); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if f.ptr {
|
||||
*(f.value.(*bool)) = v.(bool)
|
||||
return
|
||||
}
|
||||
|
||||
f.value = v
|
||||
return
|
||||
}
|
||||
|
||||
// Set value into float type
|
||||
func (f *Flag) setValueFloat(val string) (err error) {
|
||||
v, err := f.convertValue(val)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, fn := range f.processors {
|
||||
if v, err = fn(f, v); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if f.ptr {
|
||||
*(f.value.(*float64)) = v.(float64)
|
||||
return
|
||||
}
|
||||
|
||||
f.value = v
|
||||
return
|
||||
}
|
||||
|
||||
// Set value into integer type
|
||||
func (f *Flag) setValueInteger(val string) (err error) {
|
||||
v, err := f.convertValue(val)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, fn := range f.processors {
|
||||
if v, err = fn(f, v); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if f.ptr {
|
||||
*(f.value.(*int64)) = v.(int64)
|
||||
return
|
||||
}
|
||||
|
||||
f.value = v
|
||||
return
|
||||
}
|
||||
|
||||
// Set value into string type
|
||||
func (f *Flag) setValueString(val string) (err error) {
|
||||
v, err := f.convertValue(val)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, fn := range f.processors {
|
||||
if v, err = fn(f, v); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if f.ptr {
|
||||
*(f.value.(*string)) = v.(string)
|
||||
return
|
||||
}
|
||||
|
||||
f.value = v
|
||||
return
|
||||
}
|
||||
|
||||
// Set value on increment type
|
||||
func (f *Flag) setValueIncrement(val string) (err error) {
|
||||
if f.ptr {
|
||||
*(f.value.(*int64)) = *(f.value.(*int64)) + 1
|
||||
return
|
||||
}
|
||||
|
||||
f.value = interface{}(f.value.(int64) + 1)
|
||||
return
|
||||
}
|
||||
|
||||
// Convert given value to expected type
|
||||
func (f *Flag) convertValue(v string) (interface{}, error) {
|
||||
switch f.kind {
|
||||
case ArrayType, MapType:
|
||||
return f.doConvert(v, f.subkind)
|
||||
case IncrementType:
|
||||
return 1, nil
|
||||
default:
|
||||
return f.doConvert(v, f.kind)
|
||||
}
|
||||
}
|
||||
|
||||
// Actually do the conversion based on type
|
||||
func (f *Flag) doConvert(v string, t Type) (interface{}, error) {
|
||||
switch t {
|
||||
case BooleanType:
|
||||
b, err := strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return b, nil
|
||||
case FloatType:
|
||||
pf, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pf, nil
|
||||
case IntegerType:
|
||||
pi, err := strconv.ParseInt(v, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pi, nil
|
||||
case StringType:
|
||||
// Original values are strings, so just return the value
|
||||
return v, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid type for conversion - %s", f.kind.String())
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the value given is the type expected by the flag. This
|
||||
// will panic on unexpected type.
|
||||
func (f *Flag) typeCheck(v interface{}) {
|
||||
switch f.kind {
|
||||
case ArrayType:
|
||||
switch f.subkind {
|
||||
case BooleanType:
|
||||
if _, ok := v.([]bool); !ok {
|
||||
panic(fmt.Sprintf("invalid variable type - expected: []bool received: %T", v))
|
||||
}
|
||||
case FloatType:
|
||||
if _, ok := v.([]float64); !ok {
|
||||
panic(fmt.Sprintf("invalid variable type - expected: []float64 received: %T", v))
|
||||
}
|
||||
case IntegerType:
|
||||
if _, ok := v.([]int64); !ok {
|
||||
panic(fmt.Sprintf("invalid variable type - expected: []int64 received: %T", v))
|
||||
}
|
||||
case StringType:
|
||||
if _, ok := v.([]string); !ok {
|
||||
panic(fmt.Sprintf("invalid variable type - expected: []string received: %T", v))
|
||||
}
|
||||
default:
|
||||
panic("invalid subtype for array: " + f.subkind.String())
|
||||
}
|
||||
case BooleanType:
|
||||
if _, ok := v.(bool); !ok {
|
||||
panic(fmt.Sprintf("invalid variable type - expected: bool received: %T", v))
|
||||
}
|
||||
case FloatType:
|
||||
if _, ok := v.(float64); !ok {
|
||||
panic(fmt.Sprintf("invalid variable type - expected: float64 received: %T", v))
|
||||
}
|
||||
case IncrementType, IntegerType:
|
||||
if _, ok := v.(int64); !ok {
|
||||
panic(fmt.Sprintf("invalid variable type - expected: int64 received: %T", v))
|
||||
}
|
||||
case MapType:
|
||||
switch f.subkind {
|
||||
case BooleanType:
|
||||
if _, ok := v.(map[string]bool); !ok {
|
||||
panic(fmt.Sprintf("invalid variable type - expected: map[string]bool received: %T", v))
|
||||
}
|
||||
case FloatType:
|
||||
if _, ok := v.(map[string]float64); !ok {
|
||||
panic(fmt.Sprintf("invalid variable type - expected: map[string]float64 received: %T", v))
|
||||
}
|
||||
case IntegerType:
|
||||
if _, ok := v.(map[string]int64); !ok {
|
||||
panic(fmt.Sprintf("invalid variable type - expected: map[string]int64 received: %T", v))
|
||||
}
|
||||
case StringType:
|
||||
if _, ok := v.(map[string]string); !ok {
|
||||
panic(fmt.Sprintf("invalid variable type - expected: map[string]string received: %T", v))
|
||||
}
|
||||
default:
|
||||
panic("invalid subtype for map: " + f.subkind.String())
|
||||
}
|
||||
case StringType:
|
||||
if _, ok := v.(string); !ok {
|
||||
panic(fmt.Sprintf("invalid variable type - expected: string received: %T", v))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the value given is a pointer to the type expected by the flag. This
|
||||
// will panic on unexpected type.
|
||||
func (f *Flag) ptrTypeCheck(v interface{}) {
|
||||
switch f.kind {
|
||||
case ArrayType:
|
||||
switch f.subkind {
|
||||
case BooleanType:
|
||||
if c, ok := v.(*[]bool); !ok {
|
||||
panic(fmt.Sprintf("invalid pointer variable - expected: *[]bool received: %T", v))
|
||||
} else {
|
||||
if *c == nil {
|
||||
panic(fmt.Sprintf("array pointer value cannot be nil - %#v", c))
|
||||
}
|
||||
}
|
||||
case FloatType:
|
||||
if c, ok := v.(*[]float64); !ok {
|
||||
panic(fmt.Sprintf("invalid pointer variable - expected: *[]float64 received: %T", v))
|
||||
} else {
|
||||
if *c == nil {
|
||||
panic(fmt.Sprintf("array pointer value cannot be nil - %#v", c))
|
||||
}
|
||||
}
|
||||
case IntegerType:
|
||||
if c, ok := v.(*[]int64); !ok {
|
||||
panic(fmt.Sprintf("invalid pointer variable - expected: *[]int64 received: %T", v))
|
||||
} else {
|
||||
if *c == nil {
|
||||
panic(fmt.Sprintf("array pointer value cannot be nil - %#v", c))
|
||||
}
|
||||
}
|
||||
case StringType:
|
||||
if c, ok := v.(*[]string); !ok {
|
||||
panic(fmt.Sprintf("invalid pointer variable - expected: *[]string received: %T", v))
|
||||
} else {
|
||||
if *c == nil {
|
||||
panic(fmt.Sprintf("array pointer value cannot be nil - %#v", c))
|
||||
}
|
||||
}
|
||||
default:
|
||||
panic("invalid subtype for array: " + f.subkind.String())
|
||||
}
|
||||
case BooleanType:
|
||||
if _, ok := v.(*bool); !ok {
|
||||
panic(fmt.Sprintf("invalid pointer variable - expected *bool received %T", v))
|
||||
}
|
||||
case FloatType:
|
||||
if _, ok := v.(*float64); !ok {
|
||||
panic(fmt.Sprintf("invalid pointer variable - expected *float64 received %T", v))
|
||||
}
|
||||
case IncrementType, IntegerType:
|
||||
if _, ok := v.(*int64); !ok {
|
||||
panic(fmt.Sprintf("invalid pointer variable - expected *int64 received %T", v))
|
||||
}
|
||||
case MapType:
|
||||
switch f.subkind {
|
||||
case BooleanType:
|
||||
if c, ok := v.(*map[string]bool); !ok {
|
||||
panic(fmt.Sprintf("invalid pointer variable - expected: *map[string]bool received: %T", v))
|
||||
} else {
|
||||
if *c == nil {
|
||||
panic(fmt.Sprintf("map pointer value cannot be nil - %#v", c))
|
||||
}
|
||||
}
|
||||
case FloatType:
|
||||
if c, ok := v.(*map[string]float64); !ok {
|
||||
panic(fmt.Sprintf("invalid pointer variable - expected: *map[string]float64 received: %T", v))
|
||||
} else {
|
||||
if *c == nil {
|
||||
panic(fmt.Sprintf("map pointer value cannot be nil - %#v", c))
|
||||
}
|
||||
}
|
||||
case IntegerType:
|
||||
if c, ok := v.(*map[string]int64); !ok {
|
||||
panic(fmt.Sprintf("invalid pointer variable - expected: *map[string]int64 received: %T", v))
|
||||
} else {
|
||||
if *c == nil {
|
||||
panic(fmt.Sprintf("map pointer value cannot be nil - %#v", c))
|
||||
}
|
||||
}
|
||||
case StringType:
|
||||
if c, ok := v.(*map[string]string); !ok {
|
||||
panic(fmt.Sprintf("invalid pointer variable - expected: *map[string]string received: %T", v))
|
||||
} else {
|
||||
if *c == nil {
|
||||
panic(fmt.Sprintf("map pointer value cannot be nil - %#v", c))
|
||||
}
|
||||
}
|
||||
default:
|
||||
panic("invalid subtype for array: " + f.subkind.String())
|
||||
}
|
||||
case StringType:
|
||||
if _, ok := v.(*string); !ok {
|
||||
panic(fmt.Sprintf("invalid pointer variable - expected *string received %T", v))
|
||||
}
|
||||
}
|
||||
}
|
||||
1704
internal/flags/flag_test.go
Normal file
1704
internal/flags/flag_test.go
Normal file
File diff suppressed because it is too large
Load Diff
260
internal/flags/group.go
Normal file
260
internal/flags/group.go
Normal file
@ -0,0 +1,260 @@
|
||||
package flags
|
||||
|
||||
import "fmt"
|
||||
|
||||
type GroupModifier func(g *Group)
|
||||
|
||||
func HideGroupName() GroupModifier {
|
||||
return func(g *Group) {
|
||||
g.showGroupName = false
|
||||
}
|
||||
}
|
||||
|
||||
func HideGroup() GroupModifier {
|
||||
return func(g *Group) {
|
||||
g.hidden = true
|
||||
}
|
||||
}
|
||||
|
||||
type Group struct {
|
||||
flags []*Flag
|
||||
hidden bool
|
||||
name string
|
||||
set *Set
|
||||
showGroupName bool
|
||||
}
|
||||
|
||||
func newGroup(s *Set, n string, modifiers ...GroupModifier) *Group {
|
||||
if s == nil {
|
||||
panic("group must be attached to set")
|
||||
}
|
||||
g := &Group{
|
||||
set: s,
|
||||
name: n,
|
||||
flags: []*Flag{},
|
||||
showGroupName: true,
|
||||
}
|
||||
|
||||
for _, fn := range modifiers {
|
||||
fn(g)
|
||||
}
|
||||
|
||||
s.groups = append(s.groups, g)
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
func (g *Group) Add(f *Flag) (err error) {
|
||||
if f.group == g {
|
||||
return nil
|
||||
}
|
||||
|
||||
if f.group != nil {
|
||||
idx := -1
|
||||
for i, flg := range f.group.flags {
|
||||
if flg.longName == f.longName {
|
||||
idx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if idx >= 0 {
|
||||
f.group.flags = append(f.group.flags[0:idx], f.group.flags[idx+1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
f.group = g
|
||||
g.flags = append(g.flags, f)
|
||||
return err
|
||||
}
|
||||
|
||||
func (g *Group) Name() string {
|
||||
return g.name
|
||||
}
|
||||
|
||||
func (g *Group) Flags() []*Flag {
|
||||
f := make([]*Flag, len(g.flags))
|
||||
copy(f, g.flags)
|
||||
return f
|
||||
}
|
||||
|
||||
func (g *Group) Bool(
|
||||
name string,
|
||||
modifiers ...FlagModifier,
|
||||
) *Flag {
|
||||
return newFlag(name, BooleanType, g, modifiers...)
|
||||
}
|
||||
|
||||
func (g *Group) BoolVar(
|
||||
name string,
|
||||
ptr *bool,
|
||||
modifiers ...FlagModifier,
|
||||
) *Flag {
|
||||
f := g.Bool(name, modifiers...)
|
||||
f.ptr = true
|
||||
f.value = ptr
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (g *Group) String(
|
||||
name string,
|
||||
modifiers ...FlagModifier,
|
||||
) *Flag {
|
||||
return newFlag(name, StringType, g, modifiers...)
|
||||
}
|
||||
|
||||
func (g *Group) StringVar(
|
||||
name string,
|
||||
ptr *string,
|
||||
modifiers ...FlagModifier,
|
||||
) *Flag {
|
||||
f := g.String(name, modifiers...)
|
||||
f.ptr = true
|
||||
f.value = ptr
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (g *Group) Array(
|
||||
name string,
|
||||
subtype Type,
|
||||
modifiers ...FlagModifier,
|
||||
) *Flag {
|
||||
modifiers = append(modifiers, SetSubtype(subtype))
|
||||
return newFlag(name, ArrayType, g, modifiers...)
|
||||
}
|
||||
|
||||
func (g *Group) ArrayVar(
|
||||
name string,
|
||||
subtype Type,
|
||||
ptr interface{},
|
||||
modifiers ...FlagModifier,
|
||||
) *Flag {
|
||||
f := g.Array(name, subtype, modifiers...)
|
||||
f.ptr = true
|
||||
f.value = ptr
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (g *Group) Float(
|
||||
name string,
|
||||
modifiers ...FlagModifier,
|
||||
) *Flag {
|
||||
return newFlag(name, StringType, g, modifiers...)
|
||||
}
|
||||
|
||||
func (g *Group) FloatVar(
|
||||
name string,
|
||||
ptr *float64,
|
||||
modifiers ...FlagModifier,
|
||||
) *Flag {
|
||||
f := g.Float(name, modifiers...)
|
||||
f.ptr = true
|
||||
f.value = ptr
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (g *Group) Integer(
|
||||
name string,
|
||||
modifiers ...FlagModifier,
|
||||
) *Flag {
|
||||
return newFlag(name, IntegerType, g, modifiers...)
|
||||
}
|
||||
|
||||
func (g *Group) IntegerVar(
|
||||
name string,
|
||||
ptr *int,
|
||||
modifiers ...FlagModifier,
|
||||
) *Flag {
|
||||
f := g.Integer(name, modifiers...)
|
||||
f.ptr = true
|
||||
f.value = ptr
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (g *Group) Increment(
|
||||
name string,
|
||||
modifiers ...FlagModifier,
|
||||
) *Flag {
|
||||
modifiers = append(modifiers, SetSubtype(IntegerType))
|
||||
return newFlag(name, IncrementType, g, modifiers...)
|
||||
}
|
||||
|
||||
func (g *Group) IncrementVar(
|
||||
name string,
|
||||
ptr *int,
|
||||
modifiers ...FlagModifier,
|
||||
) *Flag {
|
||||
f := g.Increment(name, modifiers...)
|
||||
f.ptr = true
|
||||
f.value = ptr
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (g *Group) Map(
|
||||
name string,
|
||||
subtype Type,
|
||||
modifiers ...FlagModifier,
|
||||
) *Flag {
|
||||
modifiers = append(modifiers, SetSubtype(subtype))
|
||||
return newFlag(name, MapType, g, modifiers...)
|
||||
}
|
||||
|
||||
func (g *Group) MapVar(
|
||||
name string,
|
||||
subtype Type,
|
||||
ptr *map[string]interface{},
|
||||
modifiers ...FlagModifier,
|
||||
) *Flag {
|
||||
f := g.Map(name, subtype, modifiers...)
|
||||
f.ptr = true
|
||||
f.value = ptr
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
// Generate printable output of flag group
|
||||
func (g *Group) Display(
|
||||
indent int, // Number of spaces to indent
|
||||
) string {
|
||||
var pad int
|
||||
opts := []string{}
|
||||
desc := []string{}
|
||||
|
||||
for i, f := range g.flags {
|
||||
if f.hidden {
|
||||
continue
|
||||
}
|
||||
if f.shortName != 0 {
|
||||
opts = append(opts, fmt.Sprintf("-%c,", f.shortName))
|
||||
} else {
|
||||
opts = append(opts, " ")
|
||||
}
|
||||
if f.kind == BooleanType {
|
||||
opts[i] = fmt.Sprintf("%s --[no-]%s", opts[i], f.longName)
|
||||
} else {
|
||||
opts[i] = fmt.Sprintf("%s --%s VALUE", opts[i], f.longName)
|
||||
}
|
||||
desc = append(desc, f.description)
|
||||
if len(opts[i]) > pad {
|
||||
pad = len(opts[i])
|
||||
}
|
||||
}
|
||||
|
||||
pad += indent
|
||||
var d string
|
||||
|
||||
if g.showGroupName {
|
||||
d = fmt.Sprintf("%s:\n", g.name)
|
||||
}
|
||||
|
||||
for i := 0; i < len(opts); i++ {
|
||||
d = fmt.Sprintf("%s%4s%-*s%s\n", d, "", pad, opts[i], desc[i])
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
381
internal/flags/set.go
Normal file
381
internal/flags/set.go
Normal file
@ -0,0 +1,381 @@
|
||||
package flags
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ErrorHandling uint
|
||||
|
||||
const INTERNAL_GROUP_NAME = "__internal__"
|
||||
|
||||
const (
|
||||
ReturnOnError ErrorHandling = iota
|
||||
PanicOnError
|
||||
)
|
||||
|
||||
type UnknownHandling uint
|
||||
|
||||
const (
|
||||
PassOnUnknown = iota
|
||||
ErrorOnUnknown
|
||||
)
|
||||
|
||||
type Set struct {
|
||||
errorHandling ErrorHandling
|
||||
flagMap map[string]*Flag
|
||||
groups []*Group
|
||||
name string
|
||||
parsed bool
|
||||
remaining []string
|
||||
unknownFlags []string
|
||||
unknownHandling UnknownHandling
|
||||
}
|
||||
|
||||
type SetModifier func(s *Set)
|
||||
type Visitor func(f *Flag)
|
||||
|
||||
func SetErrorMode(m ErrorHandling) SetModifier {
|
||||
return func(s *Set) {
|
||||
s.errorHandling = m
|
||||
}
|
||||
}
|
||||
|
||||
func SetUnknownMode(m UnknownHandling) SetModifier {
|
||||
return func(s *Set) {
|
||||
s.unknownHandling = m
|
||||
}
|
||||
}
|
||||
|
||||
func NewSet(name string, modifiers ...SetModifier) *Set {
|
||||
s := &Set{
|
||||
name: name,
|
||||
groups: []*Group{},
|
||||
errorHandling: ReturnOnError,
|
||||
flagMap: map[string]*Flag{},
|
||||
remaining: []string{},
|
||||
unknownHandling: ErrorOnUnknown,
|
||||
unknownFlags: []string{},
|
||||
}
|
||||
s.NewGroup(INTERNAL_GROUP_NAME, HideGroupName())
|
||||
|
||||
for _, m := range modifiers {
|
||||
m(s)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Name of this flag set
|
||||
func (s *Set) Name() string {
|
||||
return s.name
|
||||
}
|
||||
|
||||
// All defined groups within the set
|
||||
func (s *Set) Groups() []*Group {
|
||||
g := make([]*Group, len(s.groups))
|
||||
copy(g, s.groups)
|
||||
|
||||
return g
|
||||
}
|
||||
|
||||
// Visit flags that were updated either by CLI or
|
||||
// environment variable
|
||||
func (s *Set) Visit(fn Visitor) {
|
||||
for _, f := range s.Flags() {
|
||||
if f.Updated() {
|
||||
fn(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Visit flags that were set by the CLI only
|
||||
func (s *Set) VisitCalled(fn Visitor) {
|
||||
for _, f := range s.Flags() {
|
||||
if f.Called() {
|
||||
fn(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Visit all flags
|
||||
func (s *Set) VisitAll(fn Visitor) {
|
||||
for _, f := range s.Flags() {
|
||||
fn(f)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Set) AddGroup(g *Group) error {
|
||||
// Check that group hasn't already been added
|
||||
for _, cg := range s.groups {
|
||||
if g == cg {
|
||||
return fmt.Errorf("group already exists in set")
|
||||
}
|
||||
}
|
||||
// Remove the group from its current set
|
||||
idx := -1
|
||||
for i, cg := range g.set.groups {
|
||||
if cg == g {
|
||||
idx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if idx >= 0 {
|
||||
g.set.groups = append(g.set.groups[0:idx], g.set.groups[idx+1:]...)
|
||||
}
|
||||
|
||||
// Update the groups Set and add the group to this Set's groups
|
||||
g.set = s
|
||||
s.groups = append(s.groups, g)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add a new group
|
||||
func (s *Set) NewGroup(name string, modifiers ...GroupModifier) error {
|
||||
for _, g := range s.groups {
|
||||
if g.name == name {
|
||||
return fmt.Errorf("flag group already exists with name %s", name)
|
||||
}
|
||||
}
|
||||
newGroup(s, name, modifiers...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Default group for flags. The default group does
|
||||
// not include a title section when displayed
|
||||
func (s *Set) DefaultGroup() *Group {
|
||||
if len(s.groups) < 1 {
|
||||
panic("default group does not exist")
|
||||
}
|
||||
return s.groups[0]
|
||||
}
|
||||
|
||||
// All defined flags within the set
|
||||
func (s *Set) Flags() []*Flag {
|
||||
f := []*Flag{}
|
||||
for _, g := range s.groups {
|
||||
f = append(f, g.flags...)
|
||||
}
|
||||
|
||||
return f
|
||||
}
|
||||
|
||||
func (s *Set) Flag(n string) (f *Flag, err error) {
|
||||
if s.parsed {
|
||||
f = s.flagMap[n]
|
||||
} else {
|
||||
for _, flg := range s.Flags() {
|
||||
if flg.longName == n {
|
||||
f = flg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if f == nil {
|
||||
err = fmt.Errorf("failed to locate flag named: %s", n)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Generate flag usage output
|
||||
func (s *Set) Display() (o string) {
|
||||
for _, g := range s.groups {
|
||||
o += g.Display(11)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Parse the command line options. The remaining arguments will
|
||||
// be non-flag arguments, or if the unkown handling allows for
|
||||
// passing, it will include unused flag/values and arguments.
|
||||
func (s *Set) Parse(args []string) (remaining []string, err error) {
|
||||
defer func() {
|
||||
if err != nil && s.errorHandling == PanicOnError {
|
||||
panic(err)
|
||||
}
|
||||
}()
|
||||
// We only allow a set to parse once
|
||||
if s.parsed {
|
||||
return nil, fmt.Errorf("Set has already parsed arguments")
|
||||
}
|
||||
// Initialize all the flags. Errors returned from here
|
||||
// are either flag initialization issues or flag name
|
||||
// collisions
|
||||
if err = s.initFlags(); err != nil {
|
||||
return
|
||||
}
|
||||
// Now we start parsing
|
||||
for i := 0; i < len(args); i++ {
|
||||
w := args[i]
|
||||
|
||||
// If the argument is the `--` separator, we stop parsing
|
||||
// and add the unprocessed arguments to the remaining list
|
||||
// to be returned
|
||||
if w == "--" {
|
||||
if i+1 < len(args) {
|
||||
// The remaining arguments may already be populated with
|
||||
// previously encountered unknown flags if the set is
|
||||
// configured for pass through. In that situation, we
|
||||
// want to retain the `--` separater
|
||||
if len(s.remaining) > 0 {
|
||||
s.remaining = append(s.remaining, args[i:]...)
|
||||
} else {
|
||||
s.remaining = append(s.remaining, args[i+1:]...)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
// Handle long name flag
|
||||
if strings.HasPrefix(w, "--") {
|
||||
var valueNext bool
|
||||
var name, value string
|
||||
flag := strings.Replace(w, "--", "", 1)
|
||||
if strings.Contains(flag, "=") {
|
||||
parts := strings.SplitN(flag, "=", 2)
|
||||
name, value = parts[0], parts[1]
|
||||
} else {
|
||||
name = flag
|
||||
valueNext = true
|
||||
}
|
||||
|
||||
f, ok := s.flagMap[name]
|
||||
// If the flag is not found check if we should error
|
||||
if !ok {
|
||||
if err = s.flagNotFound(name); err != nil {
|
||||
return
|
||||
}
|
||||
// Since we haven't errored, add flag to remaining
|
||||
s.remaining = append(s.remaining, w)
|
||||
s.unknownFlags = append(s.unknownFlags, name)
|
||||
continue
|
||||
}
|
||||
switch f.kind {
|
||||
case BooleanType:
|
||||
// Since boolean types can be negated, check the flag
|
||||
// name to set the correct value
|
||||
if strings.HasPrefix(name, "no-") {
|
||||
value = "false"
|
||||
} else {
|
||||
value = "true"
|
||||
}
|
||||
case IncrementType:
|
||||
// Increment values don't matter, so just set as 1
|
||||
value = "1"
|
||||
default:
|
||||
// If the value was not included in the argument (argument form was not --flag=VAL)
|
||||
// then we need to get the value from the next argument
|
||||
if valueNext {
|
||||
if i+1 >= len(args) {
|
||||
return nil, fmt.Errorf("missing argument for flag `--%s`", f.longName)
|
||||
}
|
||||
i += 1
|
||||
value = args[i]
|
||||
}
|
||||
}
|
||||
// Mark the flag as being called on the CLI and the name used
|
||||
f.markCalled(name)
|
||||
// And finally, set the value
|
||||
if err = f.setValue(value); err != nil {
|
||||
return
|
||||
}
|
||||
} else if strings.HasPrefix(w, "-") {
|
||||
// For short flags, multiple patterns can be used. Valid examples:
|
||||
//
|
||||
// Boolean/Increment types can be chained: -vvvbx (-v -v -v -b -x)
|
||||
// Other types can include value in argument: -aVAL
|
||||
// Chaining can be used for both: -vvvbxaVAL
|
||||
wordLoop:
|
||||
for j := 1; j < len(w); j++ {
|
||||
c := string(w[j])
|
||||
f, ok := s.flagMap[c]
|
||||
// If the flag was not found check if we should error
|
||||
if !ok {
|
||||
if err = s.flagNotFound(c); err != nil {
|
||||
return
|
||||
}
|
||||
// Add the unprocessed to remaining
|
||||
s.remaining = append(s.remaining, "-"+w[j:])
|
||||
// Only add the flag we encountered that was unknown
|
||||
s.unknownFlags = append(s.unknownFlags, c)
|
||||
continue
|
||||
}
|
||||
|
||||
// Mark the flag as being called on the CLI and the name used
|
||||
f.markCalled(c)
|
||||
|
||||
switch f.kind {
|
||||
case BooleanType:
|
||||
err = f.setValue("true")
|
||||
case IncrementType:
|
||||
err = f.setValue("1")
|
||||
default:
|
||||
// Check if we have anything left in this argument. If we do, it is the value.
|
||||
// Otherwise, get the value from the next argument.
|
||||
if len(w)-1 == j {
|
||||
if i+1 >= len(args) {
|
||||
return nil, fmt.Errorf("missing argument for flag `-%s", string(f.shortName))
|
||||
}
|
||||
i += 1
|
||||
err = f.setValue(args[i])
|
||||
} else {
|
||||
err = f.setValue(w[j+1:])
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
break wordLoop
|
||||
}
|
||||
// If an error was encountered, bail out
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
} else {
|
||||
s.remaining = append(s.remaining, w)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: need to validate for required flags
|
||||
|
||||
s.parsed = true
|
||||
|
||||
return s.remaining, nil
|
||||
}
|
||||
|
||||
func (s *Set) flagNotFound(name string) error {
|
||||
if s.unknownHandling == ErrorOnUnknown {
|
||||
return fmt.Errorf("unknown flag encountered `%s`", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Set) initFlags() error {
|
||||
for _, f := range s.Flags() {
|
||||
if err := f.init(); err != nil {
|
||||
return err
|
||||
}
|
||||
names := make([]string, len(f.aliases))
|
||||
copy(names, f.aliases)
|
||||
names = append(names, f.longName)
|
||||
if f.shortName != 0 {
|
||||
names = append(names, string(f.shortName))
|
||||
}
|
||||
for _, n := range names {
|
||||
if cf, ok := s.flagMap[n]; ok {
|
||||
var colFlag string
|
||||
if len(n) == 1 {
|
||||
colFlag = "-" + n
|
||||
} else {
|
||||
colFlag = "--" + n
|
||||
}
|
||||
|
||||
return fmt.Errorf("flags --%s and --%s share a common flag (collision on %s)",
|
||||
f.longName, cf.longName, colFlag)
|
||||
}
|
||||
s.flagMap[n] = f
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
541
internal/flags/set_test.go
Normal file
541
internal/flags/set_test.go
Normal file
@ -0,0 +1,541 @@
|
||||
package flags
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_NewSet(t *testing.T) {
|
||||
s := testSet()
|
||||
if s.name != "testing-set" {
|
||||
t.Errorf("invalid name - testing-set != %s", s.name)
|
||||
}
|
||||
if len(s.groups) < 1 {
|
||||
t.Fatalf("default group does not exist")
|
||||
}
|
||||
if s.groups[0].name != INTERNAL_GROUP_NAME {
|
||||
t.Errorf("invalid default group - %s != %s", INTERNAL_GROUP_NAME, s.groups[0].name)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SetErrorMode(t *testing.T) {
|
||||
s := testSet()
|
||||
if s.errorHandling != ReturnOnError {
|
||||
t.Errorf("invalid error handling - %d != %d", ReturnOnError, s.errorHandling)
|
||||
}
|
||||
SetErrorMode(PanicOnError)(s)
|
||||
if s.errorHandling != PanicOnError {
|
||||
t.Errorf("invalid error handling - %d != %d", PanicOnError, s.errorHandling)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_SetUnknownMode(t *testing.T) {
|
||||
s := testSet()
|
||||
if s.unknownHandling != ErrorOnUnknown {
|
||||
t.Errorf("invalid unknown handling - %d != %d", ErrorOnUnknown, s.unknownHandling)
|
||||
}
|
||||
SetUnknownMode(PassOnUnknown)(s)
|
||||
if s.unknownHandling != PassOnUnknown {
|
||||
t.Errorf("invalid unknown handling - %d != %d", PassOnUnknown, s.unknownHandling)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_Name(t *testing.T) {
|
||||
s := testSet()
|
||||
s.name = "my-set"
|
||||
if s.Name() != "my-set" {
|
||||
t.Errorf("invalid name - my-set != %s", s.Name())
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_Groups(t *testing.T) {
|
||||
s := testSet()
|
||||
if len(s.Groups()) != 1 {
|
||||
t.Fatalf("invalid groups length - 1 != %d", len(s.Groups()))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_Visit(t *testing.T) {
|
||||
s := testSet()
|
||||
g := s.groups[0]
|
||||
for i := 0; i < 5; i++ {
|
||||
f := testFlag(g)
|
||||
f.longName = fmt.Sprintf("test-flag-%d", i)
|
||||
if i > 2 {
|
||||
f.updated = true
|
||||
}
|
||||
if i > 3 {
|
||||
f.called = true
|
||||
}
|
||||
}
|
||||
seen := []string{}
|
||||
s.Visit(func(f *Flag) {
|
||||
seen = append(seen, f.longName)
|
||||
})
|
||||
if len(seen) != 2 {
|
||||
t.Errorf("invalid number of flags seen - 2 != %d", len(seen))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_VisitCalled(t *testing.T) {
|
||||
s := testSet()
|
||||
g := s.groups[0]
|
||||
for i := 0; i < 5; i++ {
|
||||
f := testFlag(g)
|
||||
f.longName = fmt.Sprintf("test-flag-%d", i)
|
||||
if i > 2 {
|
||||
f.updated = true
|
||||
}
|
||||
if i > 3 {
|
||||
f.called = true
|
||||
}
|
||||
}
|
||||
seen := []string{}
|
||||
s.VisitCalled(func(f *Flag) {
|
||||
seen = append(seen, f.longName)
|
||||
})
|
||||
if len(seen) != 1 {
|
||||
t.Errorf("invalid number of flags seen - 1 != %d", len(seen))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_VisitAll(t *testing.T) {
|
||||
s := testSet()
|
||||
g := s.groups[0]
|
||||
for i := 0; i < 5; i++ {
|
||||
f := testFlag(g)
|
||||
f.longName = fmt.Sprintf("test-flag-%d", i)
|
||||
if i > 2 {
|
||||
f.updated = true
|
||||
}
|
||||
if i > 3 {
|
||||
f.called = true
|
||||
}
|
||||
}
|
||||
seen := []string{}
|
||||
s.VisitAll(func(f *Flag) {
|
||||
seen = append(seen, f.longName)
|
||||
})
|
||||
if len(seen) != 5 {
|
||||
t.Errorf("invalid number of flags seen - 5 != %d", len(seen))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_CreateGroup(t *testing.T) {
|
||||
s := testSet()
|
||||
if err := s.NewGroup("test-group"); err != nil {
|
||||
t.Fatalf("failed to create new group: %s", err)
|
||||
}
|
||||
if len(s.groups) != 2 {
|
||||
t.Fatalf("invalid groups length - 2 != %d", len(s.groups))
|
||||
}
|
||||
if s.groups[1].name != "test-group" {
|
||||
t.Errorf("invalid group name - test-group != %s", s.groups[1].name)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_CreateGroup_duplicate(t *testing.T) {
|
||||
n := "test-group-name"
|
||||
s := testSet()
|
||||
if err := s.NewGroup(n); err != nil {
|
||||
t.Fatalf("failed to create new group: %s", err)
|
||||
}
|
||||
if err := s.NewGroup(n); err == nil {
|
||||
t.Fatalf("expected error but no error returned")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_DefaultGroup(t *testing.T) {
|
||||
s := testSet()
|
||||
if s.DefaultGroup().name != INTERNAL_GROUP_NAME {
|
||||
t.Errorf("invalid default group name - %s != %s", INTERNAL_GROUP_NAME, s.name)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_Flags(t *testing.T) {
|
||||
s := testSet()
|
||||
if err := s.NewGroup("test-group"); err != nil {
|
||||
t.Fatalf("failed to create new group: %s", err)
|
||||
}
|
||||
for i := 0; i < 5; i++ {
|
||||
testFlag(s.groups[0])
|
||||
testFlag(s.groups[1])
|
||||
}
|
||||
if len(s.Flags()) != 10 {
|
||||
t.Errorf("invalid flags length - 10 != %d", len(s.Flags()))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_Parse(t *testing.T) {
|
||||
s := testSet()
|
||||
r, err := s.Parse([]string{})
|
||||
if len(r) != 0 {
|
||||
t.Errorf("invalid remaining args - 0 != %d", len(r))
|
||||
}
|
||||
if err != nil {
|
||||
t.Errorf("unexpected parse error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_Parse_no_flags(t *testing.T) {
|
||||
s := testSet()
|
||||
r, err := s.Parse([]string{"some-arg"})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected parse error: %s", err)
|
||||
}
|
||||
if len(r) != 1 {
|
||||
t.Fatalf("invalid remaining args - 1 != %d", len(r))
|
||||
}
|
||||
if r[0] != "some-arg" {
|
||||
t.Errorf("invalid remaining value - some-arg != %s", r[0])
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_Parse_multi_error(t *testing.T) {
|
||||
s := testSet()
|
||||
if _, err := s.Parse([]string{}); err != nil {
|
||||
t.Fatalf("unexpected parse error: %s", err)
|
||||
}
|
||||
if _, err := s.Parse([]string{}); err == nil {
|
||||
t.Errorf("expected error but no error returned")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_Parse_multi_panic(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Errorf("expected panic but no panic recovered")
|
||||
}
|
||||
}()
|
||||
s := testSet()
|
||||
s.errorHandling = PanicOnError
|
||||
if _, err := s.Parse([]string{}); err != nil {
|
||||
t.Fatalf("unexpected parse error: %s", err)
|
||||
}
|
||||
if _, err := s.Parse([]string{}); err != nil {
|
||||
t.Errorf("expected panic from parse but received error: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_Parse_single_bool(t *testing.T) {
|
||||
s := testSet()
|
||||
s.DefaultGroup().Bool("mark")
|
||||
r, err := s.Parse([]string{"--mark"})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected parse error: %s", err)
|
||||
}
|
||||
if len(r) > 0 {
|
||||
t.Errorf("invalid remaining args - 0 != %d", len(r))
|
||||
}
|
||||
if !s.Flags()[0].Value().(bool) {
|
||||
t.Errorf("invalid flag value - true != false")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_Parse_single_bool_extra_arg(t *testing.T) {
|
||||
s := testSet()
|
||||
s.DefaultGroup().Bool("mark")
|
||||
r, err := s.Parse([]string{"--mark", "extra-arg"})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected parse error: %s", err)
|
||||
}
|
||||
if len(r) != 1 {
|
||||
t.Fatalf("invalid remaining args length - 1 != %d", len(r))
|
||||
}
|
||||
if r[0] != "extra-arg" {
|
||||
t.Errorf("invalid remaining arg - extra-arg != %s", r[0])
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_flagNotFound(t *testing.T) {
|
||||
s := testSet()
|
||||
s.unknownHandling = ErrorOnUnknown
|
||||
if err := s.flagNotFound("mark"); err == nil {
|
||||
t.Errorf("expected error but no error returned")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_flagNotFound_pass(t *testing.T) {
|
||||
s := testSet()
|
||||
s.unknownHandling = PassOnUnknown
|
||||
if err := s.flagNotFound("mark"); err != nil {
|
||||
t.Errorf("expected no error but error was returned: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_initFlags(t *testing.T) {
|
||||
s := testSet()
|
||||
s.DefaultGroup().Bool("mark")
|
||||
s.DefaultGroup().String("entry")
|
||||
for _, f := range s.Flags() {
|
||||
if f.value != nil {
|
||||
t.Fatalf("expected value to be nil before init (%#v)", f.value)
|
||||
}
|
||||
}
|
||||
if err := s.initFlags(); err != nil {
|
||||
t.Fatalf("unexpected init error: %s", err)
|
||||
}
|
||||
for _, f := range s.Flags() {
|
||||
if f.value == nil {
|
||||
t.Errorf("flag value should not be nil - flag: %s", f.longName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_initFlags_bool_negated(t *testing.T) {
|
||||
s := testSet()
|
||||
s.DefaultGroup().Bool("mark")
|
||||
if err := s.initFlags(); err != nil {
|
||||
t.Fatalf("unexpected init error: %s", err)
|
||||
}
|
||||
if _, ok := s.flagMap["no-mark"]; !ok {
|
||||
t.Errorf("negated boolean flag not found")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_initFlags_collision_long(t *testing.T) {
|
||||
s := testSet()
|
||||
s.DefaultGroup().Bool("mark")
|
||||
s.DefaultGroup().String("mark")
|
||||
if err := s.initFlags(); err == nil {
|
||||
t.Errorf("expected error but no error returned")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_initFlags_collision_short(t *testing.T) {
|
||||
s := testSet()
|
||||
s.DefaultGroup().Bool("mark", ShortName('m'))
|
||||
s.DefaultGroup().String("entry", ShortName('m'))
|
||||
if err := s.initFlags(); err == nil {
|
||||
t.Errorf("expected error but no error returned")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_initFlags_collision_long_alias(t *testing.T) {
|
||||
s := testSet()
|
||||
s.DefaultGroup().Bool("mark", Alias("thing"))
|
||||
s.DefaultGroup().String("entry", Alias("thing"))
|
||||
if err := s.initFlags(); err == nil {
|
||||
t.Errorf("expected error but no error returned")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_initFlags_collision_short_alias(t *testing.T) {
|
||||
s := testSet()
|
||||
s.DefaultGroup().Bool("mark", ShortName('m'))
|
||||
s.DefaultGroup().String("entry", Alias("m"))
|
||||
if err := s.initFlags(); err == nil {
|
||||
t.Errorf("expected error but no error returned")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_initFlags_collision_bool_negate_long(t *testing.T) {
|
||||
s := testSet()
|
||||
s.DefaultGroup().Bool("mark")
|
||||
s.DefaultGroup().String("no-mark")
|
||||
if err := s.initFlags(); err == nil {
|
||||
t.Errorf("expected error but no error returned")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_Parse_unknown_error(t *testing.T) {
|
||||
s := testSet()
|
||||
s.unknownHandling = ErrorOnUnknown
|
||||
s.errorHandling = ReturnOnError
|
||||
s.DefaultGroup().Bool("mark")
|
||||
if _, err := s.Parse([]string{"--entry"}); err == nil {
|
||||
t.Errorf("expected error but no error returned")
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Set_Parse_unknown_panic(t *testing.T) {
|
||||
defer func() {
|
||||
if r := recover(); r == nil {
|
||||
t.Fatalf("expected panic but no panic recovered")
|
||||
}
|
||||
}()
|
||||
s := testSet()
|
||||
s.unknownHandling = ErrorOnUnknown
|
||||
s.errorHandling = PanicOnError
|
||||
s.DefaultGroup().Bool("mark")
|
||||
s.Parse([]string{"--entry"})
|
||||
}
|
||||
|
||||
func Test_Set_Parse_unknown_pass(t *testing.T) {
|
||||
s := testSet()
|
||||
s.unknownHandling = PassOnUnknown
|
||||
s.DefaultGroup().Bool("mark")
|
||||
r, err := s.Parse([]string{"--entry", "VALUE"})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected parse error: %s", err)
|
||||
}
|
||||
if len(r) != 2 {
|
||||
t.Fatalf("invalid remaining length - 2 != %d", len(r))
|
||||
}
|
||||
if r[0] != "--entry" {
|
||||
t.Errorf("invalid arg value - --entry != %s", r[0])
|
||||
}
|
||||
if r[1] != "VALUE" {
|
||||
t.Errorf("invalid arg value - VALUE != %s", r[1])
|
||||
}
|
||||
if len(s.unknownFlags) != 1 {
|
||||
t.Fatalf("invalid unknown flags length - 1 != %d", len(s.unknownFlags))
|
||||
}
|
||||
if s.unknownFlags[0] != "entry" {
|
||||
t.Errorf("invalid unknown flags value - entry != %s", s.unknownFlags[0])
|
||||
}
|
||||
}
|
||||
|
||||
// -vvv --entry eVALUE --mark -x xVALUE -y
|
||||
func Test_Set_Parse_1(t *testing.T) {
|
||||
s := testSet()
|
||||
s.DefaultGroup().Increment("verbosity", ShortName('v'))
|
||||
s.DefaultGroup().String("entry")
|
||||
s.DefaultGroup().Bool("mark")
|
||||
s.DefaultGroup().String("xylophone", ShortName('x'))
|
||||
s.DefaultGroup().Bool("yesterday", ShortName('y'))
|
||||
if _, err := s.Parse([]string{"-vvv", "--entry", "eVALUE", "--mark", "-x", "xVALUE", "-y"}); err != nil {
|
||||
t.Fatalf("unexpected parse error: %s", err)
|
||||
}
|
||||
for _, f := range s.Flags() {
|
||||
switch f.longName {
|
||||
case "verbosity":
|
||||
if f.Value().(int64) != 3 {
|
||||
t.Errorf("invalid verbosity value - 3 != %#v", f.Value())
|
||||
}
|
||||
case "entry":
|
||||
if f.Value().(string) != "eVALUE" {
|
||||
t.Errorf("invalid entry value - eVALUE != %#v", f.Value())
|
||||
}
|
||||
case "mark":
|
||||
if f.Value().(bool) != true {
|
||||
t.Errorf("invalid mark value - true != %#v", f.Value())
|
||||
}
|
||||
case "xylophone":
|
||||
if f.Value().(string) != "xVALUE" {
|
||||
t.Errorf("invalid xylophone value - xVALUE != %#v", f.Value())
|
||||
}
|
||||
case "yesterday":
|
||||
if f.Value().(bool) != true {
|
||||
t.Errorf("invalid yesterday value - true != %#v", f.Value())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -vvyvvxxVALUE --mark --entry=EVALUE
|
||||
func Test_Set_Parse_2(t *testing.T) {
|
||||
s := testSet()
|
||||
s.DefaultGroup().Increment("verbosity", ShortName('v'))
|
||||
s.DefaultGroup().String("entry")
|
||||
s.DefaultGroup().Bool("mark")
|
||||
s.DefaultGroup().String("xylophone", ShortName('x'))
|
||||
s.DefaultGroup().Bool("yesterday", ShortName('y'))
|
||||
if _, err := s.Parse([]string{"-vvyvvxxVALUE", "--mark", "--entry=EVALUE"}); err != nil {
|
||||
t.Fatalf("unexpected parse error: %s", err)
|
||||
}
|
||||
for _, f := range s.Flags() {
|
||||
switch f.longName {
|
||||
case "verbosity":
|
||||
if f.Value().(int64) != 4 {
|
||||
t.Errorf("invalid verbosity value - 4 != %#v", f.Value())
|
||||
}
|
||||
case "entry":
|
||||
if f.Value().(string) != "EVALUE" {
|
||||
t.Errorf("invalid entry value - EVALUE != %#v", f.Value())
|
||||
}
|
||||
case "mark":
|
||||
if f.Value().(bool) != true {
|
||||
t.Errorf("invalid mark value - true != %#v", f.Value())
|
||||
}
|
||||
case "xylophone":
|
||||
if f.Value().(string) != "xVALUE" {
|
||||
t.Errorf("invalid xylophone value - xVALUE != %#v", f.Value())
|
||||
}
|
||||
case "yesterday":
|
||||
if f.Value().(bool) != true {
|
||||
t.Errorf("invalid yesterday value - true != %#v", f.Value())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -vvyv --xylophone xVALUE --entry=EVALUE -mv
|
||||
func Test_Set_Parse_3(t *testing.T) {
|
||||
s := testSet()
|
||||
s.DefaultGroup().Increment("verbosity", ShortName('v'))
|
||||
s.DefaultGroup().String("entry")
|
||||
s.DefaultGroup().Bool("mark", ShortName('m'))
|
||||
s.DefaultGroup().String("xylophone", ShortName('x'))
|
||||
s.DefaultGroup().Bool("yesterday", ShortName('y'))
|
||||
if _, err := s.Parse([]string{"-vvyv", "--xylophone", "xVALUE", "--entry=EVALUE", "-mv"}); err != nil {
|
||||
t.Fatalf("unexpected parse error: %s", err)
|
||||
}
|
||||
for _, f := range s.Flags() {
|
||||
switch f.longName {
|
||||
case "verbosity":
|
||||
if f.Value().(int64) != 4 {
|
||||
t.Errorf("invalid verbosity value - 4 != %#v", f.Value())
|
||||
}
|
||||
case "entry":
|
||||
if f.Value().(string) != "EVALUE" {
|
||||
t.Errorf("invalid entry value - EVALUE != %#v", f.Value())
|
||||
}
|
||||
case "mark":
|
||||
if f.Value().(bool) != true {
|
||||
t.Errorf("invalid mark value - true != %#v", f.Value())
|
||||
}
|
||||
case "xylophone":
|
||||
if f.Value().(string) != "xVALUE" {
|
||||
t.Errorf("invalid xylophone value - xVALUE != %#v", f.Value())
|
||||
}
|
||||
case "yesterday":
|
||||
if f.Value().(bool) != true {
|
||||
t.Errorf("invalid yesterday value - true != %#v", f.Value())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --entry 3.14 --hash ping=pong --hash=fee=fi --entry=99.9
|
||||
func Test_Set_Parse_4(t *testing.T) {
|
||||
s := testSet()
|
||||
s.DefaultGroup().Array("entry", FloatType)
|
||||
s.DefaultGroup().Map("hash", StringType)
|
||||
if _, err := s.Parse([]string{"--entry", "3.14", "--hash", "ping=pong", "--hash=fee=fi", "--entry=99.9"}); err != nil {
|
||||
t.Fatalf("unexpected parse error: %s", err)
|
||||
}
|
||||
for _, f := range s.Flags() {
|
||||
switch f.longName {
|
||||
case "entry":
|
||||
v := f.Value().([]float64)
|
||||
if len(v) != 2 {
|
||||
t.Fatalf("invalid entry length - 2 != %d", len(v))
|
||||
}
|
||||
if v[0] != 3.14 {
|
||||
t.Errorf("invalid entry value - 3.14 != %#v", v)
|
||||
}
|
||||
if v[1] != 99.9 {
|
||||
t.Errorf("invalid entry value - 99.9 != %#v", v)
|
||||
}
|
||||
case "hash":
|
||||
h := f.Value().(map[string]string)
|
||||
if v, ok := h["ping"]; !ok {
|
||||
t.Errorf("invalid hash value - missing ping key")
|
||||
} else {
|
||||
if v != "pong" {
|
||||
t.Errorf("invalid hash value - pong != %#v", v)
|
||||
}
|
||||
}
|
||||
if v, ok := h["fee"]; !ok {
|
||||
t.Errorf("invalid hash value - missing fee key")
|
||||
} else {
|
||||
if v != "fi" {
|
||||
t.Errorf("invalid hash value - fi != %#v", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add some complex usage tests which include flag modifiers
|
||||
30
internal/flags/type_string.go
Normal file
30
internal/flags/type_string.go
Normal file
@ -0,0 +1,30 @@
|
||||
// Code generated by "stringer -type=Type -linecomment ./internal/flags"; DO NOT EDIT.
|
||||
|
||||
package flags
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[UnsetType-0]
|
||||
_ = x[ArrayType-1]
|
||||
_ = x[BooleanType-2]
|
||||
_ = x[FloatType-3]
|
||||
_ = x[IncrementType-4]
|
||||
_ = x[IntegerType-5]
|
||||
_ = x[MapType-6]
|
||||
_ = x[StringType-7]
|
||||
}
|
||||
|
||||
const _Type_name = "UnsetArrayBooleanFloatIncrementIntegerMapString"
|
||||
|
||||
var _Type_index = [...]uint8{0, 5, 10, 17, 22, 31, 38, 41, 47}
|
||||
|
||||
func (i Type) String() string {
|
||||
if i >= Type(len(_Type_index)-1) {
|
||||
return "Type(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _Type_name[_Type_index[i]:_Type_index[i+1]]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user