cli icon indicating copy to clipboard operation
cli copied to clipboard

Is there anyway to support dynamic flag names?

Open hsrzq opened this issue 3 years ago • 1 comments

Suppose I have a go web program named goweb, and the subcommand web will starts a web daemon. Most importantly, it can have multiple instances at the same time, of course, they have different port numbers.

This is my /etc/goweb/config.conf content:

[web]
path = "/var/lib/goweb/default"
port = 8000

[web.user1]
path = "/var/lib/goweb/user1"
port = 8001

[web.user2]
path = "/var/lib/goweb/user2"
port = 8002

What I expect is:

  1. When I use goweb web --config /etc/goweb/config.conf, the web service is based on path /var/lib/goweb/default and port 8000.
  2. When I use goweb --user user1 web --config /etc/goweb/config.conf, the web service is based on path /var/lib/goweb/user1 and port 8001.
  3. Of course, when I use goweb --user user2 web --config /etc/goweb/config.conf, the web service is based on path /var/lib/goweb/user2 and port 8002.
  4. And THE MOST WONDERFUL THING is, when I use goweb --user user1 web --config /etc/goweb/config.conf --port 10000, the web service is based on path /var/lib/goweb/user1 and port 10000!

This is my []cli.Flag section:

portFlag := &cli.IntFlag{Name: "port"}
pathFlag := &cli.StringFlag{Name: "path"} 
flags := []cli.Flag{
    altsrc.NewStringFlag(pathFlag),
    altsrc.NewIntFlag(portFlag),
    &cli.StringFlag{Name: "config"},
}

And I changed the Aliases of portFlag in Before function:

func(c *cli.Context) error {
    var pathAlias string
    var portAlias string
    if len(user) == 0 {
        pathAlias = "web.port"
        portAlias = "web.port"
    } else {
        pathAlias = fmt.Sprint("web.", user, ".path")
        portAlias = fmt.Sprint("web.", user, ".port")
    }
    pathFlag.Aliases = append(pathFlag.Aliases, pathAlias)
    portFlag.Aliases = append(portFlag.Aliases, portAlias)
    altsrc.InitInputSourceWithContext(flags, altsrc.NewTomlSourceFromFlagFunc("config"))
    return nil
}

UNFORTUNATELY, IT DOESN'T WORK. SO, HOW CAN I DO FOR IT?

hsrzq avatar Jun 16 '21 03:06 hsrzq

I don't think there's native support for what you're trying to do.

I've accomplished something similar by parsing CLI flags twice—once to get the non-dynamic flags (in your case, --user) and then afterwards, create a new cli.App with configuration based on the options parsed the first go around. Unfortunately, that was rather complex, and I'm not sure that the way I did it was necessarily the best way to do it, but it did work.

With the caveat that my use case is slightly different (the app creates additional flags dynamically) and that I have not migrated from v1 of the app, here is the code: https://github.com/rliebz/tusk/blob/524de887cdfea4e2c1499ce25765e803ca57aaf9/appcli/app.go#L93-L141

rliebz avatar Jun 18 '21 01:06 rliebz