Merge remote-tracking branch 'origin/master' into v2-merge
This commit is contained in:
commit
83497d2cda
@ -12,6 +12,7 @@ go:
|
|||||||
- 1.4.2
|
- 1.4.2
|
||||||
- 1.5.x
|
- 1.5.x
|
||||||
- 1.6.x
|
- 1.6.x
|
||||||
|
- 1.7.x
|
||||||
- master
|
- master
|
||||||
|
|
||||||
env: pip_install="pip install --user"
|
env: pip_install="pip install --user"
|
||||||
@ -23,6 +24,9 @@ matrix:
|
|||||||
- go: 1.6.x
|
- go: 1.6.x
|
||||||
os: osx
|
os: osx
|
||||||
env: pip_install="sudo pip install"
|
env: pip_install="sudo pip install"
|
||||||
|
- go: 1.7.x
|
||||||
|
os: osx
|
||||||
|
env: pip_install="sudo pip install"
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- $pip_install flake8
|
- $pip_install flake8
|
||||||
|
61
README.md
61
README.md
@ -23,13 +23,14 @@ applications in an expressive way.
|
|||||||
- [Installation](#installation)
|
- [Installation](#installation)
|
||||||
* [Supported platforms](#supported-platforms)
|
* [Supported platforms](#supported-platforms)
|
||||||
* [Using the `v2` branch](#using-the-v2-branch)
|
* [Using the `v2` branch](#using-the-v2-branch)
|
||||||
* [Pinning to the `v1` branch](#pinning-to-the-v1-branch)
|
* [Pinning to the `v1` releases](#pinning-to-the-v1-releases)
|
||||||
- [Getting Started](#getting-started)
|
- [Getting Started](#getting-started)
|
||||||
- [Examples](#examples)
|
- [Examples](#examples)
|
||||||
* [Arguments](#arguments)
|
* [Arguments](#arguments)
|
||||||
* [Flags](#flags)
|
* [Flags](#flags)
|
||||||
+ [Placeholder Values](#placeholder-values)
|
+ [Placeholder Values](#placeholder-values)
|
||||||
+ [Alternate Names](#alternate-names)
|
+ [Alternate Names](#alternate-names)
|
||||||
|
+ [Ordering](#ordering)
|
||||||
+ [Values from the Environment](#values-from-the-environment)
|
+ [Values from the Environment](#values-from-the-environment)
|
||||||
+ [Values from alternate input sources (YAML, TOML, and others)](#values-from-alternate-input-sources-yaml-toml-and-others)
|
+ [Values from alternate input sources (YAML, TOML, and others)](#values-from-alternate-input-sources-yaml-toml-and-others)
|
||||||
+ [Default Values for help output](#default-values-for-help-output)
|
+ [Default Values for help output](#default-values-for-help-output)
|
||||||
@ -108,11 +109,11 @@ import (
|
|||||||
**NOTE**: There is a [migrator (python) script](./cli-v1-to-v2) available to aid
|
**NOTE**: There is a [migrator (python) script](./cli-v1-to-v2) available to aid
|
||||||
with the transition from the v1 to v2 API.
|
with the transition from the v1 to v2 API.
|
||||||
|
|
||||||
### Pinning to the `v1` branch
|
### Pinning to the `v1` releases
|
||||||
|
|
||||||
Similarly to the section above describing use of the `v2` branch, if one wants
|
Similarly to the section above describing use of the `v2` branch, if one wants
|
||||||
to avoid any unexpected compatibility pains once `v2` becomes `master`, then
|
to avoid any unexpected compatibility pains once `v2` becomes `master`, then
|
||||||
pinning to the `v1` branch is an acceptable option, e.g.:
|
pinning to `v1` is an acceptable option, e.g.:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ go get gopkg.in/urfave/cli.v1
|
$ go get gopkg.in/urfave/cli.v1
|
||||||
@ -126,6 +127,8 @@ import (
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This will pull the latest tagged `v1` release (e.g. `v1.18.1` at the time of writing).
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
One of the philosophies behind cli is that an API should be playful and full of
|
One of the philosophies behind cli is that an API should be playful and full of
|
||||||
@ -454,6 +457,56 @@ 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
|
giving two different forms of the same flag in the same command invocation is an
|
||||||
error.
|
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`
|
||||||
|
with `sort`.
|
||||||
|
|
||||||
|
For example this:
|
||||||
|
|
||||||
|
<!-- {
|
||||||
|
"args": ["--help"],
|
||||||
|
"output": "Load configuration from FILE\n.*Language for the greeting.*"
|
||||||
|
} -->
|
||||||
|
``` go
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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`",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Sort(cli.FlagsByName(app.Flags))
|
||||||
|
|
||||||
|
app.Run(os.Args)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
#### Values from the Environment
|
||||||
|
|
||||||
You can also have the default value set from the environment via `EnvVars`. e.g.
|
You can also have the default value set from the environment via `EnvVars`. e.g.
|
||||||
@ -1013,7 +1066,7 @@ is checked by the cli internals in order to print the `App.Version` via
|
|||||||
|
|
||||||
#### Customization
|
#### Customization
|
||||||
|
|
||||||
The default flag may be cusomized to something other than `-v/--version` by
|
The default flag may be customized to something other than `-v/--version` by
|
||||||
setting `cli.VersionFlag`, e.g.:
|
setting `cli.VersionFlag`, e.g.:
|
||||||
|
|
||||||
<!-- {
|
<!-- {
|
||||||
|
12
app.go
12
app.go
@ -25,6 +25,8 @@ type App struct {
|
|||||||
ArgsUsage string
|
ArgsUsage string
|
||||||
// Version of the program
|
// Version of the program
|
||||||
Version string
|
Version string
|
||||||
|
// Description of the program
|
||||||
|
Description string
|
||||||
// List of commands to execute
|
// List of commands to execute
|
||||||
Commands []*Command
|
Commands []*Command
|
||||||
// List of flags to parse
|
// List of flags to parse
|
||||||
@ -191,7 +193,7 @@ func (a *App) Run(arguments []string) (err error) {
|
|||||||
HandleExitCoder(err)
|
HandleExitCoder(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(a.Writer, "Incorrect Usage: %s\n\n", err)
|
fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
|
||||||
ShowAppHelp(context)
|
ShowAppHelp(context)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -248,6 +250,8 @@ func (a *App) Run(arguments []string) (err error) {
|
|||||||
// RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to
|
// RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to
|
||||||
// generate command-specific flags
|
// generate command-specific flags
|
||||||
func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
||||||
|
a.Setup()
|
||||||
|
|
||||||
// append help to commands
|
// append help to commands
|
||||||
if len(a.Commands) > 0 {
|
if len(a.Commands) > 0 {
|
||||||
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
||||||
@ -301,7 +305,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
|||||||
HandleExitCoder(err)
|
HandleExitCoder(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(a.Writer, "Incorrect Usage: %s\n\n", err)
|
fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
|
||||||
ShowSubcommandHelp(context)
|
ShowSubcommandHelp(context)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -441,8 +445,8 @@ type Author struct {
|
|||||||
func (a *Author) String() string {
|
func (a *Author) String() string {
|
||||||
e := ""
|
e := ""
|
||||||
if a.Email != "" {
|
if a.Email != "" {
|
||||||
e = "<" + a.Email + "> "
|
e = " <" + a.Email + ">"
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("%v %v", a.Name, e)
|
return fmt.Sprintf("%v%v", a.Name, e)
|
||||||
}
|
}
|
||||||
|
78
app_test.go
78
app_test.go
@ -91,7 +91,63 @@ func ExampleApp_Run_subcommand() {
|
|||||||
// Hello, Jeremy
|
// Hello, Jeremy
|
||||||
}
|
}
|
||||||
|
|
||||||
func ExampleApp_Run_help() {
|
func ExampleApp_Run_appHelp() {
|
||||||
|
// set args for examples sake
|
||||||
|
os.Args = []string{"greet", "help"}
|
||||||
|
|
||||||
|
app := &App{
|
||||||
|
Name: "greet",
|
||||||
|
Version: "0.1.0",
|
||||||
|
Description: "This is how we describe greet the app",
|
||||||
|
Authors: []*Author{
|
||||||
|
{Name: "Harrison", Email: "harrison@lolwut.com"},
|
||||||
|
{Name: "Oliver Allen", Email: "oliver@toyshop.com"},
|
||||||
|
},
|
||||||
|
Flags: []Flag{
|
||||||
|
&StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
|
||||||
|
},
|
||||||
|
Commands: []*Command{
|
||||||
|
{
|
||||||
|
Name: "describeit",
|
||||||
|
Aliases: []string{"d"},
|
||||||
|
Usage: "use it to see a description",
|
||||||
|
Description: "This is how we describe describeit the function",
|
||||||
|
Action: func(c *Context) error {
|
||||||
|
fmt.Printf("i like to describe things")
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
app.Run(os.Args)
|
||||||
|
// Output:
|
||||||
|
// NAME:
|
||||||
|
// greet - A new cli application
|
||||||
|
//
|
||||||
|
// USAGE:
|
||||||
|
// greet [global options] command [command options] [arguments...]
|
||||||
|
//
|
||||||
|
// VERSION:
|
||||||
|
// 0.1.0
|
||||||
|
//
|
||||||
|
// DESCRIPTION:
|
||||||
|
// This is how we describe greet the app
|
||||||
|
//
|
||||||
|
// AUTHORS:
|
||||||
|
// Harrison <harrison@lolwut.com>
|
||||||
|
// Oliver Allen <oliver@toyshop.com>
|
||||||
|
//
|
||||||
|
// COMMANDS:
|
||||||
|
// describeit, d use it to see a description
|
||||||
|
// help, h Shows a list of commands or help for one command
|
||||||
|
//
|
||||||
|
// GLOBAL OPTIONS:
|
||||||
|
// --name value a name to say (default: "bob")
|
||||||
|
// --help, -h show help (default: false)
|
||||||
|
// --version, -v print the version (default: false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExampleApp_Run_commandHelp() {
|
||||||
// set args for examples sake
|
// set args for examples sake
|
||||||
os.Args = []string{"greet", "h", "describeit"}
|
os.Args = []string{"greet", "h", "describeit"}
|
||||||
|
|
||||||
@ -130,7 +186,7 @@ func ExampleApp_Run_shellComplete() {
|
|||||||
os.Args = []string{"greet", "--generate-completion"}
|
os.Args = []string{"greet", "--generate-completion"}
|
||||||
|
|
||||||
app := &App{
|
app := &App{
|
||||||
Name: "greet",
|
Name: "greet",
|
||||||
EnableShellCompletion: true,
|
EnableShellCompletion: true,
|
||||||
Commands: []*Command{
|
Commands: []*Command{
|
||||||
{
|
{
|
||||||
@ -234,6 +290,24 @@ func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
|
|||||||
expect(t, context.String("lang"), "spanish")
|
expect(t, context.String("lang"), "spanish")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestApp_RunAsSubCommandIncorrectUsage(t *testing.T) {
|
||||||
|
a := App{
|
||||||
|
Name: "cmd",
|
||||||
|
Flags: []Flag{
|
||||||
|
&StringFlag{Name: "--foo"},
|
||||||
|
},
|
||||||
|
Writer: bytes.NewBufferString(""),
|
||||||
|
}
|
||||||
|
|
||||||
|
set := flag.NewFlagSet("", flag.ContinueOnError)
|
||||||
|
set.Parse([]string{"", "---foo"})
|
||||||
|
c := &Context{flagSet: set}
|
||||||
|
|
||||||
|
err := a.RunAsSubcommand(c)
|
||||||
|
|
||||||
|
expect(t, err, errors.New("bad flag syntax: ---foo"))
|
||||||
|
}
|
||||||
|
|
||||||
func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
|
func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
|
||||||
var parsedOption string
|
var parsedOption string
|
||||||
var args Args
|
var args Args
|
||||||
|
@ -90,7 +90,7 @@ func (c *Command) Run(ctx *Context) (err error) {
|
|||||||
HandleExitCoder(err)
|
HandleExitCoder(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(ctx.App.Writer, "Incorrect Usage: %s\n\n", err)
|
fmt.Fprintln(ctx.App.Writer, "Incorrect Usage:", err.Error())
|
||||||
fmt.Fprintln(ctx.App.Writer)
|
fmt.Fprintln(ctx.App.Writer)
|
||||||
ShowCommandHelp(ctx, c.Name)
|
ShowCommandHelp(ctx, c.Name)
|
||||||
return err
|
return err
|
||||||
|
@ -15,10 +15,12 @@ func TestCommandFlagParsing(t *testing.T) {
|
|||||||
skipFlagParsing bool
|
skipFlagParsing bool
|
||||||
expectedErr error
|
expectedErr error
|
||||||
}{
|
}{
|
||||||
{[]string{"test-cmd", "-break", "blah", "blah"}, false, errors.New("flag provided but not defined: -break")}, // Test normal "not ignoring flags" flow
|
// Test normal "not ignoring flags" flow
|
||||||
{[]string{"test-cmd", "blah", "blah"}, true, nil}, // Test SkipFlagParsing without any args that look like flags
|
{[]string{"test-cmd", "-break", "blah", "blah"}, false, errors.New("flag provided but not defined: -break")},
|
||||||
{[]string{"test-cmd", "-break", "blah"}, true, nil}, // Test SkipFlagParsing with random flag arg
|
|
||||||
{[]string{"test-cmd", "-help", "blah"}, true, nil}, // Test SkipFlagParsing with "special" help flag arg
|
{[]string{"test-cmd", "blah", "blah"}, true, nil}, // Test SkipFlagParsing without any args that look like flags
|
||||||
|
{[]string{"test-cmd", "blah", "-break"}, true, nil}, // Test SkipFlagParsing with random flag arg
|
||||||
|
{[]string{"test-cmd", "blah", "-help"}, true, nil}, // Test SkipFlagParsing with "special" help flag arg
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
@ -29,15 +31,14 @@ func TestCommandFlagParsing(t *testing.T) {
|
|||||||
context := NewContext(app, set, nil)
|
context := NewContext(app, set, nil)
|
||||||
|
|
||||||
command := Command{
|
command := Command{
|
||||||
Name: "test-cmd",
|
Name: "test-cmd",
|
||||||
Aliases: []string{"tc"},
|
Aliases: []string{"tc"},
|
||||||
Usage: "this is for testing",
|
Usage: "this is for testing",
|
||||||
Description: "testing",
|
Description: "testing",
|
||||||
Action: func(_ *Context) error { return nil },
|
Action: func(_ *Context) error { return nil },
|
||||||
|
SkipFlagParsing: c.skipFlagParsing,
|
||||||
}
|
}
|
||||||
|
|
||||||
command.SkipFlagParsing = c.skipFlagParsing
|
|
||||||
|
|
||||||
err := command.Run(context)
|
err := command.Run(context)
|
||||||
|
|
||||||
expect(t, err, c.expectedErr)
|
expect(t, err, c.expectedErr)
|
||||||
|
68
context.go
68
context.go
@ -3,6 +3,8 @@ package cli
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -42,8 +44,44 @@ func (c *Context) IsSet(name string) bool {
|
|||||||
isSet = true
|
isSet = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return isSet
|
if isSet {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// XXX hack to support IsSet for flags with EnvVar
|
||||||
|
//
|
||||||
|
// There isn't an easy way to do this with the current implementation since
|
||||||
|
// whether a flag was set via an environment variable is very difficult to
|
||||||
|
// determine here. Instead, we intend to introduce a backwards incompatible
|
||||||
|
// change in version 2 to add `IsSet` to the Flag interface to push the
|
||||||
|
// responsibility closer to where the information required to determine
|
||||||
|
// whether a flag is set by non-standard means such as environment
|
||||||
|
// variables is avaliable.
|
||||||
|
//
|
||||||
|
// See https://github.com/urfave/cli/issues/294 for additional discussion
|
||||||
|
f := lookupFlag(name, c)
|
||||||
|
if f == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val := reflect.ValueOf(f)
|
||||||
|
if val.Kind() == reflect.Ptr {
|
||||||
|
val = val.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
envVarValues := val.FieldByName("EnvVars")
|
||||||
|
if !envVarValues.IsValid() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, envVar := range envVarValues.Interface().([]string) {
|
||||||
|
envVar = strings.TrimSpace(envVar)
|
||||||
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,6 +125,34 @@ func (c *Context) NArg() int {
|
|||||||
return c.Args().Len()
|
return c.Args().Len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func lookupFlag(name string, ctx *Context) Flag {
|
||||||
|
for _, c := range ctx.Lineage() {
|
||||||
|
if c.Command == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, f := range c.Command.Flags {
|
||||||
|
for _, n := range f.Names() {
|
||||||
|
if n == name {
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.App != nil {
|
||||||
|
for _, f := range ctx.App.Flags {
|
||||||
|
for _, n := range f.Names() {
|
||||||
|
if n == name {
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func lookupFlagSet(name string, ctx *Context) *flag.FlagSet {
|
func lookupFlagSet(name string, ctx *Context) *flag.FlagSet {
|
||||||
for _, c := range ctx.Lineage() {
|
for _, c := range ctx.Lineage() {
|
||||||
if f := c.flagSet.Lookup(name); f != nil {
|
if f := c.flagSet.Lookup(name); f != nil {
|
||||||
|
20
flag.go
20
flag.go
@ -58,6 +58,26 @@ type Serializeder interface {
|
|||||||
Serialized() string
|
Serialized() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FlagsByName is a slice of Flag.
|
||||||
|
type FlagsByName []Flag
|
||||||
|
|
||||||
|
func (f FlagsByName) Len() int {
|
||||||
|
return len(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FlagsByName) Less(i, j int) bool {
|
||||||
|
if len(f[j].Names()) == 0 {
|
||||||
|
return false
|
||||||
|
} else if len(f[i].Names()) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return f[i].Names()[0] < f[j].Names()[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FlagsByName) Swap(i, j int) {
|
||||||
|
f[i], f[j] = f[j], f[i]
|
||||||
|
}
|
||||||
|
|
||||||
// Flag is a common interface related to parsing flags in cli.
|
// Flag is a common interface related to parsing flags in cli.
|
||||||
// For more advanced flag parsing techniques, it is recommended that
|
// For more advanced flag parsing techniques, it is recommended that
|
||||||
// this interface be implemented.
|
// this interface be implemented.
|
||||||
|
41
help.go
41
help.go
@ -16,24 +16,28 @@ var AppHelpTemplate = `NAME:
|
|||||||
{{.Name}} - {{.Usage}}
|
{{.Name}} - {{.Usage}}
|
||||||
|
|
||||||
USAGE:
|
USAGE:
|
||||||
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}
|
{{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}}
|
||||||
{{if .Version}}{{if not .HideVersion}}
|
|
||||||
VERSION:
|
VERSION:
|
||||||
{{.Version}}
|
{{.Version}}{{end}}{{end}}{{if .Description}}
|
||||||
{{end}}{{end}}{{if len .Authors}}
|
|
||||||
AUTHOR(S):
|
DESCRIPTION:
|
||||||
{{range .Authors}}{{.}}{{end}}
|
{{.Description}}{{end}}{{if len .Authors}}
|
||||||
{{end}}{{if .VisibleCommands}}
|
|
||||||
|
AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}:
|
||||||
|
{{range $index, $author := .Authors}}{{if $index}}
|
||||||
|
{{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}}
|
||||||
|
|
||||||
COMMANDS:{{range .VisibleCategories}}{{if .Name}}
|
COMMANDS:{{range .VisibleCategories}}{{if .Name}}
|
||||||
{{.Name}}:{{end}}{{range .VisibleCommands}}
|
{{.Name}}:{{end}}{{range .VisibleCommands}}
|
||||||
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}
|
{{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
|
||||||
{{end}}{{end}}{{if .VisibleFlags}}
|
|
||||||
GLOBAL OPTIONS:
|
GLOBAL OPTIONS:
|
||||||
{{range .VisibleFlags}}{{.}}
|
{{range $index, $option := .VisibleFlags}}{{if $index}}
|
||||||
{{end}}{{end}}{{if .Copyright}}
|
{{end}}{{$option}}{{end}}{{end}}{{if .Copyright}}
|
||||||
|
|
||||||
COPYRIGHT:
|
COPYRIGHT:
|
||||||
{{.Copyright}}
|
{{.Copyright}}{{end}}
|
||||||
{{end}}
|
|
||||||
`
|
`
|
||||||
|
|
||||||
// CommandHelpTemplate is the text template for the command help topic.
|
// CommandHelpTemplate is the text template for the command help topic.
|
||||||
@ -205,17 +209,6 @@ func printHelp(out io.Writer, templ string, data interface{}) {
|
|||||||
|
|
||||||
errDebug := os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != ""
|
errDebug := os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != ""
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
if errDebug {
|
|
||||||
fmt.Fprintf(ErrWriter, "CLI TEMPLATE PANIC: %#v\n", r)
|
|
||||||
}
|
|
||||||
if os.Getenv("CLI_TEMPLATE_REPANIC") != "" {
|
|
||||||
panic(r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
err := t.Execute(w, data)
|
err := t.Execute(w, data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errDebug {
|
if errDebug {
|
||||||
|
Loading…
Reference in New Issue
Block a user