Crystal
Crystal

Reputation: 29468

Global parameters to commands using go-flags

I'm using this library https://github.com/jessevdk/go-flags

A command for my app might be like:

ex list events

So I have my wrapper command

type ExCommand struct {
    List list.ListCommand `command:"list" description:"list events" subcommands-optional:"true"`
}

List command

type ListCommand struct {
    ExCommand ExCommand `command:"events" description:"list events"`

    Config string `short:"c" long:"config" description:"config file" optional:"yes"`
}

Ex command

type EventsCommand struct {
}


func (c *ListCommand) Execute(args []string) error {
    fmt.Println("execute list")
    for _, val := range args {
        fmt.Println(val)
    }
    fmt.Printf("c: %s\n", c.Config)

    return nil
}

func (c *ExCommand) Execute(args []string) error {
    fmt.Println("list events")
    for _, val := range args {
        fmt.Println(val)
    }

    return nil
}

So what I'd like to do, is to have a few options like

verbose
config
terse

that are global options that can be run on any commands. I can't seem to figure out if there's a way to do this though with this library. Does anyone have experience with that? I can add Config to each individual low level command, list in this case the EventsCommand, but it seems like I'm repeating myself by adding at each low level command instead of the higher up ListCommand or ExCommand.

Upvotes: 2

Views: 1620

Answers (1)

Kel Cecil
Kel Cecil

Reputation: 194

You can use NewParser to create a new parser. You'll notice from the documentation that the first argument is a pointer to a struct that will be "Application Options." I'll start with an explanation and follow with a working example. Pretend you have the following struct that contains your application wide options:

type Defaults struct {
    Verbose []bool `short:"v" long:"verbose" description:"Show verbose debug information"`
    Terse   bool   `short:"t" long:"terse" description:"Shows terse output"`
}

You can pass this into the NewParser function as mentioned before like so:

defaultOptions = Defaults{}
parser = flags.NewParser(&defaultOptions, flags.Default)

Your additional commands can be added with the parser.AddCommand function. For example:

list := ListCommand{}
parser.AddCommand("list", "lists something", "", &list)

Finish up by calling parser. Parse and enjoy!

parser.Parse()
fmt.Printf("Verbose: %v\n", defaultOptions.Verbose)
fmt.Printf("Terse: %v\n", defaultOptions.Terse)

Here's a small fully-working example:

package main

import (
    "fmt"
    flags "github.com/jessevdk/go-flags"
)

type Defaults struct {
    Verbose []bool `short:"v" long:"verbose" description:"Show verbose    debug information"`
    Terse   bool   `short:"t" long:"terse" description:"Shows terse output"`
}

type ListCommand struct {
    Config string `short:"c" long:"config" description:"config file" optional:"yes"`
}

func main() {
    defaultOptions := Defaults{}
    listCmd := ListCommand{}

    parser := flags.NewParser(&defaultOptions, flags.Default)
    parser.AddCommand("list", "lists something", "", &listCmd)

    parser.Parse()
}

You can also achieve exactly what you're asking for by including the Defaults struct as an anonymous struct in your Command structs. Notice how I am referencing the Defaults type in my ListCommand struct but am not providing a name for the field. This allows me to access the fields of Defaults as if they were part of the ListCommand struct. The following example code allows me to provide the Verbose and Terse flags when using <prog> list -h:

package main

import flags "github.com/jessevdk/go-flags"

type Defaults struct {
    Verbose []bool `short:"v" long:"verbose" description:"Show verbose    debug information"`
    Terse   bool   `short:"t" long:"terse" description:"Shows terse output"`
}

type ListCommand struct {
    Config string `short:"c" long:"config" description:"config file" optional:"yes"`
    Defaults
}

func main() {
    listCmd := ListCommand{}

    parser := flags.NewParser(nil, flags.Default)
    parser.AddCommand("list", "lists something", "", &listCmd)

    parser.Parse()
}

Upvotes: 4

Related Questions