Merge pull request #1421 from urfave/docs-cleanups

Clean up the v2 manual a bit
This commit is contained in:
Dan Buch 2022-06-22 07:56:12 -04:00 committed by GitHub
commit 7d21dda232
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -44,14 +44,13 @@ func main() {
app := &cli.App{
Name: "boom",
Usage: "make an explosive entrance",
Action: func(c *cli.Context) error {
Action: func(*cli.Context) error {
fmt.Println("boom! I say!")
return nil
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -87,14 +86,13 @@ func main() {
app := &cli.App{
Name: "greet",
Usage: "fight the loneliness!",
Action: func(c *cli.Context) error {
Action: func(*cli.Context) error {
fmt.Println("Hello friend!")
return nil
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -102,20 +100,20 @@ func main() {
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!
@ -150,14 +148,13 @@ import (
func main() {
app := &cli.App{
Action: func(c *cli.Context) error {
fmt.Printf("Hello %q", c.Args().Get(0))
Action: func(cCtx *cli.Context) error {
fmt.Printf("Hello %q", cCtx.Args().Get(0))
return nil
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -190,12 +187,12 @@ func main() {
Usage: "language for the greeting",
},
},
Action: func(c *cli.Context) error {
Action: func(cCtx *cli.Context) error {
name := "Nefertiti"
if c.NArg() > 0 {
name = c.Args().Get(0)
if cCtx.NArg() > 0 {
name = cCtx.Args().Get(0)
}
if c.String("lang") == "spanish" {
if cCtx.String("lang") == "spanish" {
fmt.Println("Hola", name)
} else {
fmt.Println("Hello", name)
@ -204,8 +201,7 @@ func main() {
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -221,9 +217,9 @@ scanned.
package main
import (
"fmt"
"log"
"os"
"fmt"
"github.com/urfave/cli/v2"
)
@ -240,10 +236,10 @@ func main() {
Destination: &language,
},
},
Action: func(c *cli.Context) error {
Action: func(cCtx *cli.Context) error {
name := "someone"
if c.NArg() > 0 {
name = c.Args().Get(0)
if cCtx.NArg() > 0 {
name = cCtx.Args().Get(0)
}
if language == "spanish" {
fmt.Println("Hola", name)
@ -254,8 +250,7 @@ func main() {
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -295,8 +290,7 @@ func main() {
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -342,8 +336,7 @@ func main() {
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -396,7 +389,7 @@ func main() {
Name: "complete",
Aliases: []string{"c"},
Usage: "complete a task on the list",
Action: func(c *cli.Context) error {
Action: func(*cli.Context) error {
return nil
},
},
@ -404,7 +397,7 @@ func main() {
Name: "add",
Aliases: []string{"a"},
Usage: "add a task to the list",
Action: func(c *cli.Context) error {
Action: func(*cli.Context) error {
return nil
},
},
@ -414,8 +407,7 @@ func main() {
sort.Sort(cli.FlagsByName(app.Flags))
sort.Sort(cli.CommandsByName(app.Commands))
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -459,8 +451,7 @@ func main() {
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -496,8 +487,7 @@ func main() {
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -522,19 +512,18 @@ import (
)
func main() {
app := cli.NewApp()
app.Flags = []cli.Flag {
app := &cli.App{
Flags: []cli.Flag{
&cli.StringFlag{
Name: "password",
Aliases: []string{"p"},
Usage: "password for the mysql database",
FilePath: "/etc/mysql/password",
},
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -549,14 +538,16 @@ 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
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"})
```
@ -564,6 +555,7 @@ 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"))
```
@ -573,9 +565,9 @@ 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.
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:
@ -601,7 +593,7 @@ func main() {
}
app := &cli.App{
Action: func(c *cli.Context) error {
Action: func(*cli.Context) error {
fmt.Println("--test value.*default: 0")
return nil
},
@ -635,30 +627,26 @@ import (
)
func main() {
app := cli.NewApp()
app.Flags = []cli.Flag {
app := &cli.App{
Flags: []cli.Flag{
&cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
Required: true,
},
}
app.Action = func(c *cli.Context) error {
var output string
if c.String("lang") == "spanish" {
},
Action: func(cCtx *cli.Context) error {
output := "Hello"
if cCtx.String("lang") == "spanish" {
output = "Hola"
} else {
output = "Hello"
}
fmt.Println(output)
return nil
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -672,7 +660,9 @@ 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.
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:
@ -702,8 +692,7 @@ func main() {
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -750,8 +739,8 @@ func main() {
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())
Action: func(cCtx *cli.Context) error {
fmt.Println("added task: ", cCtx.Args().First())
return nil
},
},
@ -759,8 +748,8 @@ func main() {
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())
Action: func(cCtx *cli.Context) error {
fmt.Println("completed task: ", cCtx.Args().First())
return nil
},
},
@ -772,16 +761,16 @@ func main() {
{
Name: "add",
Usage: "add a new template",
Action: func(c *cli.Context) error {
fmt.Println("new task template: ", c.Args().First())
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(c *cli.Context) error {
fmt.Println("removed task template: ", c.Args().First())
Action: func(cCtx *cli.Context) error {
fmt.Println("removed task template: ", cCtx.Args().First())
return nil
},
},
@ -790,8 +779,7 @@ func main() {
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -801,9 +789,7 @@ func main() {
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.
output, e.g.:
```go
package main
@ -832,8 +818,7 @@ func main() {
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -885,8 +870,7 @@ func main() {
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -896,7 +880,7 @@ func main() {
Traditional use of options using their shortnames look like this:
```
```sh-session
$ cmd -s -o -m "Some message"
```
@ -921,9 +905,9 @@ import (
)
func main() {
app := &cli.App{}
app.UseShortOptionHandling = true
app.Commands = []*cli.Command{
app := &cli.App{
UseShortOptionHandling: true,
Commands: []*cli.Command{
{
Name: "short",
Usage: "complete a task on the list",
@ -932,17 +916,17 @@ func main() {
&cli.BoolFlag{Name: "option", Aliases: []string{"o"}},
&cli.StringFlag{Name: "message", Aliases: []string{"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"))
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
},
},
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -953,7 +937,7 @@ 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"
```
@ -964,31 +948,34 @@ have a single leading `-` or this will result in failures. For example,
### Bash Completion
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.
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.NewApp()
app.EnableBashCompletion = true
app.Commands = []*cli.Command{
app := &cli.App{
EnableBashCompletion: true,
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())
Action: func(cCtx *cli.Context) error {
fmt.Println("added task: ", cCtx.Args().First())
return nil
},
},
@ -996,8 +983,8 @@ func main() {
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())
Action: func(cCtx *cli.Context) error {
fmt.Println("completed task: ", cCtx.Args().First())
return nil
},
},
@ -1009,24 +996,25 @@ func main() {
{
Name: "add",
Usage: "add a new template",
Action: func(c *cli.Context) error {
fmt.Println("new task template: ", c.Args().First())
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(c *cli.Context) error {
fmt.Println("removed task template: ", c.Args().First())
Action: func(cCtx *cli.Context) error {
fmt.Println("removed task template: ", cCtx.Args().First())
return nil
},
},
},
},
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -1059,13 +1047,13 @@ func main() {
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())
Action: func(cCtx *cli.Context) error {
fmt.Println("completed task: ", cCtx.Args().First())
return nil
},
BashComplete: func(c *cli.Context) {
BashComplete: func(cCtx *cli.Context) {
// This will complete if no args are passed
if c.NArg() > 0 {
if cCtx.NArg() > 0 {
return
}
for _, t := range tasks {
@ -1076,8 +1064,7 @@ func main() {
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -1089,14 +1076,18 @@ func main() {
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.
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`:
`PROG=myprogram source path/to/cli/autocomplete/bash_autocomplete`
```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.
Auto-completion is now enabled for the current shell, but will not persist into
a new shell.
#### Distribution and Persistent Autocompletion
@ -1105,28 +1096,30 @@ 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.
```
sudo cp path/to/autocomplete/bash_autocomplete /etc/bash_completion.d/<myprogram>
source /etc/bash_completion.d/<myprogram>
```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
```
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:
```
PROG=<program1>
source path/to/cli/autocomplete/bash_autocomplete
PROG=<program2>
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
@ -1157,45 +1150,54 @@ func main() {
},
},
}
err := app.Run(os.Args)
if err != nil {
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:
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
```
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.
Auto-completion for PowerShell is also supported using the
`autocomplete/powershell_autocomplete.ps1` file included in this repo.
To activate it, enter `& path/to/autocomplete/<my program>.ps1`
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 persist across new shells, open the PowerShell profile (with `code $profile` or `notepad $profile`)
and add the line:
```
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
```
### Generated Help Text
@ -1333,7 +1335,8 @@ func main() {
}
```
Alternatively, the version printer at `cli.VersionPrinter` may be overridden, e.g.:
Alternatively, the version printer at `cli.VersionPrinter` may be overridden,
e.g.:
<!-- {
"args": ["&#45;&#45version"],
@ -1354,8 +1357,8 @@ var (
)
func main() {
cli.VersionPrinter = func(c *cli.Context) {
fmt.Printf("version=%s revision=%s\n", c.App.Version, Revision)
cli.VersionPrinter = func(cCtx *cli.Context) {
fmt.Printf("version=%s revision=%s\n", cCtx.App.Version, Revision)
}
app := &cli.App{
@ -1368,7 +1371,9 @@ func main() {
### Timestamp Flag
Using the timestamp flag is simple. Please refer to [`time.Parse`](https://golang.org/pkg/time/#example_Parse) to get possible formats.
Using the timestamp flag is simple. Please refer to
[`time.Parse`](https://golang.org/pkg/time/#example_Parse) to get possible
formats.
<!-- {
"args": ["&#45;&#45;meeting", "2019-08-12T15:04:05"],
@ -1390,14 +1395,13 @@ func main() {
Flags: []cli.Flag{
&cli.TimestampFlag{Name: "meeting", Layout: "2006-01-02T15:04:05"},
},
Action: func(c *cli.Context) error {
fmt.Printf("%s", c.Timestamp("meeting").String())
Action: func(cCtx *cli.Context) error {
fmt.Printf("%s", cCtx.Timestamp("meeting").String())
return nil
},
}
err := app.Run(os.Args)
if err != nil {
if err := app.Run(os.Args); err != nil {
log.Fatal(err)
}
}
@ -1405,9 +1409,12 @@ func main() {
In this example the flag could be used like this:
`myapp --meeting 2019-08-12T15:04:05`
```sh-session
$ myapp --meeting 2019-08-12T15:04:05
```
Side note: quotes may be necessary around the date depending on your layout (if you have spaces for instance)
Side note: quotes may be necessary around the date depending on your layout (if
you have spaces for instance)
### Suggestions
@ -1450,11 +1457,11 @@ func init() {
cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {
fmt.Fprintf(w, "best of luck to you\n")
}
cli.VersionPrinter = func(c *cli.Context) {
fmt.Fprintf(c.App.Writer, "version=%s\n", c.App.Version)
cli.VersionPrinter = func(cCtx *cli.Context) {
fmt.Fprintf(cCtx.App.Writer, "version=%s\n", cCtx.App.Version)
}
cli.OsExiter = func(c int) {
fmt.Fprintf(cli.ErrWriter, "refusing to exit %d\n", c)
cli.OsExiter = func(cCtx int) {
fmt.Fprintf(cli.ErrWriter, "refusing to exit %d\n", cCtx)
}
cli.ErrWriter = ioutil.Discard
cli.FlagStringer = func(fl cli.Flag) string {
@ -1524,30 +1531,30 @@ func main() {
HideHelp: false,
Hidden: false,
HelpName: "doo!",
BashComplete: func(c *cli.Context) {
fmt.Fprintf(c.App.Writer, "--better\n")
BashComplete: func(cCtx *cli.Context) {
fmt.Fprintf(cCtx.App.Writer, "--better\n")
},
Before: func(c *cli.Context) error {
fmt.Fprintf(c.App.Writer, "brace for impact\n")
Before: func(cCtx *cli.Context) error {
fmt.Fprintf(cCtx.App.Writer, "brace for impact\n")
return nil
},
After: func(c *cli.Context) error {
fmt.Fprintf(c.App.Writer, "did we lose anyone?\n")
After: func(cCtx *cli.Context) error {
fmt.Fprintf(cCtx.App.Writer, "did we lose anyone?\n")
return nil
},
Action: func(c *cli.Context) error {
c.Command.FullName()
c.Command.HasName("wop")
c.Command.Names()
c.Command.VisibleFlags()
fmt.Fprintf(c.App.Writer, "dodododododoodododddooooododododooo\n")
if c.Bool("forever") {
c.Command.Run(c)
Action: func(cCtx *cli.Context) error {
cCtx.Command.FullName()
cCtx.Command.HasName("wop")
cCtx.Command.Names()
cCtx.Command.VisibleFlags()
fmt.Fprintf(cCtx.App.Writer, "dodododododoodododddooooododododooo\n")
if cCtx.Bool("forever") {
cCtx.Command.Run(cCtx)
}
return nil
},
OnUsageError: func(c *cli.Context, err error, isSubcommand bool) error {
fmt.Fprintf(c.App.Writer, "for shame\n")
OnUsageError: func(cCtx *cli.Context, err error, isSubcommand bool) error {
fmt.Fprintf(cCtx.App.Writer, "for shame\n")
return err
},
},
@ -1570,60 +1577,60 @@ func main() {
EnableBashCompletion: true,
HideHelp: false,
HideVersion: false,
BashComplete: func(c *cli.Context) {
fmt.Fprintf(c.App.Writer, "lipstick\nkiss\nme\nlipstick\nringo\n")
BashComplete: func(cCtx *cli.Context) {
fmt.Fprintf(cCtx.App.Writer, "lipstick\nkiss\nme\nlipstick\nringo\n")
},
Before: func(c *cli.Context) error {
fmt.Fprintf(c.App.Writer, "HEEEERE GOES\n")
Before: func(cCtx *cli.Context) error {
fmt.Fprintf(cCtx.App.Writer, "HEEEERE GOES\n")
return nil
},
After: func(c *cli.Context) error {
fmt.Fprintf(c.App.Writer, "Phew!\n")
After: func(cCtx *cli.Context) error {
fmt.Fprintf(cCtx.App.Writer, "Phew!\n")
return nil
},
CommandNotFound: func(c *cli.Context, command string) {
fmt.Fprintf(c.App.Writer, "Thar be no %q here.\n", command)
CommandNotFound: func(cCtx *cli.Context, command string) {
fmt.Fprintf(cCtx.App.Writer, "Thar be no %q here.\n", command)
},
OnUsageError: func(c *cli.Context, err error, isSubcommand bool) error {
OnUsageError: func(cCtx *cli.Context, err error, isSubcommand bool) error {
if isSubcommand {
return err
}
fmt.Fprintf(c.App.Writer, "WRONG: %#v\n", err)
fmt.Fprintf(cCtx.App.Writer, "WRONG: %#v\n", err)
return nil
},
Action: func(c *cli.Context) error {
cli.DefaultAppComplete(c)
Action: func(cCtx *cli.Context) error {
cli.DefaultAppComplete(cCtx)
cli.HandleExitCoder(errors.New("not an exit coder, though"))
cli.ShowAppHelp(c)
cli.ShowCommandCompletions(c, "nope")
cli.ShowCommandHelp(c, "also-nope")
cli.ShowCompletions(c)
cli.ShowSubcommandHelp(c)
cli.ShowVersion(c)
cli.ShowAppHelp(cCtx)
cli.ShowCommandCompletions(cCtx, "nope")
cli.ShowCommandHelp(cCtx, "also-nope")
cli.ShowCompletions(cCtx)
cli.ShowSubcommandHelp(cCtx)
cli.ShowVersion(cCtx)
fmt.Printf("%#v\n", c.App.Command("doo"))
if c.Bool("infinite") {
c.App.Run([]string{"app", "doo", "wop"})
fmt.Printf("%#v\n", cCtx.App.Command("doo"))
if cCtx.Bool("infinite") {
cCtx.App.Run([]string{"app", "doo", "wop"})
}
if c.Bool("forevar") {
c.App.RunAsSubcommand(c)
if cCtx.Bool("forevar") {
cCtx.App.RunAsSubcommand(cCtx)
}
c.App.Setup()
fmt.Printf("%#v\n", c.App.VisibleCategories())
fmt.Printf("%#v\n", c.App.VisibleCommands())
fmt.Printf("%#v\n", c.App.VisibleFlags())
cCtx.App.Setup()
fmt.Printf("%#v\n", cCtx.App.VisibleCategories())
fmt.Printf("%#v\n", cCtx.App.VisibleCommands())
fmt.Printf("%#v\n", cCtx.App.VisibleFlags())
fmt.Printf("%#v\n", c.Args().First())
if c.Args().Len() > 0 {
fmt.Printf("%#v\n", c.Args().Get(1))
fmt.Printf("%#v\n", cCtx.Args().First())
if cCtx.Args().Len() > 0 {
fmt.Printf("%#v\n", cCtx.Args().Get(1))
}
fmt.Printf("%#v\n", c.Args().Present())
fmt.Printf("%#v\n", c.Args().Tail())
fmt.Printf("%#v\n", cCtx.Args().Present())
fmt.Printf("%#v\n", cCtx.Args().Tail())
set := flag.NewFlagSet("contrive", 0)
nc := cli.NewContext(c.App, set, c)
nc := cli.NewContext(cCtx.App, set, cCtx)
fmt.Printf("%#v\n", nc.Args())
fmt.Printf("%#v\n", nc.Bool("nope"))
@ -1649,7 +1656,7 @@ func main() {
nc.Set("wat", "also-nope")
ec := cli.Exit("ohwell", 86)
fmt.Fprintf(c.App.Writer, "%d", ec.ExitCode())
fmt.Fprintf(cCtx.App.Writer, "%d", ec.ExitCode())
fmt.Printf("made it!\n")
return ec
},
@ -1668,16 +1675,16 @@ func main() {
app.Run(os.Args)
}
func wopAction(c *cli.Context) error {
fmt.Fprintf(c.App.Writer, ":wave: over here, eh\n")
func wopAction(cCtx *cli.Context) error {
fmt.Fprintf(cCtx.App.Writer, ":wave: over here, eh\n")
return nil
}
```
## Migrating From Older Releases
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.
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.