commit
9166808eb5
@ -1 +0,0 @@
|
|||||||
comment: false
|
|
@ -0,0 +1,9 @@
|
|||||||
|
comment: false
|
||||||
|
coverage:
|
||||||
|
status:
|
||||||
|
project:
|
||||||
|
default:
|
||||||
|
threshold: 5%
|
||||||
|
patch:
|
||||||
|
default:
|
||||||
|
threshold: 5%
|
@ -1,10 +1,12 @@
|
|||||||
*.coverprofile
|
*.coverprofile
|
||||||
|
*.exe
|
||||||
*.orig
|
*.orig
|
||||||
vendor
|
.*envrc
|
||||||
|
.envrc
|
||||||
.idea
|
.idea
|
||||||
internal/*/built-example
|
|
||||||
coverage.txt
|
|
||||||
/.local/
|
/.local/
|
||||||
|
/cmd/urfave-cli-genflags/urfave-cli-genflags
|
||||||
/site/
|
/site/
|
||||||
|
coverage.txt
|
||||||
*.exe
|
internal/*/built-example
|
||||||
|
vendor
|
||||||
|
@ -1,23 +1,25 @@
|
|||||||
// Package cli provides a minimal framework for creating and organizing command line
|
// Package cli provides a minimal framework for creating and organizing command line
|
||||||
// Go applications. cli is designed to be easy to understand and write, the most simple
|
// Go applications. cli is designed to be easy to understand and write, the most simple
|
||||||
// cli application can be written as follows:
|
// cli application can be written as follows:
|
||||||
// func main() {
|
//
|
||||||
// (&cli.App{}).Run(os.Args)
|
// func main() {
|
||||||
// }
|
// (&cli.App{}).Run(os.Args)
|
||||||
|
// }
|
||||||
//
|
//
|
||||||
// Of course this application does not do much, so let's make this an actual application:
|
// Of course this application does not do much, so let's make this an actual application:
|
||||||
// func main() {
|
|
||||||
// app := &cli.App{
|
|
||||||
// Name: "greet",
|
|
||||||
// Usage: "say a greeting",
|
|
||||||
// Action: func(c *cli.Context) error {
|
|
||||||
// fmt.Println("Greetings")
|
|
||||||
// return nil
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// app.Run(os.Args)
|
// func main() {
|
||||||
// }
|
// app := &cli.App{
|
||||||
|
// Name: "greet",
|
||||||
|
// Usage: "say a greeting",
|
||||||
|
// Action: func(c *cli.Context) error {
|
||||||
|
// fmt.Println("Greetings")
|
||||||
|
// return nil
|
||||||
|
// },
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// app.Run(os.Args)
|
||||||
|
// }
|
||||||
package cli
|
package cli
|
||||||
|
|
||||||
//go:generate go run internal/genflags/cmd/genflags/main.go
|
//go:generate go run cmd/urfave-cli-genflags/main.go
|
||||||
|
@ -0,0 +1,21 @@
|
|||||||
|
GOTEST_FLAGS ?= -v --coverprofile main.coverprofile --covermode count --cover github.com/urfave/cli/v2/cmd/urfave-cli-genflags
|
||||||
|
GOBUILD_FLAGS ?= -x
|
||||||
|
|
||||||
|
.PHONY: all
|
||||||
|
all: test build smoke-test
|
||||||
|
|
||||||
|
.PHONY: test
|
||||||
|
test:
|
||||||
|
go test $(GOTEST_FLAGS) ./...
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build:
|
||||||
|
go build $(GOBUILD_FLAGS) ./...
|
||||||
|
|
||||||
|
.PHONY: smoke-test
|
||||||
|
smoke-test: build
|
||||||
|
./urfave-cli-genflags --help
|
||||||
|
|
||||||
|
.PHONY: show-cover
|
||||||
|
show-cover:
|
||||||
|
go tool cover -func main.coverprofile
|
@ -0,0 +1,15 @@
|
|||||||
|
# urfave-cli-genflags
|
||||||
|
|
||||||
|
This is a tool that is used internally by [urfave/cli] to generate
|
||||||
|
flag types and methods from a YAML input. It intentionally pins
|
||||||
|
usage of `github.com/urfave/cli/v2` to a *release* rather than
|
||||||
|
using the adjacent code so that changes don't result in *this* tool
|
||||||
|
refusing to compile. It's almost like dogfooding?
|
||||||
|
|
||||||
|
## support warning
|
||||||
|
|
||||||
|
This tool is maintained as a sub-project and is not covered by the
|
||||||
|
API and backward compatibility guaranteed by releases of
|
||||||
|
[urfave/cli].
|
||||||
|
|
||||||
|
[urfave/cli]: https://github.com/urfave/cli
|
@ -0,0 +1,15 @@
|
|||||||
|
module github.com/urfave/cli/v2/cmd/urfave-cli-genflags
|
||||||
|
|
||||||
|
go 1.18
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/urfave/cli/v2 v2.11.2
|
||||||
|
golang.org/x/text v0.3.7
|
||||||
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||||
|
)
|
@ -0,0 +1,14 @@
|
|||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/urfave/cli/v2 v2.11.2 h1:FVfNg4m3vbjbBpLYxW//WjxUoHvJ9TlppXcqY9Q9ZfA=
|
||||||
|
github.com/urfave/cli/v2 v2.11.2/go.mod h1:f8iq5LtQ/bLxafbdBSLPPNsgaW0l/2fYYEHhAyPlwvo=
|
||||||
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
|
||||||
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
|
||||||
|
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v1
|
||||||
|
---
|
||||||
|
|
||||||
|
You can lookup arguments by calling the `Args` function on `cli.Context`, e.g.:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"output": "Hello \""
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
|
||||||
|
app.Action = func(c *cli.Context) error {
|
||||||
|
fmt.Printf("Hello %q", c.Args().Get(0))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
@ -0,0 +1,119 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v1
|
||||||
|
---
|
||||||
|
|
||||||
|
You can enable completion commands by setting the `EnableBashCompletion`
|
||||||
|
flag on the `App` object. By default, this setting will only auto-complete to
|
||||||
|
show an app's subcommands, but you can write your own completion methods for
|
||||||
|
the App or its subcommands.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["complete", "--generate-bash-completion"],
|
||||||
|
"output": "laundry"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
tasks := []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
|
||||||
|
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.EnableBashCompletion = true
|
||||||
|
app.Commands = []cli.Command{
|
||||||
|
{
|
||||||
|
Name: "complete",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Usage: "complete a task on the list",
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
fmt.Println("completed task: ", c.Args().First())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
BashComplete: func(c *cli.Context) {
|
||||||
|
// This will complete if no args are passed
|
||||||
|
if c.NArg() > 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, t := range tasks {
|
||||||
|
fmt.Println(t)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Enabling
|
||||||
|
|
||||||
|
Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while
|
||||||
|
setting the `PROG` variable to the name of your program:
|
||||||
|
|
||||||
|
`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete`
|
||||||
|
|
||||||
|
#### Distribution
|
||||||
|
|
||||||
|
Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename
|
||||||
|
it to the name of the program you wish to add autocomplete support for (or
|
||||||
|
automatically install it there if you are distributing a package). Don't forget
|
||||||
|
to source the file to make it active in the current shell.
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo cp src/bash_autocomplete /etc/bash_completion.d/<myprogram>
|
||||||
|
source /etc/bash_completion.d/<myprogram>
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can just document that users should source the generic
|
||||||
|
`autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set
|
||||||
|
to the name of their program (as above).
|
||||||
|
|
||||||
|
#### Customization
|
||||||
|
|
||||||
|
The default bash completion flag (`--generate-bash-completion`) is defined as
|
||||||
|
`cli.BashCompletionFlag`, and may be redefined if desired, e.g.:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--compgen"],
|
||||||
|
"output": "wat\nhelp\nh"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cli.BashCompletionFlag = cli.BoolFlag{
|
||||||
|
Name: "compgen",
|
||||||
|
Hidden: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.EnableBashCompletion = true
|
||||||
|
app.Commands = []cli.Command{
|
||||||
|
{
|
||||||
|
Name: "wat",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
@ -0,0 +1,72 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v1
|
||||||
|
---
|
||||||
|
|
||||||
|
Traditional use of options using their shortnames look like this:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cmd -s -o -m "Some message"
|
||||||
|
```
|
||||||
|
|
||||||
|
Suppose you want users to be able to combine options with their shortnames. This
|
||||||
|
can be done using the `UseShortOptionHandling` bool in your app configuration,
|
||||||
|
or for individual commands by attaching it to the command configuration. For
|
||||||
|
example:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["short", "-som", "Some message"],
|
||||||
|
"output": "serve: true\noption: true\nmessage: Some message\n"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.UseShortOptionHandling = true
|
||||||
|
app.Commands = []cli.Command{
|
||||||
|
{
|
||||||
|
Name: "short",
|
||||||
|
Usage: "complete a task on the list",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
cli.BoolFlag{Name: "serve, s"},
|
||||||
|
cli.BoolFlag{Name: "option, o"},
|
||||||
|
cli.StringFlag{Name: "message, m"},
|
||||||
|
},
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
fmt.Println("serve:", c.Bool("serve"))
|
||||||
|
fmt.Println("option:", c.Bool("option"))
|
||||||
|
fmt.Println("message:", c.String("message"))
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If your program has any number of bool flags such as `serve` and `option`, and
|
||||||
|
optionally one non-bool flag `message`, with the short options of `-s`, `-o`,
|
||||||
|
and `-m` respectively, setting `UseShortOptionHandling` will also support the
|
||||||
|
following syntax:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ cmd -som "Some message"
|
||||||
|
```
|
||||||
|
|
||||||
|
If you enable `UseShortOptionHandling`, then you must not use any flags that
|
||||||
|
have a single leading `-` or this will result in failures. For example,
|
||||||
|
`-option` can no longer be used. Flags with two leading dashes (such as
|
||||||
|
`--options`) are still valid.
|
@ -0,0 +1,43 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v1
|
||||||
|
---
|
||||||
|
|
||||||
|
Calling `App.Run` will not automatically call `os.Exit`, which means that by
|
||||||
|
default the exit code will "fall through" to being `0`. An explicit exit code
|
||||||
|
may be set by returning a non-nil error that fulfills `cli.ExitCoder`, *or* a
|
||||||
|
`cli.MultiError` that includes an error that fulfills `cli.ExitCoder`, e.g.:
|
||||||
|
<!-- {
|
||||||
|
"error": "Ginger croutons are not in the soup"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.Flags = []cli.Flag{
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "ginger-crouton",
|
||||||
|
Usage: "Add ginger croutons to the soup",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
app.Action = func(ctx *cli.Context) error {
|
||||||
|
if !ctx.Bool("ginger-crouton") {
|
||||||
|
return cli.NewExitError("Ginger croutons are not in the soup", 86)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
@ -0,0 +1,462 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v1
|
||||||
|
---
|
||||||
|
|
||||||
|
Setting and querying flags is simple.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"output": "Hello Nefertiti"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
|
||||||
|
app.Flags = []cli.Flag {
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "lang",
|
||||||
|
Value: "english",
|
||||||
|
Usage: "language for the greeting",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
app.Action = func(c *cli.Context) error {
|
||||||
|
name := "Nefertiti"
|
||||||
|
if c.NArg() > 0 {
|
||||||
|
name = c.Args().Get(0)
|
||||||
|
}
|
||||||
|
if c.String("lang") == "spanish" {
|
||||||
|
fmt.Println("Hola", name)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Hello", name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also set a destination variable for a flag, to which the content will be
|
||||||
|
scanned.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"output": "Hello someone"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var language string
|
||||||
|
|
||||||
|
app := cli.NewApp()
|
||||||
|
|
||||||
|
app.Flags = []cli.Flag {
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "lang",
|
||||||
|
Value: "english",
|
||||||
|
Usage: "language for the greeting",
|
||||||
|
Destination: &language,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
app.Action = func(c *cli.Context) error {
|
||||||
|
name := "someone"
|
||||||
|
if c.NArg() > 0 {
|
||||||
|
name = c.Args()[0]
|
||||||
|
}
|
||||||
|
if language == "spanish" {
|
||||||
|
fmt.Println("Hola", name)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Hello", name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See full list of flags at http://godoc.org/github.com/urfave/cli
|
||||||
|
|
||||||
|
#### Placeholder Values
|
||||||
|
|
||||||
|
Sometimes it's useful to specify a flag's value within the usage string itself.
|
||||||
|
Such placeholders are indicated with back quotes.
|
||||||
|
|
||||||
|
For example this:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "--config FILE, -c FILE"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
|
||||||
|
app.Flags = []cli.Flag{
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "config, c",
|
||||||
|
Usage: "Load configuration from `FILE`",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Will result in help output like:
|
||||||
|
|
||||||
|
```
|
||||||
|
--config FILE, -c FILE Load configuration from FILE
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that only the first placeholder is used. Subsequent back-quoted words will
|
||||||
|
be left as-is.
|
||||||
|
|
||||||
|
#### Alternate Names
|
||||||
|
|
||||||
|
You can set alternate (or short) names for flags by providing a comma-delimited
|
||||||
|
list for the `Name`. e.g.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "--lang value, -l value.*language for the greeting.*default: \"english\""
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
|
||||||
|
app.Flags = []cli.Flag {
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "lang, l",
|
||||||
|
Value: "english",
|
||||||
|
Usage: "language for the greeting",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
That flag can then be set with `--lang spanish` or `-l spanish`. Note that
|
||||||
|
giving two different forms of the same flag in the same command invocation is an
|
||||||
|
error.
|
||||||
|
|
||||||
|
#### Ordering
|
||||||
|
|
||||||
|
Flags for the application and commands are shown in the order they are defined.
|
||||||
|
However, it's possible to sort them from outside this library by using `FlagsByName`
|
||||||
|
or `CommandsByName` with `sort`.
|
||||||
|
|
||||||
|
For example this:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "add a task to the list\n.*complete a task on the list\n.*\n\n.*\n.*Load configuration from FILE\n.*Language for the greeting.*"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
|
||||||
|
app.Flags = []cli.Flag {
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "lang, l",
|
||||||
|
Value: "english",
|
||||||
|
Usage: "Language for the greeting",
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "config, c",
|
||||||
|
Usage: "Load configuration from `FILE`",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
app.Commands = []cli.Command{
|
||||||
|
{
|
||||||
|
Name: "complete",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Usage: "complete a task on the list",
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "add",
|
||||||
|
Aliases: []string{"a"},
|
||||||
|
Usage: "add a task to the list",
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(cli.FlagsByName(app.Flags))
|
||||||
|
sort.Sort(cli.CommandsByName(app.Commands))
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Will result in help output like:
|
||||||
|
|
||||||
|
```
|
||||||
|
--config FILE, -c FILE Load configuration from FILE
|
||||||
|
--lang value, -l value Language for the greeting (default: "english")
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Values from the Environment
|
||||||
|
|
||||||
|
You can also have the default value set from the environment via `EnvVar`. e.g.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "language for the greeting.*APP_LANG"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
|
||||||
|
app.Flags = []cli.Flag {
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "lang, l",
|
||||||
|
Value: "english",
|
||||||
|
Usage: "language for the greeting",
|
||||||
|
EnvVar: "APP_LANG",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The `EnvVar` may also be given as a comma-delimited "cascade", where the first
|
||||||
|
environment variable that resolves is used as the default.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "language for the greeting.*LEGACY_COMPAT_LANG.*APP_LANG.*LANG"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
|
||||||
|
app.Flags = []cli.Flag {
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "lang, l",
|
||||||
|
Value: "english",
|
||||||
|
Usage: "language for the greeting",
|
||||||
|
EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Values from files
|
||||||
|
|
||||||
|
You can also have the default value set from file via `FilePath`. e.g.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "password for the mysql database"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
|
||||||
|
app.Flags = []cli.Flag {
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "password, p",
|
||||||
|
Usage: "password for the mysql database",
|
||||||
|
FilePath: "/etc/mysql/password",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that default values set from file (e.g. `FilePath`) take precedence over
|
||||||
|
default values set from the environment (e.g. `EnvVar`).
|
||||||
|
|
||||||
|
#### Values from alternate input sources (YAML, TOML, and others)
|
||||||
|
|
||||||
|
There is a separate package altsrc that adds support for getting flag values
|
||||||
|
from other file input sources.
|
||||||
|
|
||||||
|
Currently supported input source formats:
|
||||||
|
* YAML
|
||||||
|
* JSON
|
||||||
|
* TOML
|
||||||
|
|
||||||
|
In order to get values for a flag from an alternate input source the following
|
||||||
|
code would be added to wrap an existing cli.Flag like below:
|
||||||
|
|
||||||
|
``` go
|
||||||
|
altsrc.NewIntFlag(cli.IntFlag{Name: "test"})
|
||||||
|
```
|
||||||
|
|
||||||
|
Initialization must also occur for these flags. Below is an example initializing
|
||||||
|
getting data from a yaml file below.
|
||||||
|
|
||||||
|
``` go
|
||||||
|
command.Before = altsrc.InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
|
```
|
||||||
|
|
||||||
|
The code above will use the "load" string as a flag name to get the file name of
|
||||||
|
a yaml file from the cli.Context. It will then use that file name to initialize
|
||||||
|
the yaml input source for any flags that are defined on that command. As a note
|
||||||
|
the "load" flag used would also have to be defined on the command flags in order
|
||||||
|
for this code snippet to work.
|
||||||
|
|
||||||
|
Currently only YAML, JSON, and TOML files are supported but developers can add support
|
||||||
|
for other input sources by implementing the altsrc.InputSourceContext for their
|
||||||
|
given sources.
|
||||||
|
|
||||||
|
Here is a more complete sample of a command using YAML support:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "--test value.*default: 0"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package notmain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
"github.com/urfave/cli/altsrc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
|
||||||
|
flags := []cli.Flag{
|
||||||
|
altsrc.NewIntFlag(cli.IntFlag{Name: "test"}),
|
||||||
|
cli.StringFlag{Name: "load"},
|
||||||
|
}
|
||||||
|
|
||||||
|
app.Action = func(c *cli.Context) error {
|
||||||
|
fmt.Println("yaml ist rad")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
app.Before = altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc("load"))
|
||||||
|
app.Flags = flags
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Precedence
|
||||||
|
|
||||||
|
The precedence for flag value sources is as follows (highest to lowest):
|
||||||
|
|
||||||
|
0. Command line flag value from user
|
||||||
|
0. Environment variable (if specified)
|
||||||
|
0. Configuration file (if specified)
|
||||||
|
0. Default defined on the flag
|
@ -0,0 +1,106 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v1
|
||||||
|
---
|
||||||
|
|
||||||
|
The default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked
|
||||||
|
by the cli internals in order to print generated help text for the app, command,
|
||||||
|
or subcommand, and break execution.
|
||||||
|
|
||||||
|
#### Customization
|
||||||
|
|
||||||
|
All of the help text generation may be customized, and at multiple levels. The
|
||||||
|
templates are exposed as variables `AppHelpTemplate`, `CommandHelpTemplate`, and
|
||||||
|
`SubcommandHelpTemplate` which may be reassigned or augmented, and full override
|
||||||
|
is possible by assigning a compatible func to the `cli.HelpPrinter` variable,
|
||||||
|
e.g.:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"output": "Ha HA. I pwnd the help!!1"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// EXAMPLE: Append to an existing template
|
||||||
|
cli.AppHelpTemplate = fmt.Sprintf(`%s
|
||||||
|
|
||||||
|
WEBSITE: http://awesometown.example.com
|
||||||
|
|
||||||
|
SUPPORT: support@awesometown.example.com
|
||||||
|
|
||||||
|
`, cli.AppHelpTemplate)
|
||||||
|
|
||||||
|
// EXAMPLE: Override a template
|
||||||
|
cli.AppHelpTemplate = `NAME:
|
||||||
|
{{.Name}} - {{.Usage}}
|
||||||
|
USAGE:
|
||||||
|
{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
|
||||||
|
{{if len .Authors}}
|
||||||
|
AUTHOR:
|
||||||
|
{{range .Authors}}{{ . }}{{end}}
|
||||||
|
{{end}}{{if .Commands}}
|
||||||
|
COMMANDS:
|
||||||
|
{{range .Commands}}{{if not .HideHelp}} {{join .Names ", "}}{{ "\t"}}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
|
||||||
|
GLOBAL OPTIONS:
|
||||||
|
{{range .VisibleFlags}}{{.}}
|
||||||
|
{{end}}{{end}}{{if .Copyright }}
|
||||||
|
COPYRIGHT:
|
||||||
|
{{.Copyright}}
|
||||||
|
{{end}}{{if .Version}}
|
||||||
|
VERSION:
|
||||||
|
{{.Version}}
|
||||||
|
{{end}}
|
||||||
|
`
|
||||||
|
|
||||||
|
// EXAMPLE: Replace the `HelpPrinter` func
|
||||||
|
cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {
|
||||||
|
fmt.Println("Ha HA. I pwnd the help!!1")
|
||||||
|
}
|
||||||
|
|
||||||
|
err := cli.NewApp().Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The default flag may be customized to something other than `-h/--help` by
|
||||||
|
setting `cli.HelpFlag`, e.g.:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--halp"],
|
||||||
|
"output": "haaaaalp.*HALP"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cli.HelpFlag = cli.BoolFlag{
|
||||||
|
Name: "halp, haaaaalp",
|
||||||
|
Usage: "HALP",
|
||||||
|
EnvVar: "SHOW_HALP,HALPPLZ",
|
||||||
|
}
|
||||||
|
|
||||||
|
err := cli.NewApp().Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v1
|
||||||
|
---
|
||||||
|
|
||||||
|
Being a programmer can be a lonely job. Thankfully by the power of automation
|
||||||
|
that is not the case! Let's create a greeter app to fend off our demons of
|
||||||
|
loneliness!
|
||||||
|
|
||||||
|
Start by creating a directory named `greet`, and within it, add a file,
|
||||||
|
`greet.go` with the following code in it:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"output": "Hello friend!"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.Name = "greet"
|
||||||
|
app.Usage = "fight the loneliness!"
|
||||||
|
app.Action = func(c *cli.Context) error {
|
||||||
|
fmt.Println("Hello friend!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Install our command to the `$GOPATH/bin` directory:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ go install
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally run our new command:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ greet
|
||||||
|
Hello friend!
|
||||||
|
```
|
||||||
|
|
||||||
|
cli also generates neat help text:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ greet help
|
||||||
|
NAME:
|
||||||
|
greet - fight the loneliness!
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
greet [global options] command [command options] [arguments...]
|
||||||
|
|
||||||
|
VERSION:
|
||||||
|
0.0.0
|
||||||
|
|
||||||
|
COMMANDS:
|
||||||
|
help, h Shows a list of commands or help for one command
|
||||||
|
|
||||||
|
GLOBAL OPTIONS
|
||||||
|
--version Shows version information
|
||||||
|
```
|
@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v1
|
||||||
|
---
|
||||||
|
|
||||||
|
For additional organization in apps that have many subcommands, you can
|
||||||
|
associate a category for each command to group them together in the help
|
||||||
|
output.
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
|
||||||
|
app.Commands = []cli.Command{
|
||||||
|
{
|
||||||
|
Name: "noop",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "add",
|
||||||
|
Category: "Template actions",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "remove",
|
||||||
|
Category: "Template actions",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Will include:
|
||||||
|
|
||||||
|
```
|
||||||
|
COMMANDS:
|
||||||
|
noop
|
||||||
|
|
||||||
|
Template actions:
|
||||||
|
add
|
||||||
|
remove
|
||||||
|
```
|
@ -0,0 +1,75 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v1
|
||||||
|
---
|
||||||
|
|
||||||
|
Subcommands can be defined for a more git-like command line app.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["template", "add"],
|
||||||
|
"output": "new task template: .+"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
|
||||||
|
app.Commands = []cli.Command{
|
||||||
|
{
|
||||||
|
Name: "add",
|
||||||
|
Aliases: []string{"a"},
|
||||||
|
Usage: "add a task to the list",
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
fmt.Println("added task: ", c.Args().First())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "complete",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Usage: "complete a task on the list",
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
fmt.Println("completed task: ", c.Args().First())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "template",
|
||||||
|
Aliases: []string{"t"},
|
||||||
|
Usage: "options for task templates",
|
||||||
|
Subcommands: []cli.Command{
|
||||||
|
{
|
||||||
|
Name: "add",
|
||||||
|
Usage: "add a new template",
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
fmt.Println("new task template: ", c.Args().First())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "remove",
|
||||||
|
Usage: "remove an existing template",
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
fmt.Println("removed task template: ", c.Args().First())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v1
|
||||||
|
---
|
||||||
|
|
||||||
|
One of the philosophies behind cli is that an API should be playful and full of
|
||||||
|
discovery. So a cli app can be as little as one line of code in `main()`.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "A new cli application"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := cli.NewApp().Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This app will run and show help text, but is not very useful. Let's give an
|
||||||
|
action to execute and some help documentation:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"output": "boom! I say!"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := cli.NewApp()
|
||||||
|
app.Name = "boom"
|
||||||
|
app.Usage = "make an explosive entrance"
|
||||||
|
app.Action = func(c *cli.Context) error {
|
||||||
|
fmt.Println("boom! I say!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err := app.Run(os.Args)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Running this already gives you a ton of functionality, plus support for things
|
||||||
|
like subcommands and flags, which are covered below.
|
@ -1 +0,0 @@
|
|||||||
manual.md
|
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v1
|
||||||
|
---
|
||||||
|
|
||||||
|
There are a small set of breaking changes between v1 and v2.
|
||||||
|
Converting is relatively straightforward and typically takes less than
|
||||||
|
an hour. Specific steps are included in
|
||||||
|
[Migration Guide: v1 to v2](../migrate-v1-to-v2.md).
|
@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v2
|
||||||
|
search:
|
||||||
|
boost: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
You can lookup arguments by calling the `Args` function on `cli.Context`, e.g.:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"output": "Hello \""
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
fmt.Printf("Hello %q", cCtx.Args().Get(0))
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
@ -0,0 +1,257 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v2
|
||||||
|
search:
|
||||||
|
boost: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
You can enable completion commands by setting the `EnableBashCompletion` flag on
|
||||||
|
the `App` object to `true`. By default, this setting will allow auto-completion
|
||||||
|
for an app's subcommands, but you can write your own completion methods for the
|
||||||
|
App or its subcommands as well.
|
||||||
|
|
||||||
|
#### Default auto-completion
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
EnableBashCompletion: true,
|
||||||
|
Commands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "add",
|
||||||
|
Aliases: []string{"a"},
|
||||||
|
Usage: "add a task to the list",
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
fmt.Println("added task: ", cCtx.Args().First())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "complete",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Usage: "complete a task on the list",
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
fmt.Println("completed task: ", cCtx.Args().First())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "template",
|
||||||
|
Aliases: []string{"t"},
|
||||||
|
Usage: "options for task templates",
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "add",
|
||||||
|
Usage: "add a new template",
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
fmt.Println("new task template: ", cCtx.Args().First())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "remove",
|
||||||
|
Usage: "remove an existing template",
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
fmt.Println("removed task template: ", cCtx.Args().First())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
![](/docs/v2/images/default-bash-autocomplete.gif)
|
||||||
|
|
||||||
|
#### Custom auto-completion
|
||||||
|
<!-- {
|
||||||
|
"args": ["complete", "--generate-bash-completion"],
|
||||||
|
"output": "laundry"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
tasks := []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
|
||||||
|
|
||||||
|
app := &cli.App{
|
||||||
|
EnableBashCompletion: true,
|
||||||
|
Commands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "complete",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Usage: "complete a task on the list",
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
fmt.Println("completed task: ", cCtx.Args().First())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
BashComplete: func(cCtx *cli.Context) {
|
||||||
|
// This will complete if no args are passed
|
||||||
|
if cCtx.NArg() > 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, t := range tasks {
|
||||||
|
fmt.Println(t)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
![](/docs/v2/images/custom-bash-autocomplete.gif)
|
||||||
|
|
||||||
|
#### Enabling
|
||||||
|
|
||||||
|
To enable auto-completion for the current shell session, a bash script,
|
||||||
|
`autocomplete/bash_autocomplete` is included in this repo.
|
||||||
|
|
||||||
|
To use `autocomplete/bash_autocomplete` set an environment variable named `PROG`
|
||||||
|
to the name of your program and then `source` the
|
||||||
|
`autocomplete/bash_autocomplete` file.
|
||||||
|
|
||||||
|
For example, if your cli program is called `myprogram`:
|
||||||
|
|
||||||
|
```sh-session
|
||||||
|
$ PROG=myprogram source path/to/cli/autocomplete/bash_autocomplete
|
||||||
|
```
|
||||||
|
|
||||||
|
Auto-completion is now enabled for the current shell, but will not persist into
|
||||||
|
a new shell.
|
||||||
|
|
||||||
|
#### Distribution and Persistent Autocompletion
|
||||||
|
|
||||||
|
Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename
|
||||||
|
it to the name of the program you wish to add autocomplete support for (or
|
||||||
|
automatically install it there if you are distributing a package). Don't forget
|
||||||
|
to source the file or restart your shell to activate the auto-completion.
|
||||||
|
|
||||||
|
```sh-session
|
||||||
|
$ sudo cp path/to/autocomplete/bash_autocomplete /etc/bash_completion.d/<myprogram>
|
||||||
|
$ source /etc/bash_completion.d/<myprogram>
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can just document that users should `source` the generic
|
||||||
|
`autocomplete/bash_autocomplete` and set `$PROG` within their bash configuration
|
||||||
|
file, adding these lines:
|
||||||
|
|
||||||
|
```sh-session
|
||||||
|
$ PROG=<myprogram>
|
||||||
|
$ source path/to/cli/autocomplete/bash_autocomplete
|
||||||
|
```
|
||||||
|
|
||||||
|
Keep in mind that if they are enabling auto-completion for more than one
|
||||||
|
program, they will need to set `PROG` and source
|
||||||
|
`autocomplete/bash_autocomplete` for each program, like so:
|
||||||
|
|
||||||
|
```sh-session
|
||||||
|
$ PROG=<program1>
|
||||||
|
$ source path/to/cli/autocomplete/bash_autocomplete
|
||||||
|
|
||||||
|
$ PROG=<program2>
|
||||||
|
$ source path/to/cli/autocomplete/bash_autocomplete
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Customization
|
||||||
|
|
||||||
|
The default shell completion flag (`--generate-bash-completion`) is defined as
|
||||||
|
`cli.EnableBashCompletion`, and may be redefined if desired, e.g.:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--generate-bash-completion"],
|
||||||
|
"output": "wat\nhelp\nh"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
EnableBashCompletion: true,
|
||||||
|
Commands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "wat",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### ZSH Support
|
||||||
|
|
||||||
|
Auto-completion for ZSH is also supported using the
|
||||||
|
`autocomplete/zsh_autocomplete` file included in this repo. One environment
|
||||||
|
variable is used, `PROG`. Set `PROG` to the program name as before, and then
|
||||||
|
`source path/to/autocomplete/zsh_autocomplete`. Adding the following lines to
|
||||||
|
your ZSH configuration file (usually `.zshrc`) will allow the auto-completion to
|
||||||
|
persist across new shells:
|
||||||
|
|
||||||
|
```sh-session
|
||||||
|
$ PROG=<myprogram>
|
||||||
|
$ source path/to/autocomplete/zsh_autocomplete
|
||||||
|
```
|
||||||
|
|
||||||
|
#### ZSH default auto-complete example
|
||||||
|
![](/docs/v2/images/default-zsh-autocomplete.gif)
|
||||||
|
|
||||||
|
#### ZSH custom auto-complete example
|
||||||
|
![](/docs/v2/images/custom-zsh-autocomplete.gif)
|
||||||
|
|
||||||
|
#### PowerShell Support
|
||||||
|
|
||||||
|
Auto-completion for PowerShell is also supported using the
|
||||||
|
`autocomplete/powershell_autocomplete.ps1` file included in this repo.
|
||||||
|
|
||||||
|
Rename the script to `<my program>.ps1` and move it anywhere in your file
|
||||||
|
system. The location of script does not matter, only the file name of the
|
||||||
|
script has to match the your program's binary name.
|
||||||
|
|
||||||
|
To activate it, enter:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
& path/to/autocomplete/<my program>.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
To persist across new shells, open the PowerShell profile (with `code $profile`
|
||||||
|
or `notepad $profile`) and add the line:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
& path/to/autocomplete/<my program>.ps1
|
||||||
|
```
|
@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v2
|
||||||
|
search:
|
||||||
|
boost: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
Traditional use of options using their shortnames look like this:
|
||||||
|
|
||||||
|
```sh-session
|
||||||
|
$ cmd -s -o -m "Some message"
|
||||||
|
```
|
||||||
|
|
||||||
|
Suppose you want users to be able to combine options with their shortnames. This
|
||||||
|
can be done using the `UseShortOptionHandling` bool in your app configuration,
|
||||||
|
or for individual commands by attaching it to the command configuration. For
|
||||||
|
example:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["short", "-som", "Some message"],
|
||||||
|
"output": "serve: true\noption: true\nmessage: Some message\n"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
UseShortOptionHandling: true,
|
||||||
|
Commands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "short",
|
||||||
|
Usage: "complete a task on the list",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{Name: "serve", Aliases: []string{"s"}},
|
||||||
|
&cli.BoolFlag{Name: "option", Aliases: []string{"o"}},
|
||||||
|
&cli.StringFlag{Name: "message", Aliases: []string{"m"}},
|
||||||
|
},
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
fmt.Println("serve:", cCtx.Bool("serve"))
|
||||||
|
fmt.Println("option:", cCtx.Bool("option"))
|
||||||
|
fmt.Println("message:", cCtx.String("message"))
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If your program has any number of bool flags such as `serve` and `option`, and
|
||||||
|
optionally one non-bool flag `message`, with the short options of `-s`, `-o`,
|
||||||
|
and `-m` respectively, setting `UseShortOptionHandling` will also support the
|
||||||
|
following syntax:
|
||||||
|
|
||||||
|
```sh-session
|
||||||
|
$ cmd -som "Some message"
|
||||||
|
```
|
||||||
|
|
||||||
|
If you enable `UseShortOptionHandling`, then you must not use any flags that
|
||||||
|
have a single leading `-` or this will result in failures. For example,
|
||||||
|
`-option` can no longer be used. Flags with two leading dashes (such as
|
||||||
|
`--options`) are still valid.
|
@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v2
|
||||||
|
search:
|
||||||
|
boost: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
Calling `App.Run` will not automatically call `os.Exit`, which means that by
|
||||||
|
default the exit code will "fall through" to being `0`. An explicit exit code
|
||||||
|
may be set by returning a non-nil error that fulfills `cli.ExitCoder`, *or* a
|
||||||
|
`cli.MultiError` that includes an error that fulfills `cli.ExitCoder`, e.g.:
|
||||||
|
<!-- {
|
||||||
|
"error": "Ginger croutons are not in the soup"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "ginger-crouton",
|
||||||
|
Usage: "is it in the soup?",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(ctx *cli.Context) error {
|
||||||
|
if !ctx.Bool("ginger-crouton") {
|
||||||
|
return cli.Exit("Ginger croutons are not in the soup", 86)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
@ -0,0 +1,597 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v2
|
||||||
|
search:
|
||||||
|
boost: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
Setting and querying flags is simple.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"output": "Hello Nefertiti"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "lang",
|
||||||
|
Value: "english",
|
||||||
|
Usage: "language for the greeting",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
name := "Nefertiti"
|
||||||
|
if cCtx.NArg() > 0 {
|
||||||
|
name = cCtx.Args().Get(0)
|
||||||
|
}
|
||||||
|
if cCtx.String("lang") == "spanish" {
|
||||||
|
fmt.Println("Hola", name)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Hello", name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also set a destination variable for a flag, to which the content will be
|
||||||
|
scanned.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"output": "Hello someone"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var language string
|
||||||
|
|
||||||
|
app := &cli.App{
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "lang",
|
||||||
|
Value: "english",
|
||||||
|
Usage: "language for the greeting",
|
||||||
|
Destination: &language,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
name := "someone"
|
||||||
|
if cCtx.NArg() > 0 {
|
||||||
|
name = cCtx.Args().Get(0)
|
||||||
|
}
|
||||||
|
if language == "spanish" {
|
||||||
|
fmt.Println("Hola", name)
|
||||||
|
} else {
|
||||||
|
fmt.Println("Hello", name)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See full list of flags at https://pkg.go.dev/github.com/urfave/cli/v2
|
||||||
|
|
||||||
|
For bool flags you can specify the flag multiple times to get a count(e.g -v -v -v or -vvv)
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--foo", "--foo"],
|
||||||
|
"output": "count 2"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var count int
|
||||||
|
|
||||||
|
app := &cli.App{
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "foo",
|
||||||
|
Usage: "foo greeting",
|
||||||
|
Count: &count,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
fmt.Println("count", count)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Placeholder Values
|
||||||
|
|
||||||
|
Sometimes it's useful to specify a flag's value within the usage string itself.
|
||||||
|
Such placeholders are indicated with back quotes.
|
||||||
|
|
||||||
|
For example this:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "--config FILE, -c FILE"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "config",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Usage: "Load configuration from `FILE`",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Will result in help output like:
|
||||||
|
|
||||||
|
```
|
||||||
|
--config FILE, -c FILE Load configuration from FILE
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that only the first placeholder is used. Subsequent back-quoted words will
|
||||||
|
be left as-is.
|
||||||
|
|
||||||
|
#### Alternate Names
|
||||||
|
|
||||||
|
You can set alternate (or short) names for flags by providing a comma-delimited
|
||||||
|
list for the `Name`. e.g.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "--lang value, -l value.*language for the greeting.*default: \"english\""
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "lang",
|
||||||
|
Aliases: []string{"l"},
|
||||||
|
Value: "english",
|
||||||
|
Usage: "language for the greeting",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
That flag can then be set with `--lang spanish` or `-l spanish`. Note that
|
||||||
|
giving two different forms of the same flag in the same command invocation is an
|
||||||
|
error.
|
||||||
|
|
||||||
|
#### Ordering
|
||||||
|
|
||||||
|
Flags for the application and commands are shown in the order they are defined.
|
||||||
|
However, it's possible to sort them from outside this library by using `FlagsByName`
|
||||||
|
or `CommandsByName` with `sort`.
|
||||||
|
|
||||||
|
For example this:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": ".*Load configuration from FILE\n.*\n.*Language for the greeting.*"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "lang",
|
||||||
|
Aliases: []string{"l"},
|
||||||
|
Value: "english",
|
||||||
|
Usage: "Language for the greeting",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "config",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Usage: "Load configuration from `FILE`",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Commands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "complete",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Usage: "complete a task on the list",
|
||||||
|
Action: func(*cli.Context) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "add",
|
||||||
|
Aliases: []string{"a"},
|
||||||
|
Usage: "add a task to the list",
|
||||||
|
Action: func(*cli.Context) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(cli.FlagsByName(app.Flags))
|
||||||
|
sort.Sort(cli.CommandsByName(app.Commands))
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Will result in help output like:
|
||||||
|
|
||||||
|
```
|
||||||
|
--config FILE, -c FILE Load configuration from FILE
|
||||||
|
--lang value, -l value Language for the greeting (default: "english")
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Values from the Environment
|
||||||
|
|
||||||
|
You can also have the default value set from the environment via `EnvVars`. e.g.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "language for the greeting.*APP_LANG"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "lang",
|
||||||
|
Aliases: []string{"l"},
|
||||||
|
Value: "english",
|
||||||
|
Usage: "language for the greeting",
|
||||||
|
EnvVars: []string{"APP_LANG"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If `EnvVars` contains more than one string, the first environment variable that
|
||||||
|
resolves is used.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "language for the greeting.*LEGACY_COMPAT_LANG.*APP_LANG.*LANG"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "lang",
|
||||||
|
Aliases: []string{"l"},
|
||||||
|
Value: "english",
|
||||||
|
Usage: "language for the greeting",
|
||||||
|
EnvVars: []string{"LEGACY_COMPAT_LANG", "APP_LANG", "LANG"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Values from files
|
||||||
|
|
||||||
|
You can also have the default value set from file via `FilePath`. e.g.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "password for the mysql database"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "password",
|
||||||
|
Aliases: []string{"p"},
|
||||||
|
Usage: "password for the mysql database",
|
||||||
|
FilePath: "/etc/mysql/password",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that default values set from file (e.g. `FilePath`) take precedence over
|
||||||
|
default values set from the environment (e.g. `EnvVar`).
|
||||||
|
|
||||||
|
#### Values from alternate input sources (YAML, TOML, and others)
|
||||||
|
|
||||||
|
There is a separate package altsrc that adds support for getting flag values
|
||||||
|
from other file input sources.
|
||||||
|
|
||||||
|
Currently supported input source formats:
|
||||||
|
|
||||||
|
- YAML
|
||||||
|
- JSON
|
||||||
|
- TOML
|
||||||
|
|
||||||
|
In order to get values for a flag from an alternate input source the following
|
||||||
|
code would be added to wrap an existing cli.Flag like below:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// --- >8 ---
|
||||||
|
altsrc.NewIntFlag(&cli.IntFlag{Name: "test"})
|
||||||
|
```
|
||||||
|
|
||||||
|
Initialization must also occur for these flags. Below is an example initializing
|
||||||
|
getting data from a yaml file below.
|
||||||
|
|
||||||
|
```go
|
||||||
|
// --- >8 ---
|
||||||
|
command.Before = altsrc.InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
|
```
|
||||||
|
|
||||||
|
The code above will use the "load" string as a flag name to get the file name of
|
||||||
|
a yaml file from the cli.Context. It will then use that file name to initialize
|
||||||
|
the yaml input source for any flags that are defined on that command. As a note
|
||||||
|
the "load" flag used would also have to be defined on the command flags in order
|
||||||
|
for this code snippet to work.
|
||||||
|
|
||||||
|
Currently only YAML, JSON, and TOML files are supported but developers can add
|
||||||
|
support for other input sources by implementing the altsrc.InputSourceContext
|
||||||
|
for their given sources.
|
||||||
|
|
||||||
|
Here is a more complete sample of a command using YAML support:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "--test value.*default: 0"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
"github.com/urfave/cli/v2/altsrc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flags := []cli.Flag{
|
||||||
|
altsrc.NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||||
|
&cli.StringFlag{Name: "load"},
|
||||||
|
}
|
||||||
|
|
||||||
|
app := &cli.App{
|
||||||
|
Action: func(*cli.Context) error {
|
||||||
|
fmt.Println("--test value.*default: 0")
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Before: altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc("load")),
|
||||||
|
Flags: flags,
|
||||||
|
}
|
||||||
|
|
||||||
|
app.Run(os.Args)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Required Flags
|
||||||
|
|
||||||
|
You can make a flag required by setting the `Required` field to `true`. If a user
|
||||||
|
does not provide a required flag, they will be shown an error message.
|
||||||
|
|
||||||
|
Take for example this app that requires the `lang` flag:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"error": "Required flag \"lang\" not set"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "lang",
|
||||||
|
Value: "english",
|
||||||
|
Usage: "language for the greeting",
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
output := "Hello"
|
||||||
|
if cCtx.String("lang") == "spanish" {
|
||||||
|
output = "Hola"
|
||||||
|
}
|
||||||
|
fmt.Println(output)
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If the app is run without the `lang` flag, the user will see the following message
|
||||||
|
|
||||||
|
```
|
||||||
|
Required flag "lang" not set
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Default Values for help output
|
||||||
|
|
||||||
|
Sometimes it's useful to specify a flag's default help-text value within the
|
||||||
|
flag declaration. This can be useful if the default value for a flag is a
|
||||||
|
computed value. The default value can be set via the `DefaultText` struct field.
|
||||||
|
|
||||||
|
For example this:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "--port value"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.IntFlag{
|
||||||
|
Name: "port",
|
||||||
|
Usage: "Use a randomized port",
|
||||||
|
Value: 0,
|
||||||
|
DefaultText: "random",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Will result in help output like:
|
||||||
|
|
||||||
|
```
|
||||||
|
--port value Use a randomized port (default: random)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Precedence
|
||||||
|
|
||||||
|
The precedence for flag value sources is as follows (highest to lowest):
|
||||||
|
|
||||||
|
0. Command line flag value from user
|
||||||
|
0. Environment variable (if specified)
|
||||||
|
0. Configuration file (if specified)
|
||||||
|
0. Default defined on the flag
|
@ -0,0 +1,101 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v2
|
||||||
|
search:
|
||||||
|
boost: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
The default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked
|
||||||
|
by the cli internals in order to print generated help text for the app, command,
|
||||||
|
or subcommand, and break execution.
|
||||||
|
|
||||||
|
#### Customization
|
||||||
|
|
||||||
|
All of the help text generation may be customized, and at multiple levels. The
|
||||||
|
templates are exposed as variables `AppHelpTemplate`, `CommandHelpTemplate`, and
|
||||||
|
`SubcommandHelpTemplate` which may be reassigned or augmented, and full override
|
||||||
|
is possible by assigning a compatible func to the `cli.HelpPrinter` variable,
|
||||||
|
e.g.:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"output": "Ha HA. I pwnd the help!!1"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// EXAMPLE: Append to an existing template
|
||||||
|
cli.AppHelpTemplate = fmt.Sprintf(`%s
|
||||||
|
|
||||||
|
WEBSITE: http://awesometown.example.com
|
||||||
|
|
||||||
|
SUPPORT: support@awesometown.example.com
|
||||||
|
|
||||||
|
`, cli.AppHelpTemplate)
|
||||||
|
|
||||||
|
// EXAMPLE: Override a template
|
||||||
|
cli.AppHelpTemplate = `NAME:
|
||||||
|
{{.Name}} - {{.Usage}}
|
||||||
|
USAGE:
|
||||||
|
{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
|
||||||
|
{{if len .Authors}}
|
||||||
|
AUTHOR:
|
||||||
|
{{range .Authors}}{{ . }}{{end}}
|
||||||
|
{{end}}{{if .Commands}}
|
||||||
|
COMMANDS:
|
||||||
|
{{range .Commands}}{{if not .HideHelp}} {{join .Names ", "}}{{ "\t"}}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
|
||||||
|
GLOBAL OPTIONS:
|
||||||
|
{{range .VisibleFlags}}{{.}}
|
||||||
|
{{end}}{{end}}{{if .Copyright }}
|
||||||
|
COPYRIGHT:
|
||||||
|
{{.Copyright}}
|
||||||
|
{{end}}{{if .Version}}
|
||||||
|
VERSION:
|
||||||
|
{{.Version}}
|
||||||
|
{{end}}
|
||||||
|
`
|
||||||
|
|
||||||
|
// EXAMPLE: Replace the `HelpPrinter` func
|
||||||
|
cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {
|
||||||
|
fmt.Println("Ha HA. I pwnd the help!!1")
|
||||||
|
}
|
||||||
|
|
||||||
|
(&cli.App{}).Run(os.Args)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The default flag may be customized to something other than `-h/--help` by
|
||||||
|
setting `cli.HelpFlag`, e.g.:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--halp"],
|
||||||
|
"output": "haaaaalp.*HALP"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cli.HelpFlag = &cli.BoolFlag{
|
||||||
|
Name: "haaaaalp",
|
||||||
|
Aliases: []string{"halp"},
|
||||||
|
Usage: "HALP",
|
||||||
|
EnvVars: []string{"SHOW_HALP", "HALPPLZ"},
|
||||||
|
}
|
||||||
|
|
||||||
|
(&cli.App{}).Run(os.Args)
|
||||||
|
}
|
||||||
|
```
|
@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v2
|
||||||
|
search:
|
||||||
|
boost: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
Being a programmer can be a lonely job. Thankfully by the power of automation
|
||||||
|
that is not the case! Let's create a greeter app to fend off our demons of
|
||||||
|
loneliness!
|
||||||
|
|
||||||
|
Start by creating a directory named `greet`, and within it, add a file,
|
||||||
|
`greet.go` with the following code in it:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"output": "Hello friend!"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Name: "greet",
|
||||||
|
Usage: "fight the loneliness!",
|
||||||
|
Action: func(*cli.Context) error {
|
||||||
|
fmt.Println("Hello friend!")
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Install our command to the `$GOPATH/bin` directory:
|
||||||
|
|
||||||
|
```sh-session
|
||||||
|
$ go install
|
||||||
|
```
|
||||||
|
|
||||||
|
Finally run our new command:
|
||||||
|
|
||||||
|
```sh-session
|
||||||
|
$ greet
|
||||||
|
Hello friend!
|
||||||
|
```
|
||||||
|
|
||||||
|
cli also generates neat help text:
|
||||||
|
|
||||||
|
```sh-session
|
||||||
|
$ greet help
|
||||||
|
NAME:
|
||||||
|
greet - fight the loneliness!
|
||||||
|
|
||||||
|
USAGE:
|
||||||
|
greet [global options] command [command options] [arguments...]
|
||||||
|
|
||||||
|
COMMANDS:
|
||||||
|
help, h Shows a list of commands or help for one command
|
||||||
|
|
||||||
|
GLOBAL OPTIONS
|
||||||
|
--help, -h show help (default: false)
|
||||||
|
```
|
@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v2
|
||||||
|
search:
|
||||||
|
boost: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
For additional organization in apps that have many subcommands, you can
|
||||||
|
associate a category for each command to group them together in the help
|
||||||
|
output, e.g.:
|
||||||
|
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Commands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "noop",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "add",
|
||||||
|
Category: "template",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "remove",
|
||||||
|
Category: "template",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Will include:
|
||||||
|
|
||||||
|
```
|
||||||
|
COMMANDS:
|
||||||
|
noop
|
||||||
|
|
||||||
|
Template actions:
|
||||||
|
add
|
||||||
|
remove
|
||||||
|
```
|
@ -0,0 +1,76 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v2
|
||||||
|
search:
|
||||||
|
boost: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
Subcommands can be defined for a more git-like command line app.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["template", "add"],
|
||||||
|
"output": "new task template: .+"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Commands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "add",
|
||||||
|
Aliases: []string{"a"},
|
||||||
|
Usage: "add a task to the list",
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
fmt.Println("added task: ", cCtx.Args().First())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "complete",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Usage: "complete a task on the list",
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
fmt.Println("completed task: ", cCtx.Args().First())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "template",
|
||||||
|
Aliases: []string{"t"},
|
||||||
|
Usage: "options for task templates",
|
||||||
|
Subcommands: []*cli.Command{
|
||||||
|
{
|
||||||
|
Name: "add",
|
||||||
|
Usage: "add a new template",
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
fmt.Println("new task template: ", cCtx.Args().First())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "remove",
|
||||||
|
Usage: "remove an existing template",
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
fmt.Println("removed task template: ", cCtx.Args().First())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v2
|
||||||
|
search:
|
||||||
|
boost: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
To enable flag and command suggestions, set `app.Suggest = true`. If the suggest
|
||||||
|
feature is enabled, then the help output of the corresponding command will
|
||||||
|
provide an appropriate suggestion for the provided flag or subcommand if
|
||||||
|
available.
|
@ -0,0 +1,64 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v2
|
||||||
|
search:
|
||||||
|
boost: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
Using the timestamp flag is simple. Please refer to
|
||||||
|
[`time.Parse`](https://golang.org/pkg/time/#example_Parse) to get possible
|
||||||
|
formats.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--meeting", "2019-08-12T15:04:05"],
|
||||||
|
"output": "2019\\-08\\-12 15\\:04\\:05 \\+0000 UTC"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.TimestampFlag{Name: "meeting", Layout: "2006-01-02T15:04:05"},
|
||||||
|
},
|
||||||
|
Action: func(cCtx *cli.Context) error {
|
||||||
|
fmt.Printf("%s", cCtx.Timestamp("meeting").String())
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example the flag could be used like this:
|
||||||
|
|
||||||
|
```sh-session
|
||||||
|
$ myapp --meeting 2019-08-12T15:04:05
|
||||||
|
```
|
||||||
|
|
||||||
|
When the layout doesn't contain timezones, timestamp will render with UTC. To
|
||||||
|
change behavior, a default timezone can be provided with flag definition:
|
||||||
|
|
||||||
|
```go
|
||||||
|
app := &cli.App{
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.TimestampFlag{Name: "meeting", Layout: "2006-01-02T15:04:05", Timezone: time.Local},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
(time.Local contains the system's local time zone.)
|
||||||
|
|
||||||
|
Side note: quotes may be necessary around the date depending on your layout (if
|
||||||
|
you have spaces for instance)
|
@ -0,0 +1,77 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v2
|
||||||
|
search:
|
||||||
|
boost: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
The default version flag (`-v/--version`) is defined as `cli.VersionFlag`, which
|
||||||
|
is checked by the cli internals in order to print the `App.Version` via
|
||||||
|
`cli.VersionPrinter` and break execution.
|
||||||
|
|
||||||
|
#### Customization
|
||||||
|
|
||||||
|
The default flag may be customized to something other than `-v/--version` by
|
||||||
|
setting `cli.VersionFlag`, e.g.:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--print-version"],
|
||||||
|
"output": "partay version v19\\.99\\.0"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cli.VersionFlag = &cli.BoolFlag{
|
||||||
|
Name: "print-version",
|
||||||
|
Aliases: []string{"V"},
|
||||||
|
Usage: "print only the version",
|
||||||
|
}
|
||||||
|
|
||||||
|
app := &cli.App{
|
||||||
|
Name: "partay",
|
||||||
|
Version: "v19.99.0",
|
||||||
|
}
|
||||||
|
app.Run(os.Args)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, the version printer at `cli.VersionPrinter` may be overridden,
|
||||||
|
e.g.:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--version"],
|
||||||
|
"output": "version=v19\\.99\\.0 revision=fafafaf"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Revision = "fafafaf"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
cli.VersionPrinter = func(cCtx *cli.Context) {
|
||||||
|
fmt.Printf("version=%s revision=%s\n", cCtx.App.Version, Revision)
|
||||||
|
}
|
||||||
|
|
||||||
|
app := &cli.App{
|
||||||
|
Name: "partay",
|
||||||
|
Version: "v19.99.0",
|
||||||
|
}
|
||||||
|
app.Run(os.Args)
|
||||||
|
}
|
||||||
|
```
|
@ -0,0 +1,63 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v2
|
||||||
|
search:
|
||||||
|
boost: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
One of the philosophies behind cli is that an API should be playful and full of
|
||||||
|
discovery. So a cli app can be as little as one line of code in `main()`.
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "A new cli application"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
(&cli.App{}).Run(os.Args)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This app will run and show help text, but is not very useful. Let's give an
|
||||||
|
action to execute and some help documentation:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"output": "boom! I say!"
|
||||||
|
} -->
|
||||||
|
```go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app := &cli.App{
|
||||||
|
Name: "boom",
|
||||||
|
Usage: "make an explosive entrance",
|
||||||
|
Action: func(*cli.Context) error {
|
||||||
|
fmt.Println("boom! I say!")
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Running this already gives you a ton of functionality, plus support for things
|
||||||
|
like subcommands and flags, which are covered below.
|
@ -1 +0,0 @@
|
|||||||
manual.md
|
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
tags:
|
||||||
|
- v2
|
||||||
|
search:
|
||||||
|
boost: 2
|
||||||
|
---
|
||||||
|
|
||||||
|
There are a small set of breaking changes between v1 and v2. Converting is
|
||||||
|
relatively straightforward and typically takes less than an hour. Specific steps
|
||||||
|
are included in [Migration Guide: v1 to v2](../migrate-v1-to-v2.md). Also see
|
||||||
|
the [pkg.go.dev docs](https://pkg.go.dev/github.com/urfave/cli/v2) for v2 API
|
||||||
|
documentation.
|
@ -1,54 +1,116 @@
|
|||||||
# NOTE: this file is used by the tool defined in
|
# NOTE: this file is used by the tool defined in
|
||||||
# ./internal/genflags/cmd/genflags/main.go which uses the
|
# ./cmd/urfave-cli-genflags/main.go which uses the
|
||||||
# `genflags.Spec` type that maps to this file structure.
|
# `Spec` type that maps to this file structure.
|
||||||
|
|
||||||
flag_types:
|
flag_types:
|
||||||
bool:
|
bool:
|
||||||
no_default_text: true
|
no_default_text: true
|
||||||
float64: {}
|
|
||||||
int64: {}
|
|
||||||
int: {}
|
|
||||||
time.Duration: {}
|
|
||||||
uint64: {}
|
|
||||||
uint: {}
|
|
||||||
|
|
||||||
string:
|
|
||||||
no_default_text: true
|
|
||||||
struct_fields:
|
|
||||||
- { name: TakesFile, type: bool }
|
|
||||||
Generic:
|
|
||||||
struct_fields:
|
struct_fields:
|
||||||
- { name: TakesFile, type: bool }
|
- name: Count
|
||||||
Path:
|
type: int
|
||||||
no_default_text: true
|
pointer: true
|
||||||
|
- name: Action
|
||||||
|
type: "func(*Context, bool) error"
|
||||||
|
float64:
|
||||||
struct_fields:
|
struct_fields:
|
||||||
- { name: TakesFile, type: bool }
|
- name: Action
|
||||||
|
type: "func(*Context, float64) error"
|
||||||
Float64Slice:
|
Float64Slice:
|
||||||
value_pointer: true
|
value_pointer: true
|
||||||
skip_interfaces:
|
skip_interfaces:
|
||||||
- fmt.Stringer
|
- fmt.Stringer
|
||||||
|
struct_fields:
|
||||||
|
- name: Action
|
||||||
|
type: "func(*Context, []float64) error"
|
||||||
|
int:
|
||||||
|
struct_fields:
|
||||||
|
- name: Base
|
||||||
|
type: int
|
||||||
|
- name: Action
|
||||||
|
type: "func(*Context, int) error"
|
||||||
|
IntSlice:
|
||||||
|
value_pointer: true
|
||||||
|
skip_interfaces:
|
||||||
|
- fmt.Stringer
|
||||||
|
struct_fields:
|
||||||
|
- name: Action
|
||||||
|
type: "func(*Context, []int) error"
|
||||||
|
int64:
|
||||||
|
struct_fields:
|
||||||
|
- name: Base
|
||||||
|
type: int
|
||||||
|
- name: Action
|
||||||
|
type: "func(*Context, int64) error"
|
||||||
Int64Slice:
|
Int64Slice:
|
||||||
value_pointer: true
|
value_pointer: true
|
||||||
skip_interfaces:
|
skip_interfaces:
|
||||||
- fmt.Stringer
|
- fmt.Stringer
|
||||||
IntSlice:
|
struct_fields:
|
||||||
|
- name: Action
|
||||||
|
type: "func(*Context, []int64) error"
|
||||||
|
uint:
|
||||||
|
struct_fields:
|
||||||
|
- name: Base
|
||||||
|
type: int
|
||||||
|
- name: Action
|
||||||
|
type: "func(*Context, uint) error"
|
||||||
|
UintSlice:
|
||||||
|
value_pointer: true
|
||||||
|
skip_interfaces:
|
||||||
|
- fmt.Stringer
|
||||||
|
struct_fields:
|
||||||
|
- name: Action
|
||||||
|
type: "func(*Context, []uint) error"
|
||||||
|
uint64:
|
||||||
|
struct_fields:
|
||||||
|
- name: Base
|
||||||
|
type: int
|
||||||
|
- name: Action
|
||||||
|
type: "func(*Context, uint64) error"
|
||||||
|
Uint64Slice:
|
||||||
value_pointer: true
|
value_pointer: true
|
||||||
skip_interfaces:
|
skip_interfaces:
|
||||||
- fmt.Stringer
|
- fmt.Stringer
|
||||||
|
struct_fields:
|
||||||
|
- name: Action
|
||||||
|
type: "func(*Context, []uint64) error"
|
||||||
|
string:
|
||||||
|
struct_fields:
|
||||||
|
- name: TakesFile
|
||||||
|
type: bool
|
||||||
|
- name: Action
|
||||||
|
type: "func(*Context, string) error"
|
||||||
StringSlice:
|
StringSlice:
|
||||||
value_pointer: true
|
value_pointer: true
|
||||||
skip_interfaces:
|
skip_interfaces:
|
||||||
- fmt.Stringer
|
- fmt.Stringer
|
||||||
struct_fields:
|
struct_fields:
|
||||||
- { name: TakesFile, type: bool }
|
- name: TakesFile
|
||||||
|
type: bool
|
||||||
|
- name: Action
|
||||||
|
type: "func(*Context, []string) error"
|
||||||
|
time.Duration:
|
||||||
|
struct_fields:
|
||||||
|
- name: Action
|
||||||
|
type: "func(*Context, time.Duration) error"
|
||||||
Timestamp:
|
Timestamp:
|
||||||
value_pointer: true
|
value_pointer: true
|
||||||
struct_fields:
|
struct_fields:
|
||||||
- { name: Layout, type: string }
|
- name: Layout
|
||||||
- { name: Timezone, type: "*time.Location" }
|
type: string
|
||||||
|
- name: Timezone
|
||||||
# TODO: enable UintSlice
|
type: "*time.Location"
|
||||||
# UintSlice: {}
|
- name: Action
|
||||||
# TODO: enable Uint64Slice once #1334 lands
|
type: "func(*Context, *time.Time) error"
|
||||||
# Uint64Slice: {}
|
Generic:
|
||||||
|
no_destination_pointer: true
|
||||||
|
struct_fields:
|
||||||
|
- name: TakesFile
|
||||||
|
type: bool
|
||||||
|
- name: Action
|
||||||
|
type: "func(*Context, interface{}) error"
|
||||||
|
Path:
|
||||||
|
struct_fields:
|
||||||
|
- name: TakesFile
|
||||||
|
type: bool
|
||||||
|
- name: Action
|
||||||
|
type: "func(*Context, Path) error"
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
package genflags
|
|
||||||
|
|
||||||
import (
|
|
||||||
_ "embed"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/text/cases"
|
|
||||||
"golang.org/x/text/language"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
//go:embed generated.gotmpl
|
|
||||||
TemplateString string
|
|
||||||
|
|
||||||
//go:embed generated_test.gotmpl
|
|
||||||
TestTemplateString string
|
|
||||||
|
|
||||||
titler = cases.Title(language.Und, cases.NoLower)
|
|
||||||
)
|
|
||||||
|
|
||||||
func TypeName(goType string, fc *FlagTypeConfig) string {
|
|
||||||
if fc != nil && strings.TrimSpace(fc.TypeName) != "" {
|
|
||||||
return strings.TrimSpace(fc.TypeName)
|
|
||||||
}
|
|
||||||
|
|
||||||
dotSplit := strings.Split(goType, ".")
|
|
||||||
goType = dotSplit[len(dotSplit)-1]
|
|
||||||
|
|
||||||
if strings.HasPrefix(goType, "[]") {
|
|
||||||
return titler.String(strings.TrimPrefix(goType, "[]")) + "SliceFlag"
|
|
||||||
}
|
|
||||||
|
|
||||||
return titler.String(goType) + "Flag"
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
package genflags_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/urfave/cli/v3/internal/genflags"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestTypeName(t *testing.T) {
|
|
||||||
for _, tc := range []struct {
|
|
||||||
gt string
|
|
||||||
fc *genflags.FlagTypeConfig
|
|
||||||
expected string
|
|
||||||
}{
|
|
||||||
{gt: "int", fc: nil, expected: "IntFlag"},
|
|
||||||
{gt: "int", fc: &genflags.FlagTypeConfig{}, expected: "IntFlag"},
|
|
||||||
{gt: "int", fc: &genflags.FlagTypeConfig{TypeName: "VeryIntyFlag"}, expected: "VeryIntyFlag"},
|
|
||||||
{gt: "[]bool", fc: nil, expected: "BoolSliceFlag"},
|
|
||||||
{gt: "[]bool", fc: &genflags.FlagTypeConfig{}, expected: "BoolSliceFlag"},
|
|
||||||
{gt: "[]bool", fc: &genflags.FlagTypeConfig{TypeName: "ManyTruthsFlag"}, expected: "ManyTruthsFlag"},
|
|
||||||
{gt: "time.Rumination", fc: nil, expected: "RuminationFlag"},
|
|
||||||
{gt: "time.Rumination", fc: &genflags.FlagTypeConfig{}, expected: "RuminationFlag"},
|
|
||||||
{gt: "time.Rumination", fc: &genflags.FlagTypeConfig{TypeName: "PonderFlag"}, expected: "PonderFlag"},
|
|
||||||
} {
|
|
||||||
t.Run(
|
|
||||||
fmt.Sprintf("type=%s,cfg=%v", tc.gt, func() string {
|
|
||||||
if tc.fc != nil {
|
|
||||||
return tc.fc.TypeName
|
|
||||||
}
|
|
||||||
return "nil"
|
|
||||||
}()),
|
|
||||||
func(ct *testing.T) {
|
|
||||||
actual := genflags.TypeName(tc.gt, tc.fc)
|
|
||||||
if tc.expected != actual {
|
|
||||||
ct.Errorf("expected %q, got %q", tc.expected, actual)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
package genflags
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Spec struct {
|
|
||||||
FlagTypes map[string]*FlagTypeConfig `yaml:"flag_types"`
|
|
||||||
PackageName string `yaml:"package_name"`
|
|
||||||
TestPackageName string `yaml:"test_package_name"`
|
|
||||||
UrfaveCLINamespace string `yaml:"urfave_cli_namespace"`
|
|
||||||
UrfaveCLITestNamespace string `yaml:"urfave_cli_test_namespace"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (gfs *Spec) SortedFlagTypes() []*FlagType {
|
|
||||||
typeNames := []string{}
|
|
||||||
|
|
||||||
for name := range gfs.FlagTypes {
|
|
||||||
if strings.HasPrefix(name, "[]") {
|
|
||||||
name = strings.TrimPrefix(name, "[]") + "Slice"
|
|
||||||
}
|
|
||||||
|
|
||||||
typeNames = append(typeNames, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Strings(typeNames)
|
|
||||||
|
|
||||||
ret := make([]*FlagType, len(typeNames))
|
|
||||||
|
|
||||||
for i, typeName := range typeNames {
|
|
||||||
ret[i] = &FlagType{
|
|
||||||
GoType: typeName,
|
|
||||||
Config: gfs.FlagTypes[typeName],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
type FlagTypeConfig struct {
|
|
||||||
SkipInterfaces []string `yaml:"skip_interfaces"`
|
|
||||||
StructFields []*FlagStructField `yaml:"struct_fields"`
|
|
||||||
TypeName string `yaml:"type_name"`
|
|
||||||
ValuePointer bool `yaml:"value_pointer"`
|
|
||||||
NoDefaultText bool `yaml:"no_default_text"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type FlagStructField struct {
|
|
||||||
Name string
|
|
||||||
Type string
|
|
||||||
}
|
|
||||||
|
|
||||||
type FlagType struct {
|
|
||||||
GoType string
|
|
||||||
Config *FlagTypeConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ft *FlagType) StructFields() []*FlagStructField {
|
|
||||||
if ft.Config == nil || ft.Config.StructFields == nil {
|
|
||||||
return []*FlagStructField{}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ft.Config.StructFields
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ft *FlagType) ValuePointer() bool {
|
|
||||||
if ft.Config == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return ft.Config.ValuePointer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ft *FlagType) TypeName() string {
|
|
||||||
return TypeName(ft.GoType, ft.Config)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ft *FlagType) GenerateFmtStringerInterface() bool {
|
|
||||||
return ft.skipInterfaceNamed("fmt.Stringer")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ft *FlagType) GenerateFlagInterface() bool {
|
|
||||||
return ft.skipInterfaceNamed("Flag")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ft *FlagType) GenerateDefaultText() bool {
|
|
||||||
return !ft.Config.NoDefaultText
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ft *FlagType) skipInterfaceNamed(name string) bool {
|
|
||||||
if ft.Config == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
lowName := strings.ToLower(name)
|
|
||||||
|
|
||||||
for _, interfaceName := range ft.Config.SkipInterfaces {
|
|
||||||
if strings.ToLower(interfaceName) == lowName {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
Loading…
Reference in new issue