Cli: Subcommands Can't Use Flags

Created on 27 Jan 2019  路  8Comments  路  Source: urfave/cli

I can't seem to be able to access the bool flags from within a subcommand. Is this a regression?

image

When I run go run main.go --xts, it works, but when I run go run main.go encrypt --xts, it returns
image

kinbug statublocked

Most helpful comment

I have a fork of this I am maintaining and I added basic support for this. Support can be added in a nicer way and presented better but will take a bit more work. It would be nice to do this by separating the global flags so we can print them out in the same way that the parent level help command does. Right now I don't see that being possible while also letting people access the flags how they are accustomed to unless we duplicate them just for the purpose of outputting them. I however also added category support for flags in my branch so you can do something like this for your global commands and get a decent looking output.

  app := cli.NewApp()
  app.Name = "collins"
  app.Version = "0.0.1"
  app.Usage = "Interface with http://tumblr.github.io/collins/"
  app.Flags = []cli.Flag{
    cli.IntFlag{
      Name:     "timeout",
      Usage:    "Timeout in seconds (0 == forever)",
      Category: "Global setting",
    },
    cli.StringFlag{
      Name:     "C, config",
      Usage:    "Use specific Collins config yaml for client",
      Category: "Global setting",
    },
  }

This then renders like so in a sub command.

NAME:
   collins-go-cli query - Search for assets in Collins

USAGE:
   collins-go-cli query [command options] [arguments...]
OPTIONS:
  Global setting
   --timeout value           Timeout in seconds (0 == forever) (default: 0)
   -C value, --config value  Use specific Collins config yaml for client

  Query options
   -t value, --tag value             Assets with tag[s] value[,...]
   -Z, --remote-lookup               Query remote datacenters for asset
   -T value, --type value            Only show asset with type value
   -n value, --nodeclass value       Assets in nodeclass value[,...]
   -p value, --pool value            Assets in pool value[,...]
   -s value, --size value            Number of assets to return per page (default: 100)
   --limit value                     Limit total results of assets (default: 0)
   -r value, --role value            Assets in primary role
   -R value, --secondary-role value  Assets in secondary role
   -i value, --ip-address value      Assets with IP address[es]
   -S value, --status value          Asset status (and optional state after :)
   -a value, --attribute value       Arbitrary attributes and values to match in query. : between key and value

  Robot formatting
   -l, --link  Output link to assets found in web UI
   -j, --json  Output results in JSON
   -y, --yaml  Output results in YAML

  Table formatting
   -H, --show-header                  Show header fields in output
   -c value, --columns value          Attributes to output as columns, comma separated (default: "tag,hostname,nodeclass,status,pool,primary_role,secondary_role")
   -x value, --extra-columns value    Show these columns in addition to the default columns, comma separated
   -f value, --field-separator value  Separator between columns in output

If you are using go.mod you can use my patch via the following.

replace github.com/urfave/cli => github.com/michaeljs1990/cli global-flag-subcommand-passthrough

All 8 comments

Is this specific to bool commands only for you? In an example I mocked up they don't pass through for any flags that are at the global level. Additionally I don't see any output for global flags in the help template for sub commands.

Did this work in the past for you and are you using v1 or v2?

I have a fork of this I am maintaining and I added basic support for this. Support can be added in a nicer way and presented better but will take a bit more work. It would be nice to do this by separating the global flags so we can print them out in the same way that the parent level help command does. Right now I don't see that being possible while also letting people access the flags how they are accustomed to unless we duplicate them just for the purpose of outputting them. I however also added category support for flags in my branch so you can do something like this for your global commands and get a decent looking output.

  app := cli.NewApp()
  app.Name = "collins"
  app.Version = "0.0.1"
  app.Usage = "Interface with http://tumblr.github.io/collins/"
  app.Flags = []cli.Flag{
    cli.IntFlag{
      Name:     "timeout",
      Usage:    "Timeout in seconds (0 == forever)",
      Category: "Global setting",
    },
    cli.StringFlag{
      Name:     "C, config",
      Usage:    "Use specific Collins config yaml for client",
      Category: "Global setting",
    },
  }

This then renders like so in a sub command.

NAME:
   collins-go-cli query - Search for assets in Collins

USAGE:
   collins-go-cli query [command options] [arguments...]
OPTIONS:
  Global setting
   --timeout value           Timeout in seconds (0 == forever) (default: 0)
   -C value, --config value  Use specific Collins config yaml for client

  Query options
   -t value, --tag value             Assets with tag[s] value[,...]
   -Z, --remote-lookup               Query remote datacenters for asset
   -T value, --type value            Only show asset with type value
   -n value, --nodeclass value       Assets in nodeclass value[,...]
   -p value, --pool value            Assets in pool value[,...]
   -s value, --size value            Number of assets to return per page (default: 100)
   --limit value                     Limit total results of assets (default: 0)
   -r value, --role value            Assets in primary role
   -R value, --secondary-role value  Assets in secondary role
   -i value, --ip-address value      Assets with IP address[es]
   -S value, --status value          Asset status (and optional state after :)
   -a value, --attribute value       Arbitrary attributes and values to match in query. : between key and value

  Robot formatting
   -l, --link  Output link to assets found in web UI
   -j, --json  Output results in JSON
   -y, --yaml  Output results in YAML

  Table formatting
   -H, --show-header                  Show header fields in output
   -c value, --columns value          Attributes to output as columns, comma separated (default: "tag,hostname,nodeclass,status,pool,primary_role,secondary_role")
   -x value, --extra-columns value    Show these columns in addition to the default columns, comma separated
   -f value, --field-separator value  Separator between columns in output

If you are using go.mod you can use my patch via the following.

replace github.com/urfave/cli => github.com/michaeljs1990/cli global-flag-subcommand-passthrough

I also have global flags (database access details) that I need for my subcommands. Would love to see this implemented in this library.

[EDIT]
Well, I'm doing this now, which is fine for me:

dbFlags := []cli.Flag{
  cli.StringFlag{
    Name:  "psql-host",
    Value: "localhost",
    Usage: "The postgres host",
  },
  cli.IntFlag{
    Name:  "psql-port",
    Value: 5432,
    Usage: "The postgres port",
  },
  cli.StringFlag{
    Name:  "psql-user",
    Value: "user",
    Usage: "The postgres user",
  },
  cli.StringFlag{
    Name:  "psql-pass",
    Value: "secret",
    Usage: "The postgres pasword",
  },
  cli.StringFlag{
    Name:  "psql-db",
    Value: "dbname",
    Usage: "The postgres dbname",
  },
}

app.Flags = dbFlags

app.Commands = []cli.Command{
  {
    Name:    "up",
    Aliases: []string{"u"},
    Usage:   "Execute new migrations.",
    Action:  up,
    Flags:   dbFlags,
  },
  {
    Name:    "down",
    Aliases: []string{"d"},
    Usage:   "Revert migrations.",
    Action:  down,
    Flags:   dbFlags,
  },
}

Reading through the issue - it sounds like there's something we can do here! But I'm not quite sure what that is 馃攳 I think it would be helpful if someone wanted to followup here.

@lynncyrin to state this issue more succinctly:

app.Flags should be queryable alongside subcommand-specific flags within the cli.Context that's passed into cli.Command.Action's func.

I was stuck with the same problem and got the solution from @erikh:

You can query the global flags in app.Flags from a subcommand with c.GlobalBool, so instead of c.Bool("xts") it's c.GlobalBool("xts").

You also need to specify the global flags before the subcommand, so this should work:

go run main.go --xts encrypt

I'm actually going to remove the help wanted here, because I think https://github.com/urfave/cli/pull/892/ will fix this issue. I'll keep this issue open until someone can confirm, though

I can confirm that this is not an issue anymore.

package main

import (
    "fmt"
    "github.com/urfave/cli/v2"
    "log"
    "os"
)

func main() {
    app := &cli.App{}
    app.Name = "myprogramname"
    app.Commands = cli.Commands{
        {
            Name: "foo",
            Action: func(c *cli.Context) error {
                name := c.String("name")
                age := c.Int("age")
                eligible := c.Bool("eligible")

                fmt.Printf("Name: %s\nAge: %s\nIs Eligible: %v\n", name, age, eligible)
                return nil
            },
        },
    }
    app.Flags = []cli.Flag{
        &cli.StringFlag{
            Name: "name",
            Aliases: []string{"n"},
        },
        &cli.IntFlag{
            Name: "age",
            Aliases: []string{"a"},
        },
        &cli.BoolFlag{
            Name: "eligible",
            Aliases: []string{"e"},
        },
    }

    app.Action = func(c *cli.Context) error {
        name := c.String("name")
        age := c.Int("age")
        eligible := c.Bool("eligible")

        fmt.Printf("Name: %s\nAge: %s\nIs Eligible: %v\n", name, age, eligible)
        return nil
    }

    log.Fatal(app.Run(os.Args))
}

I tried to execute with this code on the v2 branch with the following commands:

go run main.go --name Ajitem --age 30 --eligible
go run main.go --name Ajitem --age 30 --eligible foo
go run main.go -n Ajitem -a 30 -e
go run main.go -n Ajitem -a 30 -e foo

I was able to access the values of the flags in the subcommands without any problem

Was this page helpful?
0 / 5 - 0 ratings

Related issues

LeonB picture LeonB  路  5Comments

vschettino picture vschettino  路  5Comments

nkprince007 picture nkprince007  路  5Comments

millken picture millken  路  5Comments

renzhengeek picture renzhengeek  路  5Comments