Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2 bug: how to pass down global information into subcommand #1009

Closed
renzhengeek opened this issue Dec 22, 2019 · 5 comments
Closed

v2 bug: how to pass down global information into subcommand #1009

renzhengeek opened this issue Dec 22, 2019 · 5 comments
Labels
area/v2 relates to / is being considered for v2 help wanted please help if you can! kind/question someone asking a question status/confirmed confirmed to be valid, but work has yet to start

Comments

@renzhengeek
Copy link

Hi,

It's great package! I'm not sure it's a problem or I just haven't known how to achieve this task.

I have a 2-level cli tool:

  • there is a --config xxx global option, which accepts a config file, parses it and need to pass down some subcommand-specific items if needed;
  • there is monitor subcommand, which need to consume some items in config file;
  • there problem is, I made the monitor subcommand as a seperate package, now the entrypoint (subcommand action) is in control of cli, I cannot find a opportunity to pass down some information in top-level app into the subcommand.

Thanks for your help in advance:-)

@renzhengeek renzhengeek added status/triage maintainers still need to look into this kind/bug describes or fixes a bug area/v2 relates to / is being considered for v2 labels Dec 22, 2019
@coilysiren coilysiren added kind/question someone asking a question and removed kind/bug describes or fixes a bug labels Dec 24, 2019
@coilysiren
Copy link
Member

In case it's unclear, @renzhengeek I don't know the answer to your question offhand 🙂

@coilysiren coilysiren added status/confirmed confirmed to be valid, but work has yet to start and removed status/triage maintainers still need to look into this labels Dec 27, 2019
@coilysiren coilysiren added the help wanted please help if you can! label Dec 27, 2019
@rliebz
Copy link
Member

rliebz commented Dec 27, 2019

I think the intended way of doing this is leveraging the Metadata field on the top level App, which is always accessible from the *cli.Context in any package:

cli/app.go

Lines 80 to 81 in db3269c

// Other custom info
Metadata map[string]interface{}

Here's an example of that in use:

package main

import (
	"fmt"
	"log"
	"os"

	"github.com/urfave/cli/v2"
)

func main() {
	app := cli.NewApp()
	app.Before = func(c *cli.Context) error {
		// Parse a config file here to get data
		// ...
		c.App.Metadata["some key"] = "some value"
		return nil
	}

	app.Commands = []*cli.Command{
		{
			Name: "cmd",
			Action: func(c *cli.Context) error {
				val := c.App.Metadata["some key"].(string)
				fmt.Println(val)
				return nil
			},
		},
	}

	if err := app.Run(os.Args); err != nil {
		log.Fatal(err)
	}
}

While in this case I am doing everything in the main function, you should be able to split this pattern across packages without any issue.

The one consideration is that the type of Metadata is map[string]interface{}, so you have to manage the type of the data yourself. The upside, though, is that any data you need can be placed in there, such as a custom config struct for your application.

@xiegeo
Copy link

xiegeo commented Jan 3, 2020

I would like to offer an alternative solution.

Although it looks like Action: func(c *cli.Context) error limits you to only use context in your action handlers. This is not true since you can write a function that generates other functions:

func Action(data dType) func(c *cli.Context) error{
    return  func(c *cli.Context) error{
        //use data and c freely here
    }
}

You can use this with Action: monitor.Action(data)

This a common pattern for any kind of handler function you may write.

@renzhengeek
Copy link
Author

func Action(data dType) func(c *cli.Context) error{

Thanks for the idea. I will give a try later. But, it seems not working: we can only register subcommand with the function signature:

			Action: func(c *cli.Context) error {

The problem is, when the wrapper should/can be called instead of calling subcommand action fn directly?

You can use this with Action: monitor.Action(data)

@renzhengeek
Copy link
Author

@rliebz Thanks very much for your example. I think the example is good enough to be putted in the doc.

Thanks all for your kind help. Closed:-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/v2 relates to / is being considered for v2 help wanted please help if you can! kind/question someone asking a question status/confirmed confirmed to be valid, but work has yet to start
Projects
None yet
Development

No branches or pull requests

4 participants