bflags

package
v1.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 4, 2023 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

	Package bflags implements binding for command flags or command line
	arguments to an object.
	Binding happens through tags annotations on struct types using the `cmd` tag

	Syntax

	Tag are specified using 'cmd' followed by either 'flag' or 'arg':
		flag, name, usage, shorthand, persistent, required, hidden
		arg,  name, usage, order

	sample:
		flag  `cmd:"flag,id,content id,i,true,true,false"`
		arg   `cmd:"arg,id,content id,0"`

	Assuming a string value, the above flag tag is read as (using cobra):
		cmd.PersistentFlags().StringP("id", "i", "", "content id")
		cmd.MarkPersistentFlagRequired("id")
	In case the flag is not persistent and not required, it reads as:
		cmd.Flags().StringP("id", "i", "", "content id")
	Note that flag names are case-sensitive

	The default value is the value of the tagged field. In the example below the
	field Ip of myInput is initialized with net.IPv4(127, 0, 0, 1) before being
 	bound. This makes the flag --ip having a default value of 127.0.0.1.

	For `arg` tags, the order (starting at 0) must be specified for all or none
	of the fields in the struct.

	The library also supports specifying a 'meta' tag, followed by a comma separated
	list of values that are attached as a slice of strings to the 'Annotations' field
	of the resulting FlagBond:
		`meta:"value1,value2"`

	Even though not a frequent usage, the bound flags can be retrieved after binding:
		var c *cobra.Command
		_ = Bind(c, &MyStruct{})
		flags, _ := GetCmdFlagSet(c)
		args, _ := GetCmdArgSet(c)

	Example

		type SimpleTaggedStruct struct {
			Stringval string `cmd:"flag"`
			Ids       id.ID  `cmd:"flag,ids,content ids,i,true,true"`
			Id        id.ID  `cmd:"arg,id,content id,0"`
			QId       id.ID
			Ignore    string
		}

	Complete Usage Sample using go generics.
	This example takes advantage of go generics to bind the input to the command
	flags and sets the RunE function of the command.

		type myInput struct {
			Ip   net.IP `cmd:"flag,ip,node ip,q"`
			Path string `cmd:"arg"`
		}

		func Execute() error {
			cmd, err := bflags.BindRunE(
				&myInput{
					Ip:   net.IPv4(127, 0, 0, 1),
					Path: "/tmp",
				},
				&cobra.Command{
					Use:   "sample /path",
					Short: "run sample",
				},
				func(in *myInput) error {
					bb, err := json.Marshal(in)
					if err != nil {
						return err
					}
					fmt.Printf("sample - input %s\n", string(bb))
					return nil
				},
				nil)
			if err != nil {
				return err
			}
			err = cmd.Execute()
			return err
		}

		func main() {
			if err := Execute(); err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
		}

	Complete Usage Sample.
	Same example as above but not using go generics.

		type myInput struct {
			Ip   net.IP `cmd:"flag,ip,node ip,q"`
			Path string `cmd:"arg"`
		}

		func InitFlagsSample() (*cobra.Command, error) {

			var cmdFlagsSample = &cobra.Command{
				Use:   "sample /path",
				Short: "run sample",
				RunE:  runSample,
			}
			// &myInput instance 'my' here represents the default values of all
			// flags bound to it
			my := &myInput{
				Ip:   net.IPv4(127, 0, 0, 1),
				Path: "/tmp",
			}

			err := bflags.Bind(cmdFlagsSample, my)
			// this is equivalent to
			//   cmdFlagsSample.Flags().IPVarP(&my.Ip, "ip", "q", my.Ip, "node ip")
			// additionally if the flag was required
			//   _ = cmdFlagsSample.MarkFlagRequired("ip")
			// or hidden:
			//   cmdFlagsSample.Flag("ip").Hidden = true

			if err != nil {
				return nil, err
			}
			return cmdFlagsSample, nil
		}

		func runSample(cmd *cobra.Command, args []string) error {
			// this is required to bind args parameters to the 'arg' fields of the input
			m, err := bflags.SetArgs(cmd, args)
			if err != nil {
				return err
			}
			my, ok := m.(*myInput)
			if !ok {
				return errors.E("runSample", "wrong input", m)
			}
			bb, err := json.Marshal(my)
			if err != nil {
				return err
			}
			fmt.Printf("sample - input %s\n", string(string(bb)))
			return nil
		}

		func Execute() error {
			cmd, err := InitFlagsSample()
			if err != nil {
				return err
			}
			err = cmd.Execute()
			return err
		}

		func main() {
			if err := Execute(); err != nil {
				fmt.Println(err)
				os.Exit(1)
			}
		}

	Binding to specific 'custom' types

		Binding to specific types is supported through the Flagger interface.
		With an instance fl of Flagger, call bflags.BindCustom(cmd, fl, v)
		See `TestCustomFlag` for a sample implementation.

	Struct implementing flag.Value

		**Pointer** values to those structs can be used as flags.

		Example:

        // workersConfig implements pflag.Value
        type workersConfig struct {
        	QueueSize int
        	Workers   int
        }

        func (u *workersConfig) String() string {
        	bb, err := json.Marshal(u)
        	if err != nil {
        		return err.Error()
        	}
        	return string(bb)
        }

        func (u *workersConfig) Set(s string) error {
        	return json.Unmarshal([]byte(s), u)
        }

        func (u *workersConfig) Type() string {
        	return "workers"
        }

        type TestFlagValueStruct struct {
			// **pointer** !
        	Workers *workersConfig `cmd:"flag"`
        }

        func TestEncodeFlagValue(t *testing.T) {
        	c := &cobra.Command{
        		Use: "dontUse",
        	}
        	sts := &TestFlagValueStruct{
        		Workers: &workersConfig{},
        	}
        	err := Bind(c, sts)
        	require.NoError(t, err)

        	pf := assertFlag(t, c, "Workers")
        	require.Equal(t, &workersConfig{}, sts.Workers)
        	err = pf.Value.Set(`{"QueueSize":50,"Workers":5}`)
        	require.NoError(t, err)
        	wc := &workersConfig{
        		QueueSize: 50,
        		Workers:   5,
        	}

        	require.Equal(t, wc, sts.Workers)
        }

	NOTES
		* inner structs - even anonymous - can be used for bindings BUT the
		  inner struct needs to be initialized otherwise an error is raised
		  since no binding would occur for its fields.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddTemplateFunc added in v1.0.3

func AddTemplateFunc(name string, tmplFunc interface{})

AddTemplateFunc adds a template function that's available to Usage and Help template generation. Also adds the function to the cobra template functions.

func AddToCmdCtx

func AddToCmdCtx(cmd *cobra.Command, name string, v interface{}) bool

func Bind

func Bind(c *cobra.Command, v interface{}) error

Bind binds the flags retrieved in tags of the given struct v as flags or args of the given command. c the command

v expected to be a struct.

Tag are specified using 'cmd' followed by either 'flag' or 'arg':

`cmd:"flag,id,content id, i,true,true,true"`
`cmd:"arg,id,content id,0"`

are read as:

flag: name, usage, shorthand, persistent, required, hidden
arg: name, usage, order

Attributes with default value on the right side of the expression can be omitted:

`cmd:"flag,id,content id, i"`

A 'meta' tag can be added to convey annotations with the bound tag:

`cmd:"flag,config,file name,c" meta:"file,non-empty"`

func BindCustom

func BindCustom(c *cobra.Command, f Flagger, v interface{}) error

BindCustom is like Bind and allows a custom Flagger

func BindRunE added in v1.0.3

func BindRunE[T any](input *T, cmd *cobra.Command, runE func(*T) error, f Flagger) (*cobra.Command, error)

BindRunE binds the input parameter to the given command and sets the runE parameter function as the function invoked by the RunE function of the cobra command. _Example_

type testOpts struct {
	Password string   `cmd:"flag,password,password for the user's key,x"`
	NoCert   bool     `cmd:"flag,no-cert,don't add certificate to the ssh-agent"`
	Domains  []string `cmd:"arg,domains,name of the ssh domains,0"`
	done     bool
}

cmd, err := BindRunE(
	&testOpts{},
	&cobra.Command{
		Use:     "test <domains>",
		Short:   "explanation short",
		Args:    cobra.MinimumNArgs(1),
		Example: "test a b",
	},
	func(opts *testOpts) error {
		return opts.run()
	},
	nil)
if err != nil {
	panic(err)
}
... use cmd

func ConfigureCommandHelp added in v1.0.3

func ConfigureCommandHelp(c *cobra.Command)

func ConfigureHelpFuncs added in v1.0.3

func ConfigureHelpFuncs()

func GetCmdCtx

func GetCmdCtx(cmd *cobra.Command) (interface{}, bool)

func GetCmdInput

func GetCmdInput(cmd *cobra.Command) (interface{}, bool)

func GetFlagArgSet added in v1.0.3

func GetFlagArgSet(c *cobra.Command) map[string]string

GetFlagArgSet returns a map[string]string of flags and args that were set for the given command. This function has to be called after SetArgs.

func GetFromCmdCtx

func GetFromCmdCtx(cmd *cobra.Command, name string) (interface{}, bool)

func SetArgs

func SetArgs(c *cobra.Command, args []string) (interface{}, error)

SetArgs sets the args to the 'arg' fields of the value previously bound as the input of the command. The input must have previously been bound to the command like so:

input := &MyStruct{}
err := bflags.BindCustom(cmd, elvflags.Flags, input)

The input is returned if no error occurred.

func SetCmdCtx

func SetCmdCtx(cmd *cobra.Command, v interface{})

func SetupCmdArgs

func SetupCmdArgs(cmd *cobra.Command, args []string, typ reflect.Type) (interface{}, error)

SetupCmdArgs configures and returns the input struct bound to the provided command with the given arguments. * If the typ parameter is not nil the type of the input is verified * if the input has a function 'Validate() error', the function is called The input must have previously been bound to the command like so:

input := &MyStruct{}
err := bflags.BindCustom(cmd, elvflags.Flags, input)

The input is returned if no error occurred.

Types

type ArgSet

type ArgSet struct {
	Flags []*FlagBond
}

func GetCmdArgSet

func GetCmdArgSet(cmd *cobra.Command) (*ArgSet, error)

func (*ArgSet) ArgUsages

func (f *ArgSet) ArgUsages() string

ArgUsages returns a string containing the usage information for all flags in the ArgSet

func (*ArgSet) Set

func (f *ArgSet) Set(string) error

Set is not intended to be called (but required by Value interface)

func (*ArgSet) String

func (f *ArgSet) String() string

func (*ArgSet) Type

func (f *ArgSet) Type() string

type Binder added in v1.0.3

type Binder struct {
	Error   error
	Command *cobra.Command
}

Binder is a utility for fluently building trees of commands with bindings. Example:

	 root := NewBinderC(
			&cobra.Command{
				Use:   "test",
				Short: "root command",
			}).
			AddCommand(
				NewBinder(
					&testOpts{},
					&cobra.Command{
						Use:     "a <domains>",
						Example: "test a x",
					},
					func(opts *testOpts) error {
						return opts.run()
					},
					nil),
				NewBinder(
					&testOpts{},
					&cobra.Command{
						Use:     "b <domains>",
						Example: "test b y",
					},
					func(opts *testOpts) error {
						return opts.run()
					},
					nil))
	if root.Error != nil {
		panic(root.Error)
	}
 ... use root.Command

func NewBinder added in v1.0.3

func NewBinder[T any](in *T, c *cobra.Command, runE func(*T) error, f Flagger) *Binder

NewBinder returns a Binder initialized by running BindRunE with the given parameters

func NewBinderC added in v1.0.3

func NewBinderC(c *cobra.Command) *Binder

NewBinderC constructs a new Binder with just a Command. This is useful for commands that are only parents of other commands, like the root command.

func (*Binder) AddCommand added in v1.0.3

func (b *Binder) AddCommand(bound ...*Binder) *Binder

AddCommand adds the commands of the given Binder instances to the command of this Binder or append their error to the Error of this Binder if they have errors.

type CmdFlags

type CmdFlags map[cmdFlag]*FlagBond

func GetCmdFlagSet

func GetCmdFlagSet(cmd *cobra.Command) (CmdFlags, error)

func (CmdFlags) ConfigureCmd

func (s CmdFlags) ConfigureCmd(cmd *cobra.Command, custom Flagger) error

func (CmdFlags) Flagset

func (s CmdFlags) Flagset(cmd *cobra.Command, name string) (*flag.FlagSet, error)

func (CmdFlags) Get

func (s CmdFlags) Get(name string) (*FlagBond, bool)

func (CmdFlags) GetBool

func (s CmdFlags) GetBool(cmd *cobra.Command, name cmdFlag) (bool, error)

func (CmdFlags) GetDuration

func (s CmdFlags) GetDuration(cmd *cobra.Command, name cmdFlag) (time.Duration, error)

func (CmdFlags) GetFloat32

func (s CmdFlags) GetFloat32(cmd *cobra.Command, name cmdFlag) (float32, error)

func (CmdFlags) GetFloat64

func (s CmdFlags) GetFloat64(cmd *cobra.Command, name cmdFlag) (float64, error)

func (CmdFlags) GetIP

func (s CmdFlags) GetIP(cmd *cobra.Command, name cmdFlag) (net.IP, error)

func (CmdFlags) GetInt

func (s CmdFlags) GetInt(cmd *cobra.Command, name cmdFlag) (int, error)

func (CmdFlags) GetInt64

func (s CmdFlags) GetInt64(cmd *cobra.Command, name cmdFlag) (int64, error)

func (CmdFlags) GetString

func (s CmdFlags) GetString(cmd *cobra.Command, name cmdFlag) (string, error)

func (CmdFlags) GetUint

func (s CmdFlags) GetUint(cmd *cobra.Command, name cmdFlag) (uint, error)

func (CmdFlags) GetUint64

func (s CmdFlags) GetUint64(cmd *cobra.Command, name cmdFlag) (uint64, error)

func (CmdFlags) Set

func (s CmdFlags) Set(string) error

Set is not intended to be called (but required by Value interface)

func (CmdFlags) String

func (s CmdFlags) String() string

func (CmdFlags) Type

func (s CmdFlags) Type() string

func (CmdFlags) Validate

func (s CmdFlags) Validate() error

type FlagBond

type FlagBond struct {
	Name        cmdFlag     // name of the flag
	Shorthand   string      // one letter shorthand or the empty string for none
	Value       interface{} // the default value (use zero value for no default)
	Usage       string      // usage string : must not be empty
	Required    bool        // true if the flag is required
	Persistent  bool        // true: the flag is available to the command as well as every command under the command
	Hidden      bool        // true to set the flag as hidden
	ArgOrder    int         // for flags used to bind args
	CsvSlice    bool        // true for flags with comma separated string representation
	Annotations []string    // annotations found as 'meta' tag
	// contains filtered or unexported fields
}

func (*FlagBond) CmdString

func (f *FlagBond) CmdString() []string

func (*FlagBond) Copy

func (f *FlagBond) Copy() *FlagBond

func (*FlagBond) HasAnnotation added in v1.0.3

func (f *FlagBond) HasAnnotation(s string) bool

func (*FlagBond) MarshalJSON

func (f *FlagBond) MarshalJSON() ([]byte, error)

func (*FlagBond) SetPersistent

func (f *FlagBond) SetPersistent(v bool) *FlagBond

func (*FlagBond) SetRequired

func (f *FlagBond) SetRequired(v bool) *FlagBond

type Flagged

type Flagged struct {
	Ptr      interface{} // a pointer to the original value (or the original value itself)
	Flag     flag.Value  // a flag.Value representing the value
	CsvSlice bool        // true if the value is a slice whose string representation is comma separated
}

type Flagger

type Flagger interface {

	// Bind returns true if this Flagger handles the given type
	Bind(t reflect.Type) bool

	// Flag returns a Flagged or nil if not handled.
	Flag(val interface{}) *Flagged
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL