cli icon indicating copy to clipboard operation
cli copied to clipboard

Flag Action

Open kke opened this issue 4 years ago • 12 comments

I think I can already do this by creating a custom struct that implements Flag, but maybe it's something we could have in the package 🤔

Consider this:

var debugFlag = &cli.BoolFlag{
  Name:    "debug",
  Usage:   "Enable debug output",
  Aliases: []string{"d"},
  EnvVars: []string{"DEBUG"},
  Action: func(v bool) error {
    if v {
      logger.SetLevel(logger.DebugLevel)
    }
  },
}

With this defined, I could just bring that into my command's Flags:

	cmd := &cli.Command{
		Name:  "do",
		Usage: "do things",
		Flags: []cli.Flag{
                        flags.debugFlag,
			&cli.StringFlag{
				Name:      "config",
				Usage:     "Path to config ",

..without having to handle the flag in that command's Before or Action.

kke avatar Jan 15 '21 14:01 kke

Did you mean add flags.debugFlag into this package? I think it is a good idea, but if the user use the third party log library, flags.debugFlag doesn't know which logger it should choose at all. Moreover, it is unnecessary to add this flag because it has a lot of limitations.

Re-Ch-Love avatar Jan 29 '21 16:01 Re-Ch-Love

Did you mean add flags.debugFlag into this package? I think it is a good idea, but if the user use the third party log library, flags.debugFlag doesn't know which logger it should choose at all. Moreover, it is unnecessary to add this flag because it has a lot of limitations.

My intention was that there would be Action in all flags, so that you could handle the flags before going into the main function of the command.

Potential uses would be to for example configure a logger, load / validate a configuration, set operating modes such as --force, somehow normalizes the value or maybe to show a version:

	cmd := &cli.Command{
		Flags: []cli.Flag{
			&cli.BoolFlag{
				Name:      "version",
				Usage:     "Display version",
                                 Action: func(_ bool) error {
                                   fmt.Println(app.Version)
                                   os.Exit(0)
                                 }
	cmd := &cli.Command{
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:      "config",
				Usage:     "Set config location",
                                 Action: func(f string, ctx *cli.Context) error {
                                   content, err := ioutil.ReadFile(f)
                                   if err != nil { 
                                     return err
                                   }
                                   ctx.SetString("config-content", content)
                                   return nil
                                 }

and so on

So you could kind of handle the flag right there in the flag definition.

kke avatar Feb 01 '21 07:02 kke

It's a good idea, flags has it's own Action function, the app looks like OOP.

vipally avatar Feb 07 '21 15:02 vipally

Did you mean add flags.debugFlag into this package? I think it is a good idea, but if the user use the third party log library, flags.debugFlag doesn't know which logger it should choose at all. Moreover, it is unnecessary to add this flag because it has a lot of limitations.

My intention was that there would be Action in all flags, so that you could handle the flags before going into the main function of the command.

Potential uses would be to for example configure a logger, load / validate a configuration, set operating modes such as --force, somehow normalizes the value or maybe to show a version:

	cmd := &cli.Command{
		Flags: []cli.Flag{
			&cli.BoolFlag{
				Name:      "version",
				Usage:     "Display version",
                                 Action: func(_ bool) error {
                                   fmt.Println(app.Version)
                                   os.Exit(0)
                                 }
	cmd := &cli.Command{
		Flags: []cli.Flag{
			&cli.StringFlag{
				Name:      "config",
				Usage:     "Set config location",
                                 Action: func(f string, ctx *cli.Context) error {
                                   content, err := ioutil.ReadFile(f)
                                   if err != nil { 
                                     return err
                                   }
                                   ctx.SetString("config-content", content)
                                   return nil
                                 }

and so on

So you could kind of handle the flag right there in the flag definition.

good idea, I think i can send a pull request when I am free. together?

Re-Ch-Love avatar Feb 07 '21 16:02 Re-Ch-Love

I try to add this feature in the package, but I met some problems. I add RunAction(*Context) error into the interface Flag, and invoke the function in app.RunContext, after normalize the flags, before show the help of the app. It can works, but it will invoke the action function of each flag, I don't know how to judge whether the flag is used or not. Then I tried to do it, but failed.

for _, f := range a.Flags {
	for _, n := range f.Names() {
		fl := context.flagSet.Lookup(n)
		if fl.Value.String() != fl.DefValue {
			a.handleExitCoder(context, f.RunAction(context))
		}
	}
}

Re-Ch-Love avatar Feb 12 '21 05:02 Re-Ch-Love

This issue or PR has been automatically marked as stale because it has not had recent activity. Please add a comment bumping this if you're still interested in it's resolution! Thanks for your help, please let us know if you need anything else.

stale[bot] avatar Jun 02 '21 15:06 stale[bot]

Still sounds like a good idea.

kke avatar Jun 03 '21 07:06 kke

This issue or PR has been bumped and is no longer marked as stale! Feel free to bump it again in the future, if it's still relevant.

stale[bot] avatar Jun 03 '21 07:06 stale[bot]

This issue or PR has been automatically marked as stale because it has not had recent activity. Please add a comment bumping this if you're still interested in it's resolution! Thanks for your help, please let us know if you need anything else.

stale[bot] avatar Sep 04 '21 23:09 stale[bot]

Still sounds like a good idea, stalebot.

kke avatar Sep 06 '21 12:09 kke

This issue or PR has been bumped and is no longer marked as stale! Feel free to bump it again in the future, if it's still relevant.

stale[bot] avatar Sep 06 '21 12:09 stale[bot]

good idea.

xwjdsh avatar Feb 14 '22 13:02 xwjdsh