diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e404f35 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,22 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +- `Added` for new features. +- `Changed` for changes in existing functionality. +- `Deprecated` for soon-to-be removed features. +- `Removed` for now removed features. +- `Fixed` for any bug fixes. +- `Security` in case of vulnerabilities. + +## [Unreleased] + +### Added +- Added support for slice flags. Added by @zkep in [PR](https://github.com/leaanthony/clir/pull/23) + +### Fixed + +### Changed \ No newline at end of file diff --git a/command.go b/command.go index 41b435d..5ac8754 100644 --- a/command.go +++ b/command.go @@ -26,6 +26,7 @@ type Command struct { helpFlag bool hidden bool positionalArgsMap map[string]reflect.Value + sliceSeparator map[string]string } // NewCommand creates a new Command @@ -37,6 +38,7 @@ func NewCommand(name string, description string) *Command { subCommandsMap: make(map[string]*Command), hidden: false, positionalArgsMap: make(map[string]reflect.Value), + sliceSeparator: make(map[string]string), } return result @@ -284,7 +286,11 @@ func (c *Command) AddFlags(optionStruct interface{}) *Command { description := tag.Get("description") defaultValue := tag.Get("default") pos := tag.Get("pos") + sep := tag.Get("sep") c.positionalArgsMap[pos] = field + if sep != "" { + c.sliceSeparator[pos] = sep + } if name == "" { name = strings.ToLower(t.Elem().Field(i).Name) } @@ -316,12 +322,42 @@ func (c *Command) AddFlags(optionStruct interface{}) *Command { field.SetInt(int64(value)) } c.IntFlag(name, description, field.Addr().Interface().(*int)) + case reflect.Int8: + if defaultValue != "" { + // set value of field to default value + value, err := strconv.Atoi(defaultValue) + if err != nil { + panic("Invalid default value for int8 flag") + } + field.SetInt(int64(value)) + } + c.Int8Flag(name, description, field.Addr().Interface().(*int8)) + case reflect.Int16: + if defaultValue != "" { + // set value of field to default value + value, err := strconv.Atoi(defaultValue) + if err != nil { + panic("Invalid default value for int16 flag") + } + field.SetInt(int64(value)) + } + c.Int16Flag(name, description, field.Addr().Interface().(*int16)) + case reflect.Int32: + if defaultValue != "" { + // set value of field to default value + value, err := strconv.Atoi(defaultValue) + if err != nil { + panic("Invalid default value for int32 flag") + } + field.SetInt(int64(value)) + } + c.Int32Flag(name, description, field.Addr().Interface().(*int32)) case reflect.Int64: if defaultValue != "" { // set value of field to default value value, err := strconv.Atoi(defaultValue) if err != nil { - panic("Invalid default value for int flag") + panic("Invalid default value for int64 flag") } field.SetInt(int64(value)) } @@ -331,34 +367,77 @@ func (c *Command) AddFlags(optionStruct interface{}) *Command { // set value of field to default value value, err := strconv.Atoi(defaultValue) if err != nil { - panic("Invalid default value for int flag") + panic("Invalid default value for uint flag") } field.SetUint(uint64(value)) } c.UintFlag(name, description, field.Addr().Interface().(*uint)) + case reflect.Uint8: + if defaultValue != "" { + // set value of field to default value + value, err := strconv.Atoi(defaultValue) + if err != nil { + panic("Invalid default value for uint8 flag") + } + field.SetUint(uint64(value)) + } + c.Uint8Flag(name, description, field.Addr().Interface().(*uint8)) + case reflect.Uint16: + if defaultValue != "" { + // set value of field to default value + value, err := strconv.Atoi(defaultValue) + if err != nil { + panic("Invalid default value for uint16 flag") + } + field.SetUint(uint64(value)) + } + c.Uint16Flag(name, description, field.Addr().Interface().(*uint16)) + case reflect.Uint32: + if defaultValue != "" { + // set value of field to default value + value, err := strconv.Atoi(defaultValue) + if err != nil { + panic("Invalid default value for uint32 flag") + } + field.SetUint(uint64(value)) + } + c.Uint32Flag(name, description, field.Addr().Interface().(*uint32)) case reflect.Uint64: if defaultValue != "" { // set value of field to default value value, err := strconv.Atoi(defaultValue) if err != nil { - panic("Invalid default value for int flag") + panic("Invalid default value for uint64 flag") } field.SetUint(uint64(value)) } c.UInt64Flag(name, description, field.Addr().Interface().(*uint64)) + case reflect.Float32: + if defaultValue != "" { + // set value of field to default value + value, err := strconv.ParseFloat(defaultValue, 64) + if err != nil { + panic("Invalid default value for float32 flag") + } + field.SetFloat(value) + } + c.Float32Flag(name, description, field.Addr().Interface().(*float32)) case reflect.Float64: if defaultValue != "" { // set value of field to default value value, err := strconv.ParseFloat(defaultValue, 64) if err != nil { - panic("Invalid default value for float flag") + panic("Invalid default value for float64 flag") } field.SetFloat(value) } c.Float64Flag(name, description, field.Addr().Interface().(*float64)) + case reflect.Slice: + c.addSliceField(field, defaultValue, sep) + c.addSliceFlags(name, description, field) default: if pos != "" { - println("WARNING: Unsupported type for flag: ", fieldType.Type.Kind()) + println("WARNING: Unsupported type for flag: ", fieldType.Type.Kind(), name) } } } @@ -366,6 +445,209 @@ func (c *Command) AddFlags(optionStruct interface{}) *Command { return c } +func (c *Command) addSliceFlags(name, description string, field reflect.Value) *Command { + if field.Kind() != reflect.Slice { + panic("addSliceFlags() requires a pointer to a slice") + } + t := reflect.TypeOf(field.Addr().Interface()) + if t.Kind() != reflect.Ptr { + panic("addSliceFlags() requires a pointer to a slice") + } + if t.Elem().Kind() != reflect.Slice { + panic("addSliceFlags() requires a pointer to a slice") + } + switch t.Elem().Elem().Kind() { + case reflect.Bool: + c.BoolsFlag(name, description, field.Addr().Interface().(*[]bool)) + case reflect.String: + c.StringsFlag(name, description, field.Addr().Interface().(*[]string)) + case reflect.Int: + c.IntsFlag(name, description, field.Addr().Interface().(*[]int)) + case reflect.Int8: + c.Int8sFlag(name, description, field.Addr().Interface().(*[]int8)) + case reflect.Int16: + c.Int16sFlag(name, description, field.Addr().Interface().(*[]int16)) + case reflect.Int32: + c.Int32sFlag(name, description, field.Addr().Interface().(*[]int32)) + case reflect.Int64: + c.Int64sFlag(name, description, field.Addr().Interface().(*[]int64)) + case reflect.Uint: + c.UintsFlag(name, description, field.Addr().Interface().(*[]uint)) + case reflect.Uint8: + c.Uint8sFlag(name, description, field.Addr().Interface().(*[]uint8)) + case reflect.Uint16: + c.Uint16sFlag(name, description, field.Addr().Interface().(*[]uint16)) + case reflect.Uint32: + c.Uint32sFlag(name, description, field.Addr().Interface().(*[]uint32)) + case reflect.Uint64: + c.Uint64sFlag(name, description, field.Addr().Interface().(*[]uint64)) + case reflect.Float32: + c.Float32sFlag(name, description, field.Addr().Interface().(*[]float32)) + case reflect.Float64: + c.Float64sFlag(name, description, field.Addr().Interface().(*[]float64)) + default: + panic(fmt.Sprintf("addSliceFlags() not supported slice type %s", t.Elem().Elem().Kind().String())) + } + return c +} + +func (c *Command) addSliceField(field reflect.Value, defaultValue, separator string) *Command { + if defaultValue == "" { + return c + } + if field.Kind() != reflect.Slice { + panic("addSliceField() requires a pointer to a slice") + } + t := reflect.TypeOf(field.Addr().Interface()) + if t.Kind() != reflect.Ptr { + panic("addSliceField() requires a pointer to a slice") + } + if t.Elem().Kind() != reflect.Slice { + panic("addSliceField() requires a pointer to a slice") + } + defaultSlice := []string{defaultValue} + if separator != "" { + defaultSlice = strings.Split(defaultValue, separator) + } + switch t.Elem().Elem().Kind() { + case reflect.Bool: + defaultValues := make([]bool, 0, len(defaultSlice)) + for _, value := range defaultSlice { + val, err := strconv.ParseBool(value) + if err != nil { + panic("Invalid default value for bool flag") + } + defaultValues = append(defaultValues, val) + } + field.Set(reflect.ValueOf(defaultValues)) + case reflect.String: + field.Set(reflect.ValueOf(defaultSlice)) + case reflect.Int: + defaultValues := make([]int, 0, len(defaultSlice)) + for _, value := range defaultSlice { + val, err := strconv.Atoi(value) + if err != nil { + panic("Invalid default value for int flag") + } + defaultValues = append(defaultValues, val) + } + field.Set(reflect.ValueOf(defaultValues)) + case reflect.Int8: + defaultValues := make([]int8, 0, len(defaultSlice)) + for _, value := range defaultSlice { + val, err := strconv.Atoi(value) + if err != nil { + panic("Invalid default value for int8 flag") + } + defaultValues = append(defaultValues, int8(val)) + } + field.Set(reflect.ValueOf(defaultValues)) + case reflect.Int16: + defaultValues := make([]int16, 0, len(defaultSlice)) + for _, value := range defaultSlice { + val, err := strconv.Atoi(value) + if err != nil { + panic("Invalid default value for int16 flag") + } + defaultValues = append(defaultValues, int16(val)) + } + field.Set(reflect.ValueOf(defaultValues)) + case reflect.Int32: + defaultValues := make([]int32, 0, len(defaultSlice)) + for _, value := range defaultSlice { + val, err := strconv.ParseInt(value, 10, 32) + if err != nil { + panic("Invalid default value for int32 flag") + } + defaultValues = append(defaultValues, int32(val)) + } + field.Set(reflect.ValueOf(defaultValues)) + case reflect.Int64: + defaultValues := make([]int64, 0, len(defaultSlice)) + for _, value := range defaultSlice { + val, err := strconv.ParseInt(value, 10, 64) + if err != nil { + panic("Invalid default value for int64 flag") + } + defaultValues = append(defaultValues, val) + } + field.Set(reflect.ValueOf(defaultValues)) + case reflect.Uint: + defaultValues := make([]uint, 0, len(defaultSlice)) + for _, value := range defaultSlice { + val, err := strconv.Atoi(value) + if err != nil { + panic("Invalid default value for uint flag") + } + defaultValues = append(defaultValues, uint(val)) + } + field.Set(reflect.ValueOf(defaultValues)) + case reflect.Uint8: + defaultValues := make([]uint8, 0, len(defaultSlice)) + for _, value := range defaultSlice { + val, err := strconv.Atoi(value) + if err != nil { + panic("Invalid default value for uint8 flag") + } + defaultValues = append(defaultValues, uint8(val)) + } + field.Set(reflect.ValueOf(defaultValues)) + case reflect.Uint16: + defaultValues := make([]uint16, 0, len(defaultSlice)) + for _, value := range defaultSlice { + val, err := strconv.Atoi(value) + if err != nil { + panic("Invalid default value for uint16 flag") + } + defaultValues = append(defaultValues, uint16(val)) + } + field.Set(reflect.ValueOf(defaultValues)) + case reflect.Uint32: + defaultValues := make([]uint32, 0, len(defaultSlice)) + for _, value := range defaultSlice { + val, err := strconv.Atoi(value) + if err != nil { + panic("Invalid default value for uint32 flag") + } + defaultValues = append(defaultValues, uint32(val)) + } + field.Set(reflect.ValueOf(defaultValues)) + case reflect.Uint64: + defaultValues := make([]uint64, 0, len(defaultSlice)) + for _, value := range defaultSlice { + val, err := strconv.Atoi(value) + if err != nil { + panic("Invalid default value for uint64 flag") + } + defaultValues = append(defaultValues, uint64(val)) + } + field.Set(reflect.ValueOf(defaultValues)) + case reflect.Float32: + defaultValues := make([]float32, 0, len(defaultSlice)) + for _, value := range defaultSlice { + val, err := strconv.Atoi(value) + if err != nil { + panic("Invalid default value for float32 flag") + } + defaultValues = append(defaultValues, float32(val)) + } + field.Set(reflect.ValueOf(defaultValues)) + case reflect.Float64: + defaultValues := make([]float64, 0, len(defaultSlice)) + for _, value := range defaultSlice { + val, err := strconv.Atoi(value) + if err != nil { + panic("Invalid default value for float64 flag") + } + defaultValues = append(defaultValues, float64(val)) + } + field.Set(reflect.ValueOf(defaultValues)) + default: + panic(fmt.Sprintf("addSliceField() not supported slice type %s", t.Elem().Elem().Kind().String())) + } + return c +} + // BoolFlag - Adds a boolean flag to the command func (c *Command) BoolFlag(name, description string, variable *bool) *Command { c.flags.BoolVar(variable, name, *variable, description) @@ -373,6 +655,13 @@ func (c *Command) BoolFlag(name, description string, variable *bool) *Command { return c } +// BoolsFlag - Adds a booleans flag to the command +func (c *Command) BoolsFlag(name, description string, variable *[]bool) *Command { + c.flags.Var(newBoolsValue(*variable, variable), name, description) + c.flagCount++ + return c +} + // StringFlag - Adds a string flag to the command func (c *Command) StringFlag(name, description string, variable *string) *Command { c.flags.StringVar(variable, name, *variable, description) @@ -380,6 +669,13 @@ func (c *Command) StringFlag(name, description string, variable *string) *Comman return c } +// StringsFlag - Adds a strings flag to the command +func (c *Command) StringsFlag(name, description string, variable *[]string) *Command { + c.flags.Var(newStringsValue(*variable, variable), name, description) + c.flagCount++ + return c +} + // IntFlag - Adds an int flag to the command func (c *Command) IntFlag(name, description string, variable *int) *Command { c.flags.IntVar(variable, name, *variable, description) @@ -387,27 +683,139 @@ func (c *Command) IntFlag(name, description string, variable *int) *Command { return c } -// Int64Flag - Adds an int flag to the command +// IntsFlag - Adds an ints flag to the command +func (c *Command) IntsFlag(name, description string, variable *[]int) *Command { + c.flags.Var(newIntsValue(*variable, variable), name, description) + c.flagCount++ + return c +} + +// Int8Flag - Adds an int8 flag to the command +func (c *Command) Int8Flag(name, description string, variable *int8) *Command { + c.flags.Var(newInt8Value(*variable, variable), name, description) + c.flagCount++ + return c +} + +// Int8sFlag - Adds an int8 s flag to the command +func (c *Command) Int8sFlag(name, description string, variable *[]int8) *Command { + c.flags.Var(newInt8sValue(*variable, variable), name, description) + c.flagCount++ + return c +} + +// Int16Flag - Adds an int16 flag to the command +func (c *Command) Int16Flag(name, description string, variable *int16) *Command { + c.flags.Var(newInt16Value(*variable, variable), name, description) + c.flagCount++ + return c +} + +// Int16sFlag - Adds an int16s flag to the command +func (c *Command) Int16sFlag(name, description string, variable *[]int16) *Command { + c.flags.Var(newInt16sValue(*variable, variable), name, description) + c.flagCount++ + return c +} + +// Int32Flag - Adds an int32 flag to the command +func (c *Command) Int32Flag(name, description string, variable *int32) *Command { + c.flags.Var(newInt32Value(*variable, variable), name, description) + c.flagCount++ + return c +} + +// Int32sFlag - Adds an int32s flag to the command +func (c *Command) Int32sFlag(name, description string, variable *[]int32) *Command { + c.flags.Var(newInt32sValue(*variable, variable), name, description) + c.flagCount++ + return c +} + +// Int64Flag - Adds an int64 flag to the command func (c *Command) Int64Flag(name, description string, variable *int64) *Command { c.flags.Int64Var(variable, name, *variable, description) c.flagCount++ return c } -// UintFlag - Adds an int flag to the command +// Int64sFlag - Adds an int64s flag to the command +func (c *Command) Int64sFlag(name, description string, variable *[]int64) *Command { + c.flags.Var(newInt64sValue(*variable, variable), name, description) + c.flagCount++ + return c +} + +// UintFlag - Adds an uint flag to the command func (c *Command) UintFlag(name, description string, variable *uint) *Command { c.flags.UintVar(variable, name, *variable, description) c.flagCount++ return c } -// UInt64Flag - Adds an int flag to the command +// UintsFlag - Adds an uints flag to the command +func (c *Command) UintsFlag(name, description string, variable *[]uint) *Command { + c.flags.Var(newUintsValue(*variable, variable), name, description) + c.flagCount++ + return c +} + +// Uint8Flag - Adds an uint8 flag to the command +func (c *Command) Uint8Flag(name, description string, variable *uint8) *Command { + c.flags.Var(newUint8Value(*variable, variable), name, description) + c.flagCount++ + return c +} + +// Uint8sFlag - Adds an uint8 s flag to the command +func (c *Command) Uint8sFlag(name, description string, variable *[]uint8) *Command { + c.flags.Var(newUint8sValue(*variable, variable), name, description) + c.flagCount++ + return c +} + +// Uint16Flag - Adds an uint16 flag to the command +func (c *Command) Uint16Flag(name, description string, variable *uint16) *Command { + c.flags.Var(newUint16Value(*variable, variable), name, description) + c.flagCount++ + return c +} + +// Uint16sFlag - Adds an uint16s flag to the command +func (c *Command) Uint16sFlag(name, description string, variable *[]uint16) *Command { + c.flags.Var(newUint16sValue(*variable, variable), name, description) + c.flagCount++ + return c +} + +// Uint32Flag - Adds an uint32 flag to the command +func (c *Command) Uint32Flag(name, description string, variable *uint32) *Command { + c.flags.Var(newUint32Value(*variable, variable), name, description) + c.flagCount++ + return c +} + +// Uint32sFlag - Adds an uint32s flag to the command +func (c *Command) Uint32sFlag(name, description string, variable *[]uint32) *Command { + c.flags.Var(newUint32sValue(*variable, variable), name, description) + c.flagCount++ + return c +} + +// UInt64Flag - Adds an uint64 flag to the command func (c *Command) UInt64Flag(name, description string, variable *uint64) *Command { c.flags.Uint64Var(variable, name, *variable, description) c.flagCount++ return c } +// Uint64sFlag - Adds an uint64s flag to the command +func (c *Command) Uint64sFlag(name, description string, variable *[]uint64) *Command { + c.flags.Var(newUint64sValue(*variable, variable), name, description) + c.flagCount++ + return c +} + // Float64Flag - Adds a float64 flag to the command func (c *Command) Float64Flag(name, description string, variable *float64) *Command { c.flags.Float64Var(variable, name, *variable, description) @@ -415,6 +823,423 @@ func (c *Command) Float64Flag(name, description string, variable *float64) *Comm return c } +// Float32Flag - Adds a float32 flag to the command +func (c *Command) Float32Flag(name, description string, variable *float32) *Command { + c.flags.Var(newFloat32Value(*variable, variable), name, description) + c.flagCount++ + return c +} + +// Float32sFlag - Adds a float32s flag to the command +func (c *Command) Float32sFlag(name, description string, variable *[]float32) *Command { + c.flags.Var(newFloat32sValue(*variable, variable), name, description) + c.flagCount++ + return c +} + +// Float64sFlag - Adds a float64s flag to the command +func (c *Command) Float64sFlag(name, description string, variable *[]float64) *Command { + c.flags.Var(newFloat64sValue(*variable, variable), name, description) + c.flagCount++ + return c +} + +type boolsFlagVar []bool + +func (f *boolsFlagVar) String() string { return fmt.Sprint([]bool(*f)) } + +func (f *boolsFlagVar) Set(value string) error { + if value == "" { + *f = append(*f, false) + return nil + } + b, err := strconv.ParseBool(value) + if err != nil { + return err + } + *f = append(*f, b) + return nil +} + +func (f *boolsFlagVar) IsBoolFlag() bool { + return true +} + +func newBoolsValue(val []bool, p *[]bool) *boolsFlagVar { + *p = val + return (*boolsFlagVar)(p) +} + +type stringsFlagVar []string + +func (f *stringsFlagVar) String() string { return fmt.Sprint([]string(*f)) } + +func (f *stringsFlagVar) Set(value string) error { + *f = append(*f, value) + return nil +} + +func newStringsValue(val []string, p *[]string) *stringsFlagVar { + *p = val + return (*stringsFlagVar)(p) +} + +type intsFlagVar []int + +func (f *intsFlagVar) String() string { return fmt.Sprint([]int(*f)) } + +func (f *intsFlagVar) Set(value string) error { + i, err := strconv.Atoi(value) + if err != nil { + return err + } + *f = append(*f, i) + return nil +} + +func newIntsValue(val []int, p *[]int) *intsFlagVar { + *p = val + return (*intsFlagVar)(p) +} + +type int8Value int8 + +func newInt8Value(val int8, p *int8) *int8Value { + *p = val + return (*int8Value)(p) +} + +func (f *int8Value) Set(value string) error { + i, err := strconv.Atoi(value) + if err != nil { + return err + } + *f = int8Value(i) + return nil +} + +func (f *int8Value) String() string { return fmt.Sprint(int8(*f)) } + +type int8sFlagVar []int8 + +func (f *int8sFlagVar) String() string { return fmt.Sprint([]int8(*f)) } + +func (f *int8sFlagVar) Set(value string) error { + i, err := strconv.Atoi(value) + if err != nil { + return err + } + *f = append(*f, int8(i)) + return nil +} + +func newInt8sValue(val []int8, p *[]int8) *int8sFlagVar { + *p = val + return (*int8sFlagVar)(p) +} + +type int16Value int16 + +func newInt16Value(val int16, p *int16) *int16Value { + *p = val + return (*int16Value)(p) +} + +func (f *int16Value) Set(value string) error { + i, err := strconv.Atoi(value) + if err != nil { + return err + } + *f = int16Value(i) + return nil +} + +func (f *int16Value) String() string { return fmt.Sprint(int16(*f)) } + +type int16sFlagVar []int16 + +func (f *int16sFlagVar) String() string { return fmt.Sprint([]int16(*f)) } + +func (f *int16sFlagVar) Set(value string) error { + i, err := strconv.Atoi(value) + if err != nil { + return err + } + *f = append(*f, int16(i)) + return nil +} + +func newInt16sValue(val []int16, p *[]int16) *int16sFlagVar { + *p = val + return (*int16sFlagVar)(p) +} + +type int32Value int32 + +func newInt32Value(val int32, p *int32) *int32Value { + *p = val + return (*int32Value)(p) +} + +func (f *int32Value) Set(value string) error { + i, err := strconv.Atoi(value) + if err != nil { + return err + } + *f = int32Value(i) + return nil +} + +func (f *int32Value) String() string { return fmt.Sprint(int32(*f)) } + +type int32sFlagVar []int32 + +func (f *int32sFlagVar) String() string { return fmt.Sprint([]int32(*f)) } + +func (f *int32sFlagVar) Set(value string) error { + i, err := strconv.Atoi(value) + if err != nil { + return err + } + *f = append(*f, int32(i)) + return nil +} + +func newInt32sValue(val []int32, p *[]int32) *int32sFlagVar { + *p = val + return (*int32sFlagVar)(p) +} + +type int64sFlagVar []int64 + +func (f *int64sFlagVar) String() string { return fmt.Sprint([]int64(*f)) } + +func (f *int64sFlagVar) Set(value string) error { + i, err := strconv.ParseInt(value, 10, 64) + if err != nil { + return err + } + *f = append(*f, i) + return nil +} + +func newInt64sValue(val []int64, p *[]int64) *int64sFlagVar { + *p = val + return (*int64sFlagVar)(p) +} + +type uintsFlagVar []uint + +func (f *uintsFlagVar) String() string { + return fmt.Sprint([]uint(*f)) +} + +func (f *uintsFlagVar) Set(value string) error { + i, err := strconv.Atoi(value) + if err != nil { + return err + } + *f = append(*f, uint(i)) + return nil +} + +func newUintsValue(val []uint, p *[]uint) *uintsFlagVar { + *p = val + return (*uintsFlagVar)(p) +} + +type uint8FlagVar uint8 + +func newUint8Value(val uint8, p *uint8) *uint8FlagVar { + *p = val + return (*uint8FlagVar)(p) +} + +func (f *uint8FlagVar) String() string { + return fmt.Sprint(uint8(*f)) +} + +func (f *uint8FlagVar) Set(value string) error { + i, err := strconv.Atoi(value) + if err != nil { + return err + } + *f = uint8FlagVar(i) + return nil +} + +type uint8sFlagVar []uint8 + +func (f *uint8sFlagVar) String() string { + return fmt.Sprint([]uint8(*f)) +} + +func (f *uint8sFlagVar) Set(value string) error { + i, err := strconv.Atoi(value) + if err != nil { + return err + } + *f = append(*f, uint8(i)) + return nil +} + +func newUint8sValue(val []uint8, p *[]uint8) *uint8sFlagVar { + *p = val + return (*uint8sFlagVar)(p) +} + +type uint16FlagVar uint16 + +func newUint16Value(val uint16, p *uint16) *uint16FlagVar { + *p = val + return (*uint16FlagVar)(p) +} + +func (f *uint16FlagVar) String() string { + return fmt.Sprint(uint16(*f)) +} + +func (f *uint16FlagVar) Set(value string) error { + i, err := strconv.Atoi(value) + if err != nil { + return err + } + *f = uint16FlagVar(i) + return nil +} + +type uint16sFlagVar []uint16 + +func (f *uint16sFlagVar) String() string { + return fmt.Sprint([]uint16(*f)) +} + +func (f *uint16sFlagVar) Set(value string) error { + i, err := strconv.Atoi(value) + if err != nil { + return err + } + *f = append(*f, uint16(i)) + return nil +} + +func newUint16sValue(val []uint16, p *[]uint16) *uint16sFlagVar { + *p = val + return (*uint16sFlagVar)(p) +} + +type uint32FlagVar uint32 + +func newUint32Value(val uint32, p *uint32) *uint32FlagVar { + *p = val + return (*uint32FlagVar)(p) +} + +func (f *uint32FlagVar) String() string { + return fmt.Sprint(uint32(*f)) +} + +func (f *uint32FlagVar) Set(value string) error { + i, err := strconv.Atoi(value) + if err != nil { + return err + } + *f = uint32FlagVar(i) + return nil +} + +type uint32sFlagVar []uint32 + +func (f *uint32sFlagVar) String() string { + return fmt.Sprint([]uint32(*f)) +} + +func (f *uint32sFlagVar) Set(value string) error { + i, err := strconv.Atoi(value) + if err != nil { + return err + } + *f = append(*f, uint32(i)) + return nil +} + +func newUint32sValue(val []uint32, p *[]uint32) *uint32sFlagVar { + *p = val + return (*uint32sFlagVar)(p) +} + +type uint64sFlagVar []uint64 + +func (f *uint64sFlagVar) String() string { return fmt.Sprint([]uint64(*f)) } + +func (f *uint64sFlagVar) Set(value string) error { + i, err := strconv.ParseUint(value, 10, 64) + if err != nil { + return err + } + *f = append(*f, i) + return nil +} + +func newUint64sValue(val []uint64, p *[]uint64) *uint64sFlagVar { + *p = val + return (*uint64sFlagVar)(p) +} + +type float32sFlagVar []float32 + +func (f *float32sFlagVar) String() string { return fmt.Sprint([]float32(*f)) } + +func (f *float32sFlagVar) Set(value string) error { + i, err := strconv.ParseFloat(value, 64) + if err != nil { + return err + } + *f = append(*f, float32(i)) + return nil +} + +func newFloat32sValue(val []float32, p *[]float32) *float32sFlagVar { + *p = val + return (*float32sFlagVar)(p) +} + +type float32FlagVar float32 + +func (f *float32FlagVar) String() string { return fmt.Sprint(float32(*f)) } + +func (f *float32FlagVar) Set(value string) error { + i, err := strconv.ParseFloat(value, 64) + if err != nil { + return err + } + *f = float32FlagVar(i) + return nil +} + +func newFloat32Value(val float32, p *float32) *float32FlagVar { + *p = val + return (*float32FlagVar)(p) +} + +type float64sFlagVar []float64 + +func (f *float64sFlagVar) String() string { return fmt.Sprint([]float64(*f)) } + +func (f *float64sFlagVar) Set(value string) error { + i, err := strconv.ParseFloat(value, 64) + if err != nil { + return err + } + *f = append(*f, i) + return nil +} + +func newFloat64sValue(val []float64, p *[]float64) *float64sFlagVar { + *p = val + return (*float64sFlagVar)(p) +} + // LongDescription - Sets the long description for the command func (c *Command) LongDescription(longdescription string) *Command { c.longdescription = longdescription @@ -499,6 +1324,8 @@ func (c *Command) parsePositionalArgs(args []string) error { return err } field.SetFloat(value) + case reflect.Slice: + c.addSliceField(field, posArg, c.sliceSeparator[key]) default: return errors.New("Unsupported type for positional argument: " + fieldType.Name()) } diff --git a/examples/flags-slice/main.go b/examples/flags-slice/main.go new file mode 100644 index 0000000..79542ef --- /dev/null +++ b/examples/flags-slice/main.go @@ -0,0 +1,215 @@ +package main + +import ( + "fmt" + "github.com/leaanthony/clir" + "reflect" +) + +type Flags struct { + String string `name:"string" description:"The string" pos:"1"` + Strings []string `name:"strings" description:"The strings" pos:"2"` + StringsDefault []string `name:"strings_default" description:"The strings default" default:"one|two|three" sep:"|" pos:"3"` + + Int int `name:"int" description:"The int" pos:"4"` + Ints []int `name:"ints" description:"The ints" pos:"5"` + IntsDefault []int `name:"ints_default" description:"The ints default" default:"3|4|5" sep:"|" pos:"6"` + + Int8 int8 `name:"int8" description:"The int8" pos:"7"` + Int8s []int8 `name:"int8s" description:"The int8s" pos:"8"` + Int8sDefault []int8 `name:"int8s_default" description:"The int8s default" default:"3,4,5" sep:"," pos:"9"` + + Int16 int16 `name:"int16" description:"The int16" pos:"10"` + Int16s []int16 `name:"int16s" description:"The int16s" pos:"11"` + Int16sDefault []int16 `name:"int16s_default" description:"The int16s default" default:"3,4,5" sep:"," pos:"12"` + + Int32 int32 `name:"int32" description:"The int32" pos:"13"` + Int32s []int32 `name:"int32s" description:"The int32s" pos:"14"` + Int32sDefault []int32 `name:"int32s_default" description:"The int32 default" default:"3,4,5" sep:"," pos:"15"` + + Int64 int64 `name:"int64" description:"The int64" pos:"16"` + Int64s []int64 `name:"int64s" description:"The int64s" pos:"17"` + Int64sDefault []int64 `name:"int64s_default" description:"The int64s default" default:"3,4,5" sep:"," pos:"18"` + + Uint uint `name:"uint" description:"The uint" pos:"19"` + Uints []uint `name:"uints" description:"The uints" pos:"20"` + UintsDefault []uint `name:"uints_default" description:"The uints default" default:"3,4,5" sep:"," pos:"21"` + + Uint8 uint8 `name:"uint8" description:"The uint8" pos:"22"` + Uint8s []uint8 `name:"uint8s" description:"The uint8s" pos:"23"` + Uint8sDefault []uint8 `name:"uint8s_default" description:"The uint8s default" default:"3,4,5" sep:"," pos:"24"` + + Uint16 uint16 `name:"uint16" description:"The uint16" pos:"25"` + Uint16s []uint16 `name:"uint16s" description:"The uint16s" pos:"26"` + Uint16sDefault []uint16 `name:"uint16s_default" description:"The uint16 default" default:"3,4,5" sep:"," pos:"27"` + + Uint32 uint32 `name:"uint32" description:"The uint32" pos:"28"` + Uint32s []uint32 `name:"uint32s" description:"The uint32s" pos:"29"` + Uint32sDefault []uint32 `name:"uint32s_default" description:"The uint32s default" default:"3,4,5" sep:"," pos:"30"` + + Uint64 uint64 `name:"uint64" description:"The uint64" pos:"31"` + Uint64s []uint64 `name:"uint64s" description:"The uint64s" pos:"32"` + Uint64sDefault []uint64 `name:"uint64s_default" description:"The uint64s default" default:"3,4,5" sep:"," pos:"33"` + + Float32 float32 `name:"float32" description:"The float32" pos:"34"` + Float32s []float32 `name:"float32s" description:"The float32s" pos:"35"` + Float32sDefault []float32 `name:"float32s_default" description:"The float32s default" default:"3|4|5" sep:"|" pos:"36"` + + Float64 float64 `name:"float64" description:"The float64" pos:"37"` + Float64s []float64 `name:"float64s" description:"The float64s" pos:"38"` + Float64sDefault []float64 `name:"float64s_default" description:"The float64s default" default:"3|4|5" sep:"|" pos:"39"` + + Bool bool `name:"bool" description:"The bool" pos:"40"` + Bools []bool `name:"bools" description:"The bools" pos:"41"` + BoolsDefault []bool `name:"bools_default" description:"The bools default" default:"false|true|false|true" sep:"|" pos:"42"` +} + +func main() { + + // Create new cli + cli := clir.NewCli("flagstruct", "An example of subcommands with flag inherence", "v0.0.1") + + // Create an init subcommand with flag inheritance + init := cli.NewSubCommand("flag", "print default") + + flags := &Flags{ + String: "zkep", + Strings: []string{"one", "two", "three"}, + Int: 1, + Ints: []int{1, 2, 3}, + Int8: int8(1), + Int8s: []int8{1, 2, 3}, + Int16: int16(1), + Int16s: []int16{1, 2, 3}, + Int32: int32(1), + Int32s: []int32{1, 2, 3}, + Int64: int64(1), + Int64s: []int64{1, 2, 3}, + Uint: uint(1), + Uints: []uint{1, 2, 3}, + Uint8: uint8(1), + Uint8s: []uint8{1, 2, 3}, + Uint16: uint16(1), + Uint16s: []uint16{1, 2, 3}, + Uint32: uint32(1), + Uint32s: []uint32{1, 2, 3}, + Uint64: uint64(1), + Uint64s: []uint64{1, 2, 3}, + Float32: float32(3.14), + Float32s: []float32{1.1, 2.2, 3.3}, + Float64: float64(3.14), + Float64s: []float64{1.1, 2.2, 3.3}, + Bool: false, + Bools: []bool{true, false, false}, + } + init.AddFlags(flags) + + init.Action(func() error { + + println("string:", fmt.Sprintf("%#v", flags.String)) + println("strings:", fmt.Sprintf("%#v", flags.Strings)) + println("strings_default:", fmt.Sprintf("%#v", flags.StringsDefault)) + println("\n") + + println("int:", fmt.Sprintf("%#v", flags.Int)) + println("ints:", fmt.Sprintf("%#v", flags.Ints)) + println("ints_default:", fmt.Sprintf("%#v", flags.IntsDefault)) + println("\n") + + println("int8:", fmt.Sprintf("%#v", flags.Int8)) + println("int8s:", fmt.Sprintf("%#v", flags.Int8s)) + println("int8s_default:", fmt.Sprintf("%#v", flags.Int8sDefault)) + println("\n") + + println("int16:", fmt.Sprintf("%#v", flags.Int16)) + println("int16s:", fmt.Sprintf("%#v", flags.Int16s)) + println("int16s_default:", fmt.Sprintf("%#v", flags.Int16sDefault)) + println("\n") + + println("int32:", fmt.Sprintf("%#v", flags.Int32)) + println("int32s:", fmt.Sprintf("%#v", flags.Int32s)) + println("int32s_default:", fmt.Sprintf("%#v", flags.Int32sDefault)) + println("\n") + + println("int64:", fmt.Sprintf("%#v", flags.Int64)) + println("int64s:", fmt.Sprintf("%#v", flags.Int64s)) + println("int64s_default:", fmt.Sprintf("%#v", flags.Int64sDefault)) + println("\n") + + println("uint:", fmt.Sprintf("%#v", flags.Uint)) + println("uints:", fmt.Sprintf("%#v", flags.Uints)) + println("uints_default:", fmt.Sprintf("%#v", flags.UintsDefault)) + println("\n") + + println("uint8:", fmt.Sprintf("%#v", flags.Uint8)) + println("uint8s:", fmt.Sprintf("%#v", flags.Uint8s)) + println("uint8s_default:", fmt.Sprintf("%#v", flags.Uint8sDefault)) + println("\n") + + println("uint16:", fmt.Sprintf("%#v", flags.Uint16)) + println("uint16s:", fmt.Sprintf("%#v", flags.Uint16s)) + println("uint16s_default:", fmt.Sprintf("%#v", flags.Uint16sDefault)) + println("\n") + + println("uint32:", fmt.Sprintf("%#v", flags.Uint32)) + println("uint32s:", fmt.Sprintf("%#v", flags.Uint32s)) + println("uint32s_default:", fmt.Sprintf("%#v", flags.Uint32sDefault)) + println("\n") + + println("uint64:", fmt.Sprintf("%#v", flags.Uint)) + println("uint64s:", fmt.Sprintf("%#v", flags.Uint64s)) + println("uint64s_default:", fmt.Sprintf("%#v", flags.Uint64sDefault)) + println("\n") + + println("float32:", fmt.Sprintf("%#v", flags.Float32)) + println("float32s:", fmt.Sprintf("%#v", flags.Float32s)) + println("float32s_default:", fmt.Sprintf("%#v", flags.Float32sDefault)) + println("\n") + + println("float64:", fmt.Sprintf("%#v", flags.Float64)) + println("float64s:", fmt.Sprintf("%#v", flags.Float64s)) + println("float64s_default:", fmt.Sprintf("%#v", flags.Float64sDefault)) + println("\n") + + println("bool:", fmt.Sprintf("%#v", flags.Bool)) + println("bools:", fmt.Sprintf("%#v", flags.Bools)) + println("bools_default:", fmt.Sprintf("%#v", flags.BoolsDefault)) + println("\n") + + return nil + }) + + // Run! + if err := cli.Run("flag"); err != nil { + panic(err) + } + + cli.NewSubCommandFunction("positional", "test positional args", func(f *Flags) error { + + if f.String != "hello" { + panic(fmt.Sprintf("expected 'hello', got '%v'", f.String)) + } + + if !reflect.DeepEqual(f.Strings, []string{"zkep,hello,clir"}) { + panic(fmt.Sprintf("expected 'zkep,hello,clir', got '%v'", f.Strings)) + } + + if !reflect.DeepEqual(f.StringsDefault, []string{"zkep", "clir", "hello"}) { + panic(fmt.Sprintf("expected '[zkep,clir,hello]', got '%v'", f.StringsDefault)) + } + + println("string:", fmt.Sprintf("%#v", f.String)) + println("strings:", fmt.Sprintf("%#v", f.Strings)) + println("strings_default:", fmt.Sprintf("%#v", f.StringsDefault)) + println("\n") + + return nil + }) + + // Run! + // The pos 3 slice separator is '|' in struct tag + if err := cli.Run("positional", "hello", "zkep,hello,clir", "zkep|clir|hello"); err != nil { + panic(err) + } + +} diff --git a/website/docs/examples/flags-slice.md b/website/docs/examples/flags-slice.md new file mode 100644 index 0000000..135e8e0 --- /dev/null +++ b/website/docs/examples/flags-slice.md @@ -0,0 +1,6 @@ + +# Flags Slice + +```go +--8<-- "../examples/flags-slice/main.go" +``` \ No newline at end of file diff --git a/website/mkdocs.yml b/website/mkdocs.yml index 28a0192..f323250 100644 --- a/website/mkdocs.yml +++ b/website/mkdocs.yml @@ -69,6 +69,7 @@ nav: - examples/flags-compact.md - examples/flags-function.md - examples/flags-positional.md + - examples/flags-slice.md - examples/flagstruct.md - examples/hidden.md - examples/nested-subcommands.md