go/testdata/cli_clir.go.bak

1340 lines
36 KiB
Go
Raw Normal View History

package core
import (
"flag"
"fmt"
"io"
"os"
"reflect"
"strconv"
"strings"
)
// Command represents a command that may be run by the user
type clirCommand struct {
name string
commandPath string
shortdescription string
longdescription string
subCommands []*clirCommand
subCommandsMap map[string]*clirCommand
longestSubcommand int
actionCallback CliAction
app *Cli
flags *flag.FlagSet
flagCount int
helpFlag bool
hidden bool
positionalArgsMap map[string]reflect.Value
sliceSeparator map[string]string
}
// NewCommand creates a new Command.
// Description is optional — if omitted, i18n resolves it from the command path.
func newClirCommand(name string, description ...string) *clirCommand {
desc := ""
if len(description) > 0 {
desc = description[0]
}
result := &Command{
name: name,
shortdescription: desc,
subCommandsMap: make(map[string]*clirCommand),
hidden: false,
positionalArgsMap: make(map[string]reflect.Value),
sliceSeparator: make(map[string]string),
}
// Init flagset so flags can be added before Run
result.setParentCommandPath("")
return result
}
func (c *clirCommand) setParentCommandPath(parentCommandPath string) {
// Set up command path
if parentCommandPath != "" {
c.commandPath += parentCommandPath + " "
}
c.commandPath += c.name
// Set up flag set
c.flags = flag.NewFlagSet(c.commandPath, flag.ContinueOnError)
c.BoolFlag("help", "Get help on the '"+strings.ToLower(c.commandPath)+"' command.", &c.helpFlag)
// result.Flags.Usage = result.PrintHelp
}
func (c *clirCommand) inheritFlags(inheritFlags *flag.FlagSet) {
// inherit flags
inheritFlags.VisitAll(func(f *flag.Flag) {
if f.Name != "help" {
c.flags.Var(f.Value, f.Name, f.Usage)
}
})
}
func (c *clirCommand) setApp(app *Cli) {
c.app = app
}
// parseFlags parses the given flags
func (c *clirCommand) parseFlags(args []string) error {
// Parse flags
// Suppress flag parse errors to stderr
c.flags.SetOutput(io.Discard)
// Credit: https://stackoverflow.com/a/74146375
var positionalArgs []string
for {
if err := c.flags.Parse(args); err != nil {
return err
}
// Consume all the flags that were parsed as flags.
args = args[len(args)-c.flags.NArg():]
if len(args) == 0 {
break
}
// There's at least one flag remaining and it must be a positional arg since
// we consumed all args that were parsed as flags. Consume just the first
// one, and retry parsing, since subsequent args may be flags.
positionalArgs = append(positionalArgs, args[0])
args = args[1:]
}
// Parse just the positional args so that flagset.Args()/flagset.NArgs()
// return the expected value.
// Note: This should never return an error.
err := c.flags.Parse(positionalArgs)
if err != nil {
return err
}
if len(positionalArgs) > 0 {
return c.parsePositionalArgs(positionalArgs)
}
return nil
}
// Run - Runs the Command with the given arguments
func (c *clirCommand) run(args []string) error {
// If we have arguments, process them
if len(args) > 0 {
// Check for subcommand
subcommand := c.subCommandsMap[args[0]]
if subcommand != nil {
return subcommand.run(args[1:])
}
// Parse flags
err := c.parseFlags(args)
if err != nil {
if c.app.errorHandler != nil {
return c.app.errorHandler(c.commandPath, err)
}
return E("cli.Run", fmt.Sprintf("see '%s --help' for usage", c.commandPath), err)
}
// Help takes precedence
if c.helpFlag {
c.PrintHelp()
return nil
}
}
// Do we have an action?
if c.actionCallback != nil {
return c.actionCallback()
}
// If we haven't specified a subcommand
// check for an app level default command
if c.app.defaultCommand != nil {
// Prevent recursion!
if c.app.defaultCommand != c {
// only run default command if no args passed
if len(args) == 0 {
return c.app.defaultCommand.run(args)
}
}
}
// Nothing left we can do
c.PrintHelp()
return nil
}
// Action - Define an action from this command
func (c *clirCommand) Action(callback CliAction) *clirCommand {
c.actionCallback = callback
return c
}
// PrintHelp - Output the help text for this command
func (c *clirCommand) PrintHelp() {
c.app.PrintBanner()
commandTitle := c.commandPath
if c.shortdescription != "" {
commandTitle += " - " + c.shortdescription
}
// Ignore root command
if c.commandPath != c.name {
fmt.Println(commandTitle)
}
if c.longdescription != "" {
fmt.Println(c.longdescription + "\n")
}
if len(c.subCommands) > 0 {
fmt.Println("Available commands:")
fmt.Println("")
for _, subcommand := range c.subCommands {
if subcommand.isHidden() {
continue
}
spacer := strings.Repeat(" ", 3+c.longestSubcommand-len(subcommand.name))
isDefault := ""
if subcommand.isDefaultCommand() {
isDefault = "[default]"
}
fmt.Printf(" %s%s%s %s\n", subcommand.name, spacer, subcommand.shortdescription, isDefault)
}
fmt.Println("")
}
if c.flagCount > 0 {
fmt.Println("Flags:")
fmt.Println()
c.flags.SetOutput(os.Stdout)
c.flags.PrintDefaults()
c.flags.SetOutput(os.Stderr)
}
fmt.Println()
}
// isDefaultCommand returns true if called on the default command
func (c *clirCommand) isDefaultCommand() bool {
return c.app.defaultCommand == c
}
// isHidden returns true if the command is a hidden command
func (c *clirCommand) isHidden() bool {
return c.hidden
}
// Hidden hides the command from the Help system
func (c *clirCommand) Hidden() {
c.hidden = true
}
// NewChildCommand - Creates a new subcommand
func (c *clirCommand) NewChildCommand(name string, description ...string) *clirCommand {
result := NewCommand(name, description...)
c.AddCommand(result)
return result
}
// AddCommand - Adds a subcommand
func (c *clirCommand) AddCommand(command *clirCommand) {
command.setApp(c.app)
command.setParentCommandPath(c.commandPath)
name := command.name
c.subCommands = append(c.subCommands, command)
c.subCommandsMap[name] = command
if len(name) > c.longestSubcommand {
c.longestSubcommand = len(name)
}
}
// NewChildCommandInheritFlags - Creates a new subcommand, inherits flags from command
func (c *clirCommand) NewChildCommandInheritFlags(name string, description ...string) *clirCommand {
result := c.NewChildCommand(name, description...)
result.inheritFlags(c.flags)
return result
}
func (c *clirCommand) AddFlags(optionStruct any) *clirCommand {
// use reflection to determine if this is a pointer to a struct
// if not, panic
t := reflect.TypeOf(optionStruct)
// Check for a pointer to a struct
if t.Kind() != reflect.Ptr {
panic("AddFlags() requires a pointer to a struct")
}
if t.Elem().Kind() != reflect.Struct {
panic("AddFlags() requires a pointer to a struct")
}
// Iterate through the fields of the struct reading the struct tags
// and adding the flags
v := reflect.ValueOf(optionStruct).Elem()
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
fieldType := t.Elem().Field(i)
if !fieldType.IsExported() {
continue
}
// If this is an embedded struct, recurse
if fieldType.Type.Kind() == reflect.Struct {
c.AddFlags(field.Addr().Interface())
continue
}
tag := t.Elem().Field(i).Tag
name := tag.Get("name")
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)
}
switch field.Kind() {
case reflect.Bool:
var defaultValueBool bool
if defaultValue != "" {
var err error
defaultValueBool, err = strconv.ParseBool(defaultValue)
if err != nil {
panic("Invalid default value for bool flag")
}
}
field.SetBool(defaultValueBool)
c.BoolFlag(name, description, field.Addr().Interface().(*bool))
case reflect.String:
if defaultValue != "" {
// set value of field to default value
field.SetString(defaultValue)
}
c.StringFlag(name, description, field.Addr().Interface().(*string))
case reflect.Int:
if defaultValue != "" {
// set value of field to default value
value, err := strconv.Atoi(defaultValue)
if err != nil {
panic("Invalid default value for int flag")
}
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 int64 flag")
}
field.SetInt(int64(value))
}
c.Int64Flag(name, description, field.Addr().Interface().(*int64))
case reflect.Uint:
if defaultValue != "" {
// set value of field to default value
value, err := strconv.Atoi(defaultValue)
if err != nil {
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 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 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 != "" {
fmt.Fprintf(os.Stderr, "WARNING: unsupported type for flag: %s %s\n", fieldType.Type.Kind(), name)
}
}
}
return c
}
func (c *clirCommand) addSliceFlags(name, description string, field reflect.Value) *clirCommand {
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 *clirCommand) addSliceField(field reflect.Value, defaultValue, separator string) *clirCommand {
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.ParseFloat(value, 32)
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.ParseFloat(value, 64)
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 *clirCommand) BoolFlag(name, description string, variable *bool) *clirCommand {
c.flags.BoolVar(variable, name, *variable, description)
c.flagCount++
return c
}
// BoolsFlag - Adds a booleans flag to the command
func (c *clirCommand) BoolsFlag(name, description string, variable *[]bool) *clirCommand {
c.flags.Var(newBoolsValue(*variable, variable), name, description)
c.flagCount++
return c
}
// StringFlag - Adds a string flag to the command
func (c *clirCommand) StringFlag(name, description string, variable *string) *clirCommand {
c.flags.StringVar(variable, name, *variable, description)
c.flagCount++
return c
}
// StringsFlag - Adds a strings flag to the command
func (c *clirCommand) StringsFlag(name, description string, variable *[]string) *clirCommand {
c.flags.Var(newStringsValue(*variable, variable), name, description)
c.flagCount++
return c
}
// IntFlag - Adds an int flag to the command
func (c *clirCommand) IntFlag(name, description string, variable *int) *clirCommand {
c.flags.IntVar(variable, name, *variable, description)
c.flagCount++
return c
}
// IntsFlag - Adds an ints flag to the command
func (c *clirCommand) IntsFlag(name, description string, variable *[]int) *clirCommand {
c.flags.Var(newIntsValue(*variable, variable), name, description)
c.flagCount++
return c
}
// Int8Flag - Adds an int8 flag to the command
func (c *clirCommand) Int8Flag(name, description string, variable *int8) *clirCommand {
c.flags.Var(newInt8Value(*variable, variable), name, description)
c.flagCount++
return c
}
// Int8sFlag - Adds an int8 s flag to the command
func (c *clirCommand) Int8sFlag(name, description string, variable *[]int8) *clirCommand {
c.flags.Var(newInt8sValue(*variable, variable), name, description)
c.flagCount++
return c
}
// Int16Flag - Adds an int16 flag to the command
func (c *clirCommand) Int16Flag(name, description string, variable *int16) *clirCommand {
c.flags.Var(newInt16Value(*variable, variable), name, description)
c.flagCount++
return c
}
// Int16sFlag - Adds an int16s flag to the command
func (c *clirCommand) Int16sFlag(name, description string, variable *[]int16) *clirCommand {
c.flags.Var(newInt16sValue(*variable, variable), name, description)
c.flagCount++
return c
}
// Int32Flag - Adds an int32 flag to the command
func (c *clirCommand) Int32Flag(name, description string, variable *int32) *clirCommand {
c.flags.Var(newInt32Value(*variable, variable), name, description)
c.flagCount++
return c
}
// Int32sFlag - Adds an int32s flag to the command
func (c *clirCommand) Int32sFlag(name, description string, variable *[]int32) *clirCommand {
c.flags.Var(newInt32sValue(*variable, variable), name, description)
c.flagCount++
return c
}
// Int64Flag - Adds an int64 flag to the command
func (c *clirCommand) Int64Flag(name, description string, variable *int64) *clirCommand {
c.flags.Int64Var(variable, name, *variable, description)
c.flagCount++
return c
}
// Int64sFlag - Adds an int64s flag to the command
func (c *clirCommand) Int64sFlag(name, description string, variable *[]int64) *clirCommand {
c.flags.Var(newInt64sValue(*variable, variable), name, description)
c.flagCount++
return c
}
// UintFlag - Adds an uint flag to the command
func (c *clirCommand) UintFlag(name, description string, variable *uint) *clirCommand {
c.flags.UintVar(variable, name, *variable, description)
c.flagCount++
return c
}
// UintsFlag - Adds an uints flag to the command
func (c *clirCommand) UintsFlag(name, description string, variable *[]uint) *clirCommand {
c.flags.Var(newUintsValue(*variable, variable), name, description)
c.flagCount++
return c
}
// Uint8Flag - Adds an uint8 flag to the command
func (c *clirCommand) Uint8Flag(name, description string, variable *uint8) *clirCommand {
c.flags.Var(newUint8Value(*variable, variable), name, description)
c.flagCount++
return c
}
// Uint8sFlag - Adds an uint8 s flag to the command
func (c *clirCommand) Uint8sFlag(name, description string, variable *[]uint8) *clirCommand {
c.flags.Var(newUint8sValue(*variable, variable), name, description)
c.flagCount++
return c
}
// Uint16Flag - Adds an uint16 flag to the command
func (c *clirCommand) Uint16Flag(name, description string, variable *uint16) *clirCommand {
c.flags.Var(newUint16Value(*variable, variable), name, description)
c.flagCount++
return c
}
// Uint16sFlag - Adds an uint16s flag to the command
func (c *clirCommand) Uint16sFlag(name, description string, variable *[]uint16) *clirCommand {
c.flags.Var(newUint16sValue(*variable, variable), name, description)
c.flagCount++
return c
}
// Uint32Flag - Adds an uint32 flag to the command
func (c *clirCommand) Uint32Flag(name, description string, variable *uint32) *clirCommand {
c.flags.Var(newUint32Value(*variable, variable), name, description)
c.flagCount++
return c
}
// Uint32sFlag - Adds an uint32s flag to the command
func (c *clirCommand) Uint32sFlag(name, description string, variable *[]uint32) *clirCommand {
c.flags.Var(newUint32sValue(*variable, variable), name, description)
c.flagCount++
return c
}
// UInt64Flag - Adds an uint64 flag to the command
func (c *clirCommand) UInt64Flag(name, description string, variable *uint64) *clirCommand {
c.flags.Uint64Var(variable, name, *variable, description)
c.flagCount++
return c
}
// Uint64sFlag - Adds an uint64s flag to the command
func (c *clirCommand) Uint64sFlag(name, description string, variable *[]uint64) *clirCommand {
c.flags.Var(newUint64sValue(*variable, variable), name, description)
c.flagCount++
return c
}
// Float64Flag - Adds a float64 flag to the command
func (c *clirCommand) Float64Flag(name, description string, variable *float64) *clirCommand {
c.flags.Float64Var(variable, name, *variable, description)
c.flagCount++
return c
}
// Float32Flag - Adds a float32 flag to the command
func (c *clirCommand) Float32Flag(name, description string, variable *float32) *clirCommand {
c.flags.Var(newFloat32Value(*variable, variable), name, description)
c.flagCount++
return c
}
// Float32sFlag - Adds a float32s flag to the command
func (c *clirCommand) Float32sFlag(name, description string, variable *[]float32) *clirCommand {
c.flags.Var(newFloat32sValue(*variable, variable), name, description)
c.flagCount++
return c
}
// Float64sFlag - Adds a float64s flag to the command
func (c *clirCommand) Float64sFlag(name, description string, variable *[]float64) *clirCommand {
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 *clirCommand) LongDescription(longdescription string) *clirCommand {
c.longdescription = longdescription
return c
}
// OtherArgs - Returns the non-flag arguments passed to the subcommand. NOTE: This should only be called within the context of an action.
func (c *clirCommand) OtherArgs() []string {
return c.flags.Args()
}
func (c *clirCommand) NewChildCommandFunction(name string, description string, fn any) *clirCommand {
result := c.NewChildCommand(name, description)
// use reflection to determine if this is a function
// if not, panic
t := reflect.TypeOf(fn)
if t.Kind() != reflect.Func {
panic("NewChildCommandFunction '" + name + "' requires a function with the signature 'func(*struct) error'")
}
// Check the function has 1 input ant it's a struct pointer
fnValue := reflect.ValueOf(fn)
if t.NumIn() != 1 {
panic("NewChildCommandFunction '" + name + "' requires a function with the signature 'func(*struct) error'")
}
// Check the input is a struct pointer
if t.In(0).Kind() != reflect.Ptr {
panic("NewChildCommandFunction '" + name + "' requires a function with the signature 'func(*struct) error'")
}
if t.In(0).Elem().Kind() != reflect.Struct {
panic("NewChildCommandFunction '" + name + "' requires a function with the signature 'func(*struct) error'")
}
// Check only 1 output and it's an error
if t.NumOut() != 1 {
panic("NewChildCommandFunction '" + name + "' requires a function with the signature 'func(*struct) error'")
}
if t.Out(0) != reflect.TypeOf((*error)(nil)).Elem() {
panic("NewChildCommandFunction '" + name + "' requires a function with the signature 'func(*struct) error'")
}
flags := reflect.New(t.In(0).Elem())
result.Action(func() error {
result := fnValue.Call([]reflect.Value{flags})[0].Interface()
if result != nil {
return result.(error)
}
return nil
})
result.AddFlags(flags.Interface())
return result
}
func (c *clirCommand) parsePositionalArgs(args []string) error {
for index, posArg := range args {
// Check the map for a field for this arg
key := strconv.Itoa(index + 1)
field, ok := c.positionalArgsMap[key]
if !ok {
continue
}
fieldType := field.Type()
switch fieldType.Kind() {
case reflect.Bool:
// set value of field to true
field.SetBool(true)
case reflect.String:
field.SetString(posArg)
case reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int:
value, err := strconv.ParseInt(posArg, 10, 64)
if err != nil {
return err
}
field.SetInt(value)
case reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint:
value, err := strconv.ParseUint(posArg, 10, 64)
if err != nil {
return err
}
field.SetUint(value)
case reflect.Float64, reflect.Float32:
value, err := strconv.ParseFloat(posArg, 64)
if err != nil {
return err
}
field.SetFloat(value)
case reflect.Slice:
c.addSliceField(field, posArg, c.sliceSeparator[key])
default:
return E("cli.parsePositionalArgs", "unsupported type for positional argument: "+fieldType.Name(), nil)
}
}
return nil
}