From un-tagged pervious version : https://github.com/urfave/cli/compare/d86a009f5e13...mastertags/v1.21.12.1
| @@ -109,7 +109,7 @@ require ( | |||||
| github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 // indirect | github.com/tecbot/gorocksdb v0.0.0-20181010114359-8752a9433481 // indirect | ||||
| github.com/tinylib/msgp v0.0.0-20180516164116-c8cf64dff200 // indirect | github.com/tinylib/msgp v0.0.0-20180516164116-c8cf64dff200 // indirect | ||||
| github.com/tstranex/u2f v1.0.0 | github.com/tstranex/u2f v1.0.0 | ||||
| github.com/urfave/cli v0.0.0-20161102131801-d86a009f5e13 | |||||
| github.com/urfave/cli v1.20.0 | |||||
| github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621 // indirect | github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621 // indirect | ||||
| github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 | github.com/yohcop/openid-go v0.0.0-20160914080427-2c050d2dae53 | ||||
| go.etcd.io/bbolt v1.3.2 // indirect | go.etcd.io/bbolt v1.3.2 // indirect | ||||
| @@ -221,8 +221,6 @@ github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK86 | |||||
| github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= | github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= | ||||
| github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= | ||||
| github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= | ||||
| github.com/mcuadros/go-version v0.0.0-20171003094716-88e56e02bea1 h1:4yXas1DDHpauOfuyfmAMm+EB+SiqPKEoTdc88XEJHsc= | |||||
| github.com/mcuadros/go-version v0.0.0-20171003094716-88e56e02bea1/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo= | |||||
| github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 h1:Pijfgr7ZuvX7QIQiEwLdRVr3RoMG+i0SbBO1Qu+7yVk= | github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75 h1:Pijfgr7ZuvX7QIQiEwLdRVr3RoMG+i0SbBO1Qu+7yVk= | ||||
| github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo= | github.com/mcuadros/go-version v0.0.0-20190308113854-92cdf37c5b75/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo= | ||||
| github.com/microcosm-cc/bluemonday v0.0.0-20161012083705-f77f16ffc87a h1:d18LCO3ctH2kugUqt0pEyKKP8L+IYrocaPqGFilhTKk= | github.com/microcosm-cc/bluemonday v0.0.0-20161012083705-f77f16ffc87a h1:d18LCO3ctH2kugUqt0pEyKKP8L+IYrocaPqGFilhTKk= | ||||
| @@ -299,8 +297,8 @@ github.com/tinylib/msgp v0.0.0-20180516164116-c8cf64dff200 h1:ZVvr38DYEyOPyelySq | |||||
| github.com/tinylib/msgp v0.0.0-20180516164116-c8cf64dff200/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= | github.com/tinylib/msgp v0.0.0-20180516164116-c8cf64dff200/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= | ||||
| github.com/tstranex/u2f v1.0.0 h1:HhJkSzDDlVSVIVt7pDJwCHQj67k7A5EeBgPmeD+pVsQ= | github.com/tstranex/u2f v1.0.0 h1:HhJkSzDDlVSVIVt7pDJwCHQj67k7A5EeBgPmeD+pVsQ= | ||||
| github.com/tstranex/u2f v1.0.0/go.mod h1:eahSLaqAS0zsIEv80+vXT7WanXs7MQQDg3j3wGBSayo= | github.com/tstranex/u2f v1.0.0/go.mod h1:eahSLaqAS0zsIEv80+vXT7WanXs7MQQDg3j3wGBSayo= | ||||
| github.com/urfave/cli v0.0.0-20161102131801-d86a009f5e13 h1:niRuEF0NOlFnqraxzjuvvOdCM6gxmHiaBABjvg3/kDo= | |||||
| github.com/urfave/cli v0.0.0-20161102131801-d86a009f5e13/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= | |||||
| github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= | |||||
| github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= | |||||
| github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621 h1:E8u341JM/N8LCnPXBV6ZFD1RKo/j+qHl1XOqSV+GstA= | github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621 h1:E8u341JM/N8LCnPXBV6ZFD1RKo/j+qHl1XOqSV+GstA= | ||||
| github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= | github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= | ||||
| github.com/xanzy/ssh-agent v0.2.0 h1:Adglfbi5p9Z0BmK2oKU9nTG+zKfniSfnaMYB+ULd+Ro= | github.com/xanzy/ssh-agent v0.2.0 h1:Adglfbi5p9Z0BmK2oKU9nTG+zKfniSfnaMYB+ULd+Ro= | ||||
| @@ -359,8 +357,6 @@ gopkg.in/src-d/go-billy.v4 v4.3.0 h1:KtlZ4c1OWbIs4jCv5ZXrTqG8EQocr0g/d4DjNg70aek | |||||
| gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= | gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= | ||||
| gopkg.in/src-d/go-git-fixtures.v3 v3.1.1 h1:XWW/s5W18RaJpmo1l0IYGqXKuJITWRFuA45iOf1dKJs= | gopkg.in/src-d/go-git-fixtures.v3 v3.1.1 h1:XWW/s5W18RaJpmo1l0IYGqXKuJITWRFuA45iOf1dKJs= | ||||
| gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= | gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= | ||||
| gopkg.in/src-d/go-git.v4 v4.8.0 h1:dDEbgvfNG9vUDM54uhCYPExiGa8uYgXpQ/MR8YvxcAM= | |||||
| gopkg.in/src-d/go-git.v4 v4.8.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk= | |||||
| gopkg.in/src-d/go-git.v4 v4.10.0 h1:NWjTJTQnk8UpIGlssuefyDZ6JruEjo5s88vm88uASbw= | gopkg.in/src-d/go-git.v4 v4.10.0 h1:NWjTJTQnk8UpIGlssuefyDZ6JruEjo5s88vm88uASbw= | ||||
| gopkg.in/src-d/go-git.v4 v4.10.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk= | gopkg.in/src-d/go-git.v4 v4.10.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk= | ||||
| gopkg.in/stretchr/testify.v1 v1.2.2 h1:yhQC6Uy5CqibAIlk1wlusa/MJ3iAN49/BsR/dCCKz3M= | gopkg.in/stretchr/testify.v1 v1.2.2 h1:yhQC6Uy5CqibAIlk1wlusa/MJ3iAN49/BsR/dCCKz3M= | ||||
| @@ -0,0 +1,2 @@ | |||||
| [flake8] | |||||
| max-line-length = 120 | |||||
| @@ -1,32 +1,20 @@ | |||||
| language: go | language: go | ||||
| sudo: false | sudo: false | ||||
| dist: trusty | |||||
| osx_image: xcode8.3 | |||||
| go: 1.8.x | |||||
| os: | |||||
| - linux | |||||
| - osx | |||||
| cache: | cache: | ||||
| directories: | directories: | ||||
| - node_modules | - node_modules | ||||
| go: | |||||
| - 1.2.x | |||||
| - 1.3.x | |||||
| - 1.4.2 | |||||
| - 1.5.x | |||||
| - 1.6.x | |||||
| - 1.7.x | |||||
| - master | |||||
| matrix: | |||||
| allow_failures: | |||||
| - go: master | |||||
| include: | |||||
| - go: 1.6.x | |||||
| os: osx | |||||
| - go: 1.7.x | |||||
| os: osx | |||||
| before_script: | before_script: | ||||
| - go get github.com/urfave/gfmrun/... || true | - go get github.com/urfave/gfmrun/... || true | ||||
| - go get golang.org/x/tools/... || true | |||||
| - go get golang.org/x/tools/cmd/goimports | |||||
| - if [ ! -f node_modules/.bin/markdown-toc ] ; then | - if [ ! -f node_modules/.bin/markdown-toc ] ; then | ||||
| npm install markdown-toc ; | npm install markdown-toc ; | ||||
| fi | fi | ||||
| @@ -3,14 +3,105 @@ | |||||
| **ATTN**: This project uses [semantic versioning](http://semver.org/). | **ATTN**: This project uses [semantic versioning](http://semver.org/). | ||||
| ## [Unreleased] | ## [Unreleased] | ||||
| ## 1.20.0 - 2017-08-10 | |||||
| ### Fixed | |||||
| * `HandleExitCoder` is now correctly iterates over all errors in | |||||
| a `MultiError`. The exit code is the exit code of the last error or `1` if | |||||
| there are no `ExitCoder`s in the `MultiError`. | |||||
| * Fixed YAML file loading on Windows (previously would fail validate the file path) | |||||
| * Subcommand `Usage`, `Description`, `ArgsUsage`, `OnUsageError` correctly | |||||
| propogated | |||||
| * `ErrWriter` is now passed downwards through command structure to avoid the | |||||
| need to redefine it | |||||
| * Pass `Command` context into `OnUsageError` rather than parent context so that | |||||
| all fields are avaiable | |||||
| * Errors occuring in `Before` funcs are no longer double printed | |||||
| * Use `UsageText` in the help templates for commands and subcommands if | |||||
| defined; otherwise build the usage as before (was previously ignoring this | |||||
| field) | |||||
| * `IsSet` and `GlobalIsSet` now correctly return whether a flag is set if | |||||
| a program calls `Set` or `GlobalSet` directly after flag parsing (would | |||||
| previously only return `true` if the flag was set during parsing) | |||||
| ### Changed | |||||
| * No longer exit the program on command/subcommand error if the error raised is | |||||
| not an `OsExiter`. This exiting behavior was introduced in 1.19.0, but was | |||||
| determined to be a regression in functionality. See [the | |||||
| PR](https://github.com/urfave/cli/pull/595) for discussion. | |||||
| ### Added | ### Added | ||||
| * `CommandsByName` type was added to make it easy to sort `Command`s by name, | |||||
| alphabetically | |||||
| * `altsrc` now handles loading of string and int arrays from TOML | |||||
| * Support for definition of custom help templates for `App` via | |||||
| `CustomAppHelpTemplate` | |||||
| * Support for arbitrary key/value fields on `App` to be used with | |||||
| `CustomAppHelpTemplate` via `ExtraInfo` | |||||
| * `HelpFlag`, `VersionFlag`, and `BashCompletionFlag` changed to explictly be | |||||
| `cli.Flag`s allowing for the use of custom flags satisfying the `cli.Flag` | |||||
| interface to be used. | |||||
| ## [1.19.1] - 2016-11-21 | |||||
| ### Fixed | |||||
| - Fixes regression introduced in 1.19.0 where using an `ActionFunc` as | |||||
| the `Action` for a command would cause it to error rather than calling the | |||||
| function. Should not have a affected declarative cases using `func(c | |||||
| *cli.Context) err)`. | |||||
| - Shell completion now handles the case where the user specifies | |||||
| `--generate-bash-completion` immediately after a flag that takes an argument. | |||||
| Previously it call the application with `--generate-bash-completion` as the | |||||
| flag value. | |||||
| ## [1.19.0] - 2016-11-19 | |||||
| ### Added | |||||
| - `FlagsByName` was added to make it easy to sort flags (e.g. `sort.Sort(cli.FlagsByName(app.Flags))`) | |||||
| - A `Description` field was added to `App` for a more detailed description of | |||||
| the application (similar to the existing `Description` field on `Command`) | |||||
| - Flag type code generation via `go generate` | - Flag type code generation via `go generate` | ||||
| - Write to stderr and exit 1 if action returns non-nil error | - Write to stderr and exit 1 if action returns non-nil error | ||||
| - Added support for TOML to the `altsrc` loader | - Added support for TOML to the `altsrc` loader | ||||
| - `SkipArgReorder` was added to allow users to skip the argument reordering. | |||||
| This is useful if you want to consider all "flags" after an argument as | |||||
| arguments rather than flags (the default behavior of the stdlib `flag` | |||||
| library). This is backported functionality from the [removal of the flag | |||||
| reordering](https://github.com/urfave/cli/pull/398) in the unreleased version | |||||
| 2 | |||||
| - For formatted errors (those implementing `ErrorFormatter`), the errors will | |||||
| be formatted during output. Compatible with `pkg/errors`. | |||||
| ### Changed | ### Changed | ||||
| - Raise minimum tested/supported Go version to 1.2+ | - Raise minimum tested/supported Go version to 1.2+ | ||||
| ### Fixed | |||||
| - Consider empty environment variables as set (previously environment variables | |||||
| with the equivalent of `""` would be skipped rather than their value used). | |||||
| - Return an error if the value in a given environment variable cannot be parsed | |||||
| as the flag type. Previously these errors were silently swallowed. | |||||
| - Print full error when an invalid flag is specified (which includes the invalid flag) | |||||
| - `App.Writer` defaults to `stdout` when `nil` | |||||
| - If no action is specified on a command or app, the help is now printed instead of `panic`ing | |||||
| - `App.Metadata` is initialized automatically now (previously was `nil` unless initialized) | |||||
| - Correctly show help message if `-h` is provided to a subcommand | |||||
| - `context.(Global)IsSet` now respects environment variables. Previously it | |||||
| would return `false` if a flag was specified in the environment rather than | |||||
| as an argument | |||||
| - Removed deprecation warnings to STDERR to avoid them leaking to the end-user | |||||
| - `altsrc`s import paths were updated to use `gopkg.in/urfave/cli.v1`. This | |||||
| fixes issues that occurred when `gopkg.in/urfave/cli.v1` was imported as well | |||||
| as `altsrc` where Go would complain that the types didn't match | |||||
| ## [1.18.1] - 2016-08-28 | |||||
| ### Fixed | |||||
| - Removed deprecation warnings to STDERR to avoid them leaking to the end-user (backported) | |||||
| ## [1.18.0] - 2016-06-27 | ## [1.18.0] - 2016-06-27 | ||||
| ### Added | ### Added | ||||
| - `./runtests` test runner with coverage tracking by default | - `./runtests` test runner with coverage tracking by default | ||||
| @@ -29,6 +120,10 @@ | |||||
| - No longer swallows `panic`s that occur within the `Action`s themselves when | - No longer swallows `panic`s that occur within the `Action`s themselves when | ||||
| detecting the signature of the `Action` field | detecting the signature of the `Action` field | ||||
| ## [1.17.1] - 2016-08-28 | |||||
| ### Fixed | |||||
| - Removed deprecation warnings to STDERR to avoid them leaking to the end-user | |||||
| ## [1.17.0] - 2016-05-09 | ## [1.17.0] - 2016-05-09 | ||||
| ### Added | ### Added | ||||
| - Pluggable flag-level help text rendering via `cli.DefaultFlagStringFunc` | - Pluggable flag-level help text rendering via `cli.DefaultFlagStringFunc` | ||||
| @@ -50,6 +145,10 @@ | |||||
| - cleanups based on [Go Report Card | - cleanups based on [Go Report Card | ||||
| feedback](https://goreportcard.com/report/github.com/urfave/cli) | feedback](https://goreportcard.com/report/github.com/urfave/cli) | ||||
| ## [1.16.1] - 2016-08-28 | |||||
| ### Fixed | |||||
| - Removed deprecation warnings to STDERR to avoid them leaking to the end-user | |||||
| ## [1.16.0] - 2016-05-02 | ## [1.16.0] - 2016-05-02 | ||||
| ### Added | ### Added | ||||
| - `Hidden` field on all flag struct types to omit from generated help text | - `Hidden` field on all flag struct types to omit from generated help text | ||||
| @@ -455,13 +455,13 @@ error. | |||||
| Flags for the application and commands are shown in the order they are defined. | 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` | However, it's possible to sort them from outside this library by using `FlagsByName` | ||||
| with `sort`. | |||||
| or `CommandsByName` with `sort`. | |||||
| For example this: | For example this: | ||||
| <!-- { | <!-- { | ||||
| "args": ["--help"], | "args": ["--help"], | ||||
| "output": "Load configuration from FILE\n.*Language for the greeting.*" | |||||
| "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 | ``` go | ||||
| package main | package main | ||||
| @@ -488,7 +488,27 @@ func main() { | |||||
| }, | }, | ||||
| } | } | ||||
| 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.FlagsByName(app.Flags)) | ||||
| sort.Sort(cli.CommandsByName(app.Commands)) | |||||
| app.Run(os.Args) | app.Run(os.Args) | ||||
| } | } | ||||
| @@ -940,16 +960,13 @@ SUPPORT: support@awesometown.example.com | |||||
| cli.AppHelpTemplate = `NAME: | cli.AppHelpTemplate = `NAME: | ||||
| {{.Name}} - {{.Usage}} | {{.Name}} - {{.Usage}} | ||||
| USAGE: | USAGE: | ||||
| {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command | |||||
| [command options]{{end}} {{if | |||||
| .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} | |||||
| {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} | |||||
| {{if len .Authors}} | {{if len .Authors}} | ||||
| AUTHOR(S): | |||||
| AUTHOR: | |||||
| {{range .Authors}}{{ . }}{{end}} | {{range .Authors}}{{ . }}{{end}} | ||||
| {{end}}{{if .Commands}} | {{end}}{{if .Commands}} | ||||
| COMMANDS: | COMMANDS: | ||||
| {{range .Commands}}{{if not .HideHelp}} {{join .Names ", "}}{{ "\t" | |||||
| }}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}} | |||||
| {{range .Commands}}{{if not .HideHelp}} {{join .Names ", "}}{{ "\t"}}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}} | |||||
| GLOBAL OPTIONS: | GLOBAL OPTIONS: | ||||
| {{range .VisibleFlags}}{{.}} | {{range .VisibleFlags}}{{.}} | ||||
| {{end}}{{end}}{{if .Copyright }} | {{end}}{{end}}{{if .Copyright }} | ||||
| @@ -85,6 +85,12 @@ type App struct { | |||||
| ErrWriter io.Writer | ErrWriter io.Writer | ||||
| // Other custom info | // Other custom info | ||||
| Metadata map[string]interface{} | Metadata map[string]interface{} | ||||
| // Carries a function which returns app specific info. | |||||
| ExtraInfo func() map[string]string | |||||
| // CustomAppHelpTemplate the text template for app help topic. | |||||
| // cli.go uses text/template to render templates. You can | |||||
| // render custom help text by setting this variable. | |||||
| CustomAppHelpTemplate string | |||||
| didSetup bool | didSetup bool | ||||
| } | } | ||||
| @@ -145,10 +151,6 @@ func (a *App) Setup() { | |||||
| } | } | ||||
| } | } | ||||
| if a.EnableBashCompletion { | |||||
| a.appendFlag(BashCompletionFlag) | |||||
| } | |||||
| if !a.HideVersion { | if !a.HideVersion { | ||||
| a.appendFlag(VersionFlag) | a.appendFlag(VersionFlag) | ||||
| } | } | ||||
| @@ -173,8 +175,20 @@ func (a *App) Setup() { | |||||
| func (a *App) Run(arguments []string) (err error) { | func (a *App) Run(arguments []string) (err error) { | ||||
| a.Setup() | a.Setup() | ||||
| // handle the completion flag separately from the flagset since | |||||
| // completion could be attempted after a flag, but before its value was put | |||||
| // on the command line. this causes the flagset to interpret the completion | |||||
| // flag name as the value of the flag before it which is undesirable | |||||
| // note that we can only do this because the shell autocomplete function | |||||
| // always appends the completion flag at the end of the command | |||||
| shellComplete, arguments := checkShellCompleteFlag(a, arguments) | |||||
| // parse flags | // parse flags | ||||
| set := flagSet(a.Name, a.Flags) | |||||
| set, err := flagSet(a.Name, a.Flags) | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| set.SetOutput(ioutil.Discard) | set.SetOutput(ioutil.Discard) | ||||
| err = set.Parse(arguments[1:]) | err = set.Parse(arguments[1:]) | ||||
| nerr := normalizeFlags(a.Flags, set) | nerr := normalizeFlags(a.Flags, set) | ||||
| @@ -184,6 +198,7 @@ func (a *App) Run(arguments []string) (err error) { | |||||
| ShowAppHelp(context) | ShowAppHelp(context) | ||||
| return nerr | return nerr | ||||
| } | } | ||||
| context.shellComplete = shellComplete | |||||
| if checkCompletions(context) { | if checkCompletions(context) { | ||||
| return nil | return nil | ||||
| @@ -225,7 +240,6 @@ func (a *App) Run(arguments []string) (err error) { | |||||
| if a.Before != nil { | if a.Before != nil { | ||||
| beforeErr := a.Before(context) | beforeErr := a.Before(context) | ||||
| if beforeErr != nil { | if beforeErr != nil { | ||||
| fmt.Fprintf(a.Writer, "%v\n\n", beforeErr) | |||||
| ShowAppHelp(context) | ShowAppHelp(context) | ||||
| HandleExitCoder(beforeErr) | HandleExitCoder(beforeErr) | ||||
| err = beforeErr | err = beforeErr | ||||
| @@ -242,6 +256,10 @@ func (a *App) Run(arguments []string) (err error) { | |||||
| } | } | ||||
| } | } | ||||
| if a.Action == nil { | |||||
| a.Action = helpCommand.Action | |||||
| } | |||||
| // Run default Action | // Run default Action | ||||
| err = HandleAction(a.Action, context) | err = HandleAction(a.Action, context) | ||||
| @@ -283,13 +301,12 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { | |||||
| } | } | ||||
| a.Commands = newCmds | a.Commands = newCmds | ||||
| // append flags | |||||
| if a.EnableBashCompletion { | |||||
| a.appendFlag(BashCompletionFlag) | |||||
| // parse flags | |||||
| set, err := flagSet(a.Name, a.Flags) | |||||
| if err != nil { | |||||
| return err | |||||
| } | } | ||||
| // parse flags | |||||
| set := flagSet(a.Name, a.Flags) | |||||
| set.SetOutput(ioutil.Discard) | set.SetOutput(ioutil.Discard) | ||||
| err = set.Parse(ctx.Args().Tail()) | err = set.Parse(ctx.Args().Tail()) | ||||
| nerr := normalizeFlags(a.Flags, set) | nerr := normalizeFlags(a.Flags, set) | ||||
| @@ -467,7 +484,9 @@ func (a Author) String() string { | |||||
| // it's an ActionFunc or a func with the legacy signature for Action, the func | // it's an ActionFunc or a func with the legacy signature for Action, the func | ||||
| // is run! | // is run! | ||||
| func HandleAction(action interface{}, context *Context) (err error) { | func HandleAction(action interface{}, context *Context) (err error) { | ||||
| if a, ok := action.(func(*Context) error); ok { | |||||
| if a, ok := action.(ActionFunc); ok { | |||||
| return a(context) | |||||
| } else if a, ok := action.(func(*Context) error); ok { | |||||
| return a(context) | return a(context) | ||||
| } else if a, ok := action.(func(*Context)); ok { // deprecated function signature | } else if a, ok := action.(func(*Context)); ok { // deprecated function signature | ||||
| a(context) | a(context) | ||||
| @@ -1,14 +1,16 @@ | |||||
| version: "{build}" | version: "{build}" | ||||
| os: Windows Server 2012 R2 | |||||
| os: Windows Server 2016 | |||||
| image: Visual Studio 2017 | |||||
| clone_folder: c:\gopath\src\github.com\urfave\cli | clone_folder: c:\gopath\src\github.com\urfave\cli | ||||
| environment: | environment: | ||||
| GOPATH: C:\gopath | GOPATH: C:\gopath | ||||
| GOVERSION: 1.6 | |||||
| PYTHON: C:\Python27-x64 | |||||
| PYTHON_VERSION: 2.7.x | |||||
| GOVERSION: 1.8.x | |||||
| PYTHON: C:\Python36-x64 | |||||
| PYTHON_VERSION: 3.6.x | |||||
| PYTHON_ARCH: 64 | PYTHON_ARCH: 64 | ||||
| install: | install: | ||||
| @@ -12,6 +12,7 @@ | |||||
| // app.Usage = "say a greeting" | // app.Usage = "say a greeting" | ||||
| // app.Action = func(c *cli.Context) error { | // app.Action = func(c *cli.Context) error { | ||||
| // println("Greetings") | // println("Greetings") | ||||
| // return nil | |||||
| // } | // } | ||||
| // | // | ||||
| // app.Run(os.Args) | // app.Run(os.Args) | ||||
| @@ -59,6 +59,25 @@ type Command struct { | |||||
| // Full name of command for help, defaults to full command name, including parent commands. | // Full name of command for help, defaults to full command name, including parent commands. | ||||
| HelpName string | HelpName string | ||||
| commandNamePath []string | commandNamePath []string | ||||
| // CustomHelpTemplate the text template for the command help topic. | |||||
| // cli.go uses text/template to render templates. You can | |||||
| // render custom help text by setting this variable. | |||||
| CustomHelpTemplate string | |||||
| } | |||||
| type CommandsByName []Command | |||||
| func (c CommandsByName) Len() int { | |||||
| return len(c) | |||||
| } | |||||
| func (c CommandsByName) Less(i, j int) bool { | |||||
| return c[i].Name < c[j].Name | |||||
| } | |||||
| func (c CommandsByName) Swap(i, j int) { | |||||
| c[i], c[j] = c[j], c[i] | |||||
| } | } | ||||
| // FullName returns the full name of the command. | // FullName returns the full name of the command. | ||||
| @@ -87,11 +106,10 @@ func (c Command) Run(ctx *Context) (err error) { | |||||
| ) | ) | ||||
| } | } | ||||
| if ctx.App.EnableBashCompletion { | |||||
| c.Flags = append(c.Flags, BashCompletionFlag) | |||||
| set, err := flagSet(c.Name, c.Flags) | |||||
| if err != nil { | |||||
| return err | |||||
| } | } | ||||
| set := flagSet(c.Name, c.Flags) | |||||
| set.SetOutput(ioutil.Discard) | set.SetOutput(ioutil.Discard) | ||||
| if c.SkipFlagParsing { | if c.SkipFlagParsing { | ||||
| @@ -132,18 +150,6 @@ func (c Command) Run(ctx *Context) (err error) { | |||||
| err = set.Parse(ctx.Args().Tail()) | err = set.Parse(ctx.Args().Tail()) | ||||
| } | } | ||||
| if err != nil { | |||||
| if c.OnUsageError != nil { | |||||
| err := c.OnUsageError(ctx, err, false) | |||||
| HandleExitCoder(err) | |||||
| return err | |||||
| } | |||||
| fmt.Fprintln(ctx.App.Writer, "Incorrect Usage:", err.Error()) | |||||
| fmt.Fprintln(ctx.App.Writer) | |||||
| ShowCommandHelp(ctx, c.Name) | |||||
| return err | |||||
| } | |||||
| nerr := normalizeFlags(c.Flags, set) | nerr := normalizeFlags(c.Flags, set) | ||||
| if nerr != nil { | if nerr != nil { | ||||
| fmt.Fprintln(ctx.App.Writer, nerr) | fmt.Fprintln(ctx.App.Writer, nerr) | ||||
| @@ -153,11 +159,23 @@ func (c Command) Run(ctx *Context) (err error) { | |||||
| } | } | ||||
| context := NewContext(ctx.App, set, ctx) | context := NewContext(ctx.App, set, ctx) | ||||
| context.Command = c | |||||
| if checkCommandCompletions(context, c.Name) { | if checkCommandCompletions(context, c.Name) { | ||||
| return nil | return nil | ||||
| } | } | ||||
| if err != nil { | |||||
| if c.OnUsageError != nil { | |||||
| err := c.OnUsageError(context, err, false) | |||||
| HandleExitCoder(err) | |||||
| return err | |||||
| } | |||||
| fmt.Fprintln(context.App.Writer, "Incorrect Usage:", err.Error()) | |||||
| fmt.Fprintln(context.App.Writer) | |||||
| ShowCommandHelp(context, c.Name) | |||||
| return err | |||||
| } | |||||
| if checkCommandHelp(context, c.Name) { | if checkCommandHelp(context, c.Name) { | ||||
| return nil | return nil | ||||
| } | } | ||||
| @@ -179,15 +197,16 @@ func (c Command) Run(ctx *Context) (err error) { | |||||
| if c.Before != nil { | if c.Before != nil { | ||||
| err = c.Before(context) | err = c.Before(context) | ||||
| if err != nil { | if err != nil { | ||||
| fmt.Fprintln(ctx.App.Writer, err) | |||||
| fmt.Fprintln(ctx.App.Writer) | |||||
| ShowCommandHelp(ctx, c.Name) | |||||
| ShowCommandHelp(context, c.Name) | |||||
| HandleExitCoder(err) | HandleExitCoder(err) | ||||
| return err | return err | ||||
| } | } | ||||
| } | } | ||||
| context.Command = c | |||||
| if c.Action == nil { | |||||
| c.Action = helpSubcommand.Action | |||||
| } | |||||
| err = HandleAction(c.Action, context) | err = HandleAction(c.Action, context) | ||||
| if err != nil { | if err != nil { | ||||
| @@ -228,14 +247,13 @@ func (c Command) startApp(ctx *Context) error { | |||||
| app.HelpName = app.Name | app.HelpName = app.Name | ||||
| } | } | ||||
| if c.Description != "" { | |||||
| app.Usage = c.Description | |||||
| } else { | |||||
| app.Usage = c.Usage | |||||
| } | |||||
| app.Usage = c.Usage | |||||
| app.Description = c.Description | |||||
| app.ArgsUsage = c.ArgsUsage | |||||
| // set CommandNotFound | // set CommandNotFound | ||||
| app.CommandNotFound = ctx.App.CommandNotFound | app.CommandNotFound = ctx.App.CommandNotFound | ||||
| app.CustomAppHelpTemplate = c.CustomHelpTemplate | |||||
| // set the flags and commands | // set the flags and commands | ||||
| app.Commands = c.Subcommands | app.Commands = c.Subcommands | ||||
| @@ -248,6 +266,7 @@ func (c Command) startApp(ctx *Context) error { | |||||
| app.Author = ctx.App.Author | app.Author = ctx.App.Author | ||||
| app.Email = ctx.App.Email | app.Email = ctx.App.Email | ||||
| app.Writer = ctx.App.Writer | app.Writer = ctx.App.Writer | ||||
| app.ErrWriter = ctx.App.ErrWriter | |||||
| app.categories = CommandCategories{} | app.categories = CommandCategories{} | ||||
| for _, command := range c.Subcommands { | for _, command := range c.Subcommands { | ||||
| @@ -270,6 +289,7 @@ func (c Command) startApp(ctx *Context) error { | |||||
| } else { | } else { | ||||
| app.Action = helpSubcommand.Action | app.Action = helpSubcommand.Action | ||||
| } | } | ||||
| app.OnUsageError = c.OnUsageError | |||||
| for index, cc := range app.Commands { | for index, cc := range app.Commands { | ||||
| app.Commands[index].commandNamePath = []string{c.Name, cc.Name} | app.Commands[index].commandNamePath = []string{c.Name, cc.Name} | ||||
| @@ -3,9 +3,9 @@ package cli | |||||
| import ( | import ( | ||||
| "errors" | "errors" | ||||
| "flag" | "flag" | ||||
| "os" | |||||
| "reflect" | "reflect" | ||||
| "strings" | "strings" | ||||
| "syscall" | |||||
| ) | ) | ||||
| // Context is a type that is passed through to | // Context is a type that is passed through to | ||||
| @@ -15,6 +15,7 @@ import ( | |||||
| type Context struct { | type Context struct { | ||||
| App *App | App *App | ||||
| Command Command | Command Command | ||||
| shellComplete bool | |||||
| flagSet *flag.FlagSet | flagSet *flag.FlagSet | ||||
| setFlags map[string]bool | setFlags map[string]bool | ||||
| parentContext *Context | parentContext *Context | ||||
| @@ -22,7 +23,13 @@ type Context struct { | |||||
| // NewContext creates a new context. For use in when invoking an App or Command action. | // NewContext creates a new context. For use in when invoking an App or Command action. | ||||
| func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { | func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { | ||||
| return &Context{App: app, flagSet: set, parentContext: parentCtx} | |||||
| c := &Context{App: app, flagSet: set, parentContext: parentCtx} | |||||
| if parentCtx != nil { | |||||
| c.shellComplete = parentCtx.shellComplete | |||||
| } | |||||
| return c | |||||
| } | } | ||||
| // NumFlags returns the number of flags set | // NumFlags returns the number of flags set | ||||
| @@ -32,11 +39,13 @@ func (c *Context) NumFlags() int { | |||||
| // Set sets a context flag to a value. | // Set sets a context flag to a value. | ||||
| func (c *Context) Set(name, value string) error { | func (c *Context) Set(name, value string) error { | ||||
| c.setFlags = nil | |||||
| return c.flagSet.Set(name, value) | return c.flagSet.Set(name, value) | ||||
| } | } | ||||
| // GlobalSet sets a context flag to a value on the global flagset | // GlobalSet sets a context flag to a value on the global flagset | ||||
| func (c *Context) GlobalSet(name, value string) error { | func (c *Context) GlobalSet(name, value string) error { | ||||
| globalContext(c).setFlags = nil | |||||
| return globalContext(c).flagSet.Set(name, value) | return globalContext(c).flagSet.Set(name, value) | ||||
| } | } | ||||
| @@ -91,7 +100,7 @@ func (c *Context) IsSet(name string) bool { | |||||
| eachName(envVarValue.String(), func(envVar string) { | eachName(envVarValue.String(), func(envVar string) { | ||||
| envVar = strings.TrimSpace(envVar) | envVar = strings.TrimSpace(envVar) | ||||
| if envVal := os.Getenv(envVar); envVal != "" { | |||||
| if _, ok := syscall.Getenv(envVar); ok { | |||||
| c.setFlags[name] = true | c.setFlags[name] = true | ||||
| return | return | ||||
| } | } | ||||
| @@ -147,6 +156,11 @@ func (c *Context) Parent() *Context { | |||||
| return c.parentContext | return c.parentContext | ||||
| } | } | ||||
| // value returns the value of the flag coressponding to `name` | |||||
| func (c *Context) value(name string) interface{} { | |||||
| return c.flagSet.Lookup(name).Value.(flag.Getter).Get() | |||||
| } | |||||
| // Args contains apps console arguments | // Args contains apps console arguments | ||||
| type Args []string | type Args []string | ||||
| @@ -34,6 +34,10 @@ func (m MultiError) Error() string { | |||||
| return strings.Join(errs, "\n") | return strings.Join(errs, "\n") | ||||
| } | } | ||||
| type ErrorFormatter interface { | |||||
| Format(s fmt.State, verb rune) | |||||
| } | |||||
| // ExitCoder is the interface checked by `App` and `Command` for a custom exit | // ExitCoder is the interface checked by `App` and `Command` for a custom exit | ||||
| // code | // code | ||||
| type ExitCoder interface { | type ExitCoder interface { | ||||
| @@ -44,11 +48,11 @@ type ExitCoder interface { | |||||
| // ExitError fulfills both the builtin `error` interface and `ExitCoder` | // ExitError fulfills both the builtin `error` interface and `ExitCoder` | ||||
| type ExitError struct { | type ExitError struct { | ||||
| exitCode int | exitCode int | ||||
| message string | |||||
| message interface{} | |||||
| } | } | ||||
| // NewExitError makes a new *ExitError | // NewExitError makes a new *ExitError | ||||
| func NewExitError(message string, exitCode int) *ExitError { | |||||
| func NewExitError(message interface{}, exitCode int) *ExitError { | |||||
| return &ExitError{ | return &ExitError{ | ||||
| exitCode: exitCode, | exitCode: exitCode, | ||||
| message: message, | message: message, | ||||
| @@ -58,7 +62,7 @@ func NewExitError(message string, exitCode int) *ExitError { | |||||
| // Error returns the string message, fulfilling the interface required by | // Error returns the string message, fulfilling the interface required by | ||||
| // `error` | // `error` | ||||
| func (ee *ExitError) Error() string { | func (ee *ExitError) Error() string { | ||||
| return ee.message | |||||
| return fmt.Sprintf("%v", ee.message) | |||||
| } | } | ||||
| // ExitCode returns the exit code, fulfilling the interface required by | // ExitCode returns the exit code, fulfilling the interface required by | ||||
| @@ -70,7 +74,7 @@ func (ee *ExitError) ExitCode() int { | |||||
| // HandleExitCoder checks if the error fulfills the ExitCoder interface, and if | // HandleExitCoder checks if the error fulfills the ExitCoder interface, and if | ||||
| // so prints the error to stderr (if it is non-empty) and calls OsExiter with the | // so prints the error to stderr (if it is non-empty) and calls OsExiter with the | ||||
| // given exit code. If the given error is a MultiError, then this func is | // given exit code. If the given error is a MultiError, then this func is | ||||
| // called on all members of the Errors slice. | |||||
| // called on all members of the Errors slice and calls OsExiter with the last exit code. | |||||
| func HandleExitCoder(err error) { | func HandleExitCoder(err error) { | ||||
| if err == nil { | if err == nil { | ||||
| return | return | ||||
| @@ -78,21 +82,34 @@ func HandleExitCoder(err error) { | |||||
| if exitErr, ok := err.(ExitCoder); ok { | if exitErr, ok := err.(ExitCoder); ok { | ||||
| if err.Error() != "" { | if err.Error() != "" { | ||||
| fmt.Fprintln(ErrWriter, err) | |||||
| if _, ok := exitErr.(ErrorFormatter); ok { | |||||
| fmt.Fprintf(ErrWriter, "%+v\n", err) | |||||
| } else { | |||||
| fmt.Fprintln(ErrWriter, err) | |||||
| } | |||||
| } | } | ||||
| OsExiter(exitErr.ExitCode()) | OsExiter(exitErr.ExitCode()) | ||||
| return | return | ||||
| } | } | ||||
| if multiErr, ok := err.(MultiError); ok { | if multiErr, ok := err.(MultiError); ok { | ||||
| for _, merr := range multiErr.Errors { | |||||
| HandleExitCoder(merr) | |||||
| } | |||||
| code := handleMultiError(multiErr) | |||||
| OsExiter(code) | |||||
| return | return | ||||
| } | } | ||||
| } | |||||
| if err.Error() != "" { | |||||
| fmt.Fprintln(ErrWriter, err) | |||||
| func handleMultiError(multiErr MultiError) int { | |||||
| code := 1 | |||||
| for _, merr := range multiErr.Errors { | |||||
| if multiErr2, ok := merr.(MultiError); ok { | |||||
| code = handleMultiError(multiErr2) | |||||
| } else { | |||||
| fmt.Fprintln(ErrWriter, merr) | |||||
| if exitErr, ok := merr.(ExitCoder); ok { | |||||
| code = exitErr.ExitCode() | |||||
| } | |||||
| } | |||||
| } | } | ||||
| OsExiter(1) | |||||
| return code | |||||
| } | } | ||||
| @@ -3,24 +3,24 @@ package cli | |||||
| import ( | import ( | ||||
| "flag" | "flag" | ||||
| "fmt" | "fmt" | ||||
| "os" | |||||
| "reflect" | "reflect" | ||||
| "runtime" | "runtime" | ||||
| "strconv" | "strconv" | ||||
| "strings" | "strings" | ||||
| "syscall" | |||||
| "time" | "time" | ||||
| ) | ) | ||||
| const defaultPlaceholder = "value" | const defaultPlaceholder = "value" | ||||
| // BashCompletionFlag enables bash-completion for all commands and subcommands | // BashCompletionFlag enables bash-completion for all commands and subcommands | ||||
| var BashCompletionFlag = BoolFlag{ | |||||
| var BashCompletionFlag Flag = BoolFlag{ | |||||
| Name: "generate-bash-completion", | Name: "generate-bash-completion", | ||||
| Hidden: true, | Hidden: true, | ||||
| } | } | ||||
| // VersionFlag prints the version for the application | // VersionFlag prints the version for the application | ||||
| var VersionFlag = BoolFlag{ | |||||
| var VersionFlag Flag = BoolFlag{ | |||||
| Name: "version, v", | Name: "version, v", | ||||
| Usage: "print the version", | Usage: "print the version", | ||||
| } | } | ||||
| @@ -28,7 +28,7 @@ var VersionFlag = BoolFlag{ | |||||
| // HelpFlag prints the help for all commands and subcommands | // HelpFlag prints the help for all commands and subcommands | ||||
| // Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand | // Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand | ||||
| // unless HideHelp is set to true) | // unless HideHelp is set to true) | ||||
| var HelpFlag = BoolFlag{ | |||||
| var HelpFlag Flag = BoolFlag{ | |||||
| Name: "help, h", | Name: "help, h", | ||||
| Usage: "show help", | Usage: "show help", | ||||
| } | } | ||||
| @@ -62,13 +62,29 @@ type Flag interface { | |||||
| GetName() string | GetName() string | ||||
| } | } | ||||
| func flagSet(name string, flags []Flag) *flag.FlagSet { | |||||
| // errorableFlag is an interface that allows us to return errors during apply | |||||
| // it allows flags defined in this library to return errors in a fashion backwards compatible | |||||
| // TODO remove in v2 and modify the existing Flag interface to return errors | |||||
| type errorableFlag interface { | |||||
| Flag | |||||
| ApplyWithError(*flag.FlagSet) error | |||||
| } | |||||
| func flagSet(name string, flags []Flag) (*flag.FlagSet, error) { | |||||
| set := flag.NewFlagSet(name, flag.ContinueOnError) | set := flag.NewFlagSet(name, flag.ContinueOnError) | ||||
| for _, f := range flags { | for _, f := range flags { | ||||
| f.Apply(set) | |||||
| //TODO remove in v2 when errorableFlag is removed | |||||
| if ef, ok := f.(errorableFlag); ok { | |||||
| if err := ef.ApplyWithError(set); err != nil { | |||||
| return nil, err | |||||
| } | |||||
| } else { | |||||
| f.Apply(set) | |||||
| } | |||||
| } | } | ||||
| return set | |||||
| return set, nil | |||||
| } | } | ||||
| func eachName(longName string, fn func(string)) { | func eachName(longName string, fn func(string)) { | ||||
| @@ -87,13 +103,22 @@ type Generic interface { | |||||
| // Apply takes the flagset and calls Set on the generic flag with the value | // Apply takes the flagset and calls Set on the generic flag with the value | ||||
| // provided by the user for parsing by the flag | // provided by the user for parsing by the flag | ||||
| // Ignores parsing errors | |||||
| func (f GenericFlag) Apply(set *flag.FlagSet) { | func (f GenericFlag) Apply(set *flag.FlagSet) { | ||||
| f.ApplyWithError(set) | |||||
| } | |||||
| // ApplyWithError takes the flagset and calls Set on the generic flag with the value | |||||
| // provided by the user for parsing by the flag | |||||
| func (f GenericFlag) ApplyWithError(set *flag.FlagSet) error { | |||||
| val := f.Value | val := f.Value | ||||
| if f.EnvVar != "" { | if f.EnvVar != "" { | ||||
| for _, envVar := range strings.Split(f.EnvVar, ",") { | for _, envVar := range strings.Split(f.EnvVar, ",") { | ||||
| envVar = strings.TrimSpace(envVar) | envVar = strings.TrimSpace(envVar) | ||||
| if envVal := os.Getenv(envVar); envVal != "" { | |||||
| val.Set(envVal) | |||||
| if envVal, ok := syscall.Getenv(envVar); ok { | |||||
| if err := val.Set(envVal); err != nil { | |||||
| return fmt.Errorf("could not parse %s as value for flag %s: %s", envVal, f.Name, err) | |||||
| } | |||||
| break | break | ||||
| } | } | ||||
| } | } | ||||
| @@ -102,9 +127,11 @@ func (f GenericFlag) Apply(set *flag.FlagSet) { | |||||
| eachName(f.Name, func(name string) { | eachName(f.Name, func(name string) { | ||||
| set.Var(f.Value, name, f.Usage) | set.Var(f.Value, name, f.Usage) | ||||
| }) | }) | ||||
| return nil | |||||
| } | } | ||||
| // StringSlice is an opaque type for []string to satisfy flag.Value | |||||
| // StringSlice is an opaque type for []string to satisfy flag.Value and flag.Getter | |||||
| type StringSlice []string | type StringSlice []string | ||||
| // Set appends the string value to the list of values | // Set appends the string value to the list of values | ||||
| @@ -123,16 +150,29 @@ func (f *StringSlice) Value() []string { | |||||
| return *f | return *f | ||||
| } | } | ||||
| // Get returns the slice of strings set by this flag | |||||
| func (f *StringSlice) Get() interface{} { | |||||
| return *f | |||||
| } | |||||
| // Apply populates the flag given the flag set and environment | // Apply populates the flag given the flag set and environment | ||||
| // Ignores errors | |||||
| func (f StringSliceFlag) Apply(set *flag.FlagSet) { | func (f StringSliceFlag) Apply(set *flag.FlagSet) { | ||||
| f.ApplyWithError(set) | |||||
| } | |||||
| // ApplyWithError populates the flag given the flag set and environment | |||||
| func (f StringSliceFlag) ApplyWithError(set *flag.FlagSet) error { | |||||
| if f.EnvVar != "" { | if f.EnvVar != "" { | ||||
| for _, envVar := range strings.Split(f.EnvVar, ",") { | for _, envVar := range strings.Split(f.EnvVar, ",") { | ||||
| envVar = strings.TrimSpace(envVar) | envVar = strings.TrimSpace(envVar) | ||||
| if envVal := os.Getenv(envVar); envVal != "" { | |||||
| if envVal, ok := syscall.Getenv(envVar); ok { | |||||
| newVal := &StringSlice{} | newVal := &StringSlice{} | ||||
| for _, s := range strings.Split(envVal, ",") { | for _, s := range strings.Split(envVal, ",") { | ||||
| s = strings.TrimSpace(s) | s = strings.TrimSpace(s) | ||||
| newVal.Set(s) | |||||
| if err := newVal.Set(s); err != nil { | |||||
| return fmt.Errorf("could not parse %s as string value for flag %s: %s", envVal, f.Name, err) | |||||
| } | |||||
| } | } | ||||
| f.Value = newVal | f.Value = newVal | ||||
| break | break | ||||
| @@ -146,9 +186,11 @@ func (f StringSliceFlag) Apply(set *flag.FlagSet) { | |||||
| } | } | ||||
| set.Var(f.Value, name, f.Usage) | set.Var(f.Value, name, f.Usage) | ||||
| }) | }) | ||||
| return nil | |||||
| } | } | ||||
| // IntSlice is an opaque type for []int to satisfy flag.Value | |||||
| // IntSlice is an opaque type for []int to satisfy flag.Value and flag.Getter | |||||
| type IntSlice []int | type IntSlice []int | ||||
| // Set parses the value into an integer and appends it to the list of values | // Set parses the value into an integer and appends it to the list of values | ||||
| @@ -171,18 +213,28 @@ func (f *IntSlice) Value() []int { | |||||
| return *f | return *f | ||||
| } | } | ||||
| // Get returns the slice of ints set by this flag | |||||
| func (f *IntSlice) Get() interface{} { | |||||
| return *f | |||||
| } | |||||
| // Apply populates the flag given the flag set and environment | // Apply populates the flag given the flag set and environment | ||||
| // Ignores errors | |||||
| func (f IntSliceFlag) Apply(set *flag.FlagSet) { | func (f IntSliceFlag) Apply(set *flag.FlagSet) { | ||||
| f.ApplyWithError(set) | |||||
| } | |||||
| // ApplyWithError populates the flag given the flag set and environment | |||||
| func (f IntSliceFlag) ApplyWithError(set *flag.FlagSet) error { | |||||
| if f.EnvVar != "" { | if f.EnvVar != "" { | ||||
| for _, envVar := range strings.Split(f.EnvVar, ",") { | for _, envVar := range strings.Split(f.EnvVar, ",") { | ||||
| envVar = strings.TrimSpace(envVar) | envVar = strings.TrimSpace(envVar) | ||||
| if envVal := os.Getenv(envVar); envVal != "" { | |||||
| if envVal, ok := syscall.Getenv(envVar); ok { | |||||
| newVal := &IntSlice{} | newVal := &IntSlice{} | ||||
| for _, s := range strings.Split(envVal, ",") { | for _, s := range strings.Split(envVal, ",") { | ||||
| s = strings.TrimSpace(s) | s = strings.TrimSpace(s) | ||||
| err := newVal.Set(s) | |||||
| if err != nil { | |||||
| fmt.Fprintf(ErrWriter, err.Error()) | |||||
| if err := newVal.Set(s); err != nil { | |||||
| return fmt.Errorf("could not parse %s as int slice value for flag %s: %s", envVal, f.Name, err) | |||||
| } | } | ||||
| } | } | ||||
| f.Value = newVal | f.Value = newVal | ||||
| @@ -197,9 +249,11 @@ func (f IntSliceFlag) Apply(set *flag.FlagSet) { | |||||
| } | } | ||||
| set.Var(f.Value, name, f.Usage) | set.Var(f.Value, name, f.Usage) | ||||
| }) | }) | ||||
| return nil | |||||
| } | } | ||||
| // Int64Slice is an opaque type for []int to satisfy flag.Value | |||||
| // Int64Slice is an opaque type for []int to satisfy flag.Value and flag.Getter | |||||
| type Int64Slice []int64 | type Int64Slice []int64 | ||||
| // Set parses the value into an integer and appends it to the list of values | // Set parses the value into an integer and appends it to the list of values | ||||
| @@ -222,18 +276,28 @@ func (f *Int64Slice) Value() []int64 { | |||||
| return *f | return *f | ||||
| } | } | ||||
| // Get returns the slice of ints set by this flag | |||||
| func (f *Int64Slice) Get() interface{} { | |||||
| return *f | |||||
| } | |||||
| // Apply populates the flag given the flag set and environment | // Apply populates the flag given the flag set and environment | ||||
| // Ignores errors | |||||
| func (f Int64SliceFlag) Apply(set *flag.FlagSet) { | func (f Int64SliceFlag) Apply(set *flag.FlagSet) { | ||||
| f.ApplyWithError(set) | |||||
| } | |||||
| // ApplyWithError populates the flag given the flag set and environment | |||||
| func (f Int64SliceFlag) ApplyWithError(set *flag.FlagSet) error { | |||||
| if f.EnvVar != "" { | if f.EnvVar != "" { | ||||
| for _, envVar := range strings.Split(f.EnvVar, ",") { | for _, envVar := range strings.Split(f.EnvVar, ",") { | ||||
| envVar = strings.TrimSpace(envVar) | envVar = strings.TrimSpace(envVar) | ||||
| if envVal := os.Getenv(envVar); envVal != "" { | |||||
| if envVal, ok := syscall.Getenv(envVar); ok { | |||||
| newVal := &Int64Slice{} | newVal := &Int64Slice{} | ||||
| for _, s := range strings.Split(envVal, ",") { | for _, s := range strings.Split(envVal, ",") { | ||||
| s = strings.TrimSpace(s) | s = strings.TrimSpace(s) | ||||
| err := newVal.Set(s) | |||||
| if err != nil { | |||||
| fmt.Fprintf(ErrWriter, err.Error()) | |||||
| if err := newVal.Set(s); err != nil { | |||||
| return fmt.Errorf("could not parse %s as int64 slice value for flag %s: %s", envVal, f.Name, err) | |||||
| } | } | ||||
| } | } | ||||
| f.Value = newVal | f.Value = newVal | ||||
| @@ -248,19 +312,33 @@ func (f Int64SliceFlag) Apply(set *flag.FlagSet) { | |||||
| } | } | ||||
| set.Var(f.Value, name, f.Usage) | set.Var(f.Value, name, f.Usage) | ||||
| }) | }) | ||||
| return nil | |||||
| } | } | ||||
| // Apply populates the flag given the flag set and environment | // Apply populates the flag given the flag set and environment | ||||
| // Ignores errors | |||||
| func (f BoolFlag) Apply(set *flag.FlagSet) { | func (f BoolFlag) Apply(set *flag.FlagSet) { | ||||
| f.ApplyWithError(set) | |||||
| } | |||||
| // ApplyWithError populates the flag given the flag set and environment | |||||
| func (f BoolFlag) ApplyWithError(set *flag.FlagSet) error { | |||||
| val := false | val := false | ||||
| if f.EnvVar != "" { | if f.EnvVar != "" { | ||||
| for _, envVar := range strings.Split(f.EnvVar, ",") { | for _, envVar := range strings.Split(f.EnvVar, ",") { | ||||
| envVar = strings.TrimSpace(envVar) | envVar = strings.TrimSpace(envVar) | ||||
| if envVal := os.Getenv(envVar); envVal != "" { | |||||
| if envVal, ok := syscall.Getenv(envVar); ok { | |||||
| if envVal == "" { | |||||
| val = false | |||||
| break | |||||
| } | |||||
| envValBool, err := strconv.ParseBool(envVal) | envValBool, err := strconv.ParseBool(envVal) | ||||
| if err == nil { | |||||
| val = envValBool | |||||
| if err != nil { | |||||
| return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err) | |||||
| } | } | ||||
| val = envValBool | |||||
| break | break | ||||
| } | } | ||||
| } | } | ||||
| @@ -273,20 +351,35 @@ func (f BoolFlag) Apply(set *flag.FlagSet) { | |||||
| } | } | ||||
| set.Bool(name, val, f.Usage) | set.Bool(name, val, f.Usage) | ||||
| }) | }) | ||||
| return nil | |||||
| } | } | ||||
| // Apply populates the flag given the flag set and environment | // Apply populates the flag given the flag set and environment | ||||
| // Ignores errors | |||||
| func (f BoolTFlag) Apply(set *flag.FlagSet) { | func (f BoolTFlag) Apply(set *flag.FlagSet) { | ||||
| f.ApplyWithError(set) | |||||
| } | |||||
| // ApplyWithError populates the flag given the flag set and environment | |||||
| func (f BoolTFlag) ApplyWithError(set *flag.FlagSet) error { | |||||
| val := true | val := true | ||||
| if f.EnvVar != "" { | if f.EnvVar != "" { | ||||
| for _, envVar := range strings.Split(f.EnvVar, ",") { | for _, envVar := range strings.Split(f.EnvVar, ",") { | ||||
| envVar = strings.TrimSpace(envVar) | envVar = strings.TrimSpace(envVar) | ||||
| if envVal := os.Getenv(envVar); envVal != "" { | |||||
| envValBool, err := strconv.ParseBool(envVal) | |||||
| if err == nil { | |||||
| val = envValBool | |||||
| if envVal, ok := syscall.Getenv(envVar); ok { | |||||
| if envVal == "" { | |||||
| val = false | |||||
| break | break | ||||
| } | } | ||||
| envValBool, err := strconv.ParseBool(envVal) | |||||
| if err != nil { | |||||
| return fmt.Errorf("could not parse %s as bool value for flag %s: %s", envVal, f.Name, err) | |||||
| } | |||||
| val = envValBool | |||||
| break | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -298,14 +391,22 @@ func (f BoolTFlag) Apply(set *flag.FlagSet) { | |||||
| } | } | ||||
| set.Bool(name, val, f.Usage) | set.Bool(name, val, f.Usage) | ||||
| }) | }) | ||||
| return nil | |||||
| } | } | ||||
| // Apply populates the flag given the flag set and environment | // Apply populates the flag given the flag set and environment | ||||
| // Ignores errors | |||||
| func (f StringFlag) Apply(set *flag.FlagSet) { | func (f StringFlag) Apply(set *flag.FlagSet) { | ||||
| f.ApplyWithError(set) | |||||
| } | |||||
| // ApplyWithError populates the flag given the flag set and environment | |||||
| func (f StringFlag) ApplyWithError(set *flag.FlagSet) error { | |||||
| if f.EnvVar != "" { | if f.EnvVar != "" { | ||||
| for _, envVar := range strings.Split(f.EnvVar, ",") { | for _, envVar := range strings.Split(f.EnvVar, ",") { | ||||
| envVar = strings.TrimSpace(envVar) | envVar = strings.TrimSpace(envVar) | ||||
| if envVal := os.Getenv(envVar); envVal != "" { | |||||
| if envVal, ok := syscall.Getenv(envVar); ok { | |||||
| f.Value = envVal | f.Value = envVal | ||||
| break | break | ||||
| } | } | ||||
| @@ -319,19 +420,28 @@ func (f StringFlag) Apply(set *flag.FlagSet) { | |||||
| } | } | ||||
| set.String(name, f.Value, f.Usage) | set.String(name, f.Value, f.Usage) | ||||
| }) | }) | ||||
| return nil | |||||
| } | } | ||||
| // Apply populates the flag given the flag set and environment | // Apply populates the flag given the flag set and environment | ||||
| // Ignores errors | |||||
| func (f IntFlag) Apply(set *flag.FlagSet) { | func (f IntFlag) Apply(set *flag.FlagSet) { | ||||
| f.ApplyWithError(set) | |||||
| } | |||||
| // ApplyWithError populates the flag given the flag set and environment | |||||
| func (f IntFlag) ApplyWithError(set *flag.FlagSet) error { | |||||
| if f.EnvVar != "" { | if f.EnvVar != "" { | ||||
| for _, envVar := range strings.Split(f.EnvVar, ",") { | for _, envVar := range strings.Split(f.EnvVar, ",") { | ||||
| envVar = strings.TrimSpace(envVar) | envVar = strings.TrimSpace(envVar) | ||||
| if envVal := os.Getenv(envVar); envVal != "" { | |||||
| if envVal, ok := syscall.Getenv(envVar); ok { | |||||
| envValInt, err := strconv.ParseInt(envVal, 0, 64) | envValInt, err := strconv.ParseInt(envVal, 0, 64) | ||||
| if err == nil { | |||||
| f.Value = int(envValInt) | |||||
| break | |||||
| if err != nil { | |||||
| return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) | |||||
| } | } | ||||
| f.Value = int(envValInt) | |||||
| break | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -343,19 +453,29 @@ func (f IntFlag) Apply(set *flag.FlagSet) { | |||||
| } | } | ||||
| set.Int(name, f.Value, f.Usage) | set.Int(name, f.Value, f.Usage) | ||||
| }) | }) | ||||
| return nil | |||||
| } | } | ||||
| // Apply populates the flag given the flag set and environment | // Apply populates the flag given the flag set and environment | ||||
| // Ignores errors | |||||
| func (f Int64Flag) Apply(set *flag.FlagSet) { | func (f Int64Flag) Apply(set *flag.FlagSet) { | ||||
| f.ApplyWithError(set) | |||||
| } | |||||
| // ApplyWithError populates the flag given the flag set and environment | |||||
| func (f Int64Flag) ApplyWithError(set *flag.FlagSet) error { | |||||
| if f.EnvVar != "" { | if f.EnvVar != "" { | ||||
| for _, envVar := range strings.Split(f.EnvVar, ",") { | for _, envVar := range strings.Split(f.EnvVar, ",") { | ||||
| envVar = strings.TrimSpace(envVar) | envVar = strings.TrimSpace(envVar) | ||||
| if envVal := os.Getenv(envVar); envVal != "" { | |||||
| if envVal, ok := syscall.Getenv(envVar); ok { | |||||
| envValInt, err := strconv.ParseInt(envVal, 0, 64) | envValInt, err := strconv.ParseInt(envVal, 0, 64) | ||||
| if err == nil { | |||||
| f.Value = envValInt | |||||
| break | |||||
| if err != nil { | |||||
| return fmt.Errorf("could not parse %s as int value for flag %s: %s", envVal, f.Name, err) | |||||
| } | } | ||||
| f.Value = envValInt | |||||
| break | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -367,19 +487,29 @@ func (f Int64Flag) Apply(set *flag.FlagSet) { | |||||
| } | } | ||||
| set.Int64(name, f.Value, f.Usage) | set.Int64(name, f.Value, f.Usage) | ||||
| }) | }) | ||||
| return nil | |||||
| } | } | ||||
| // Apply populates the flag given the flag set and environment | // Apply populates the flag given the flag set and environment | ||||
| // Ignores errors | |||||
| func (f UintFlag) Apply(set *flag.FlagSet) { | func (f UintFlag) Apply(set *flag.FlagSet) { | ||||
| f.ApplyWithError(set) | |||||
| } | |||||
| // ApplyWithError populates the flag given the flag set and environment | |||||
| func (f UintFlag) ApplyWithError(set *flag.FlagSet) error { | |||||
| if f.EnvVar != "" { | if f.EnvVar != "" { | ||||
| for _, envVar := range strings.Split(f.EnvVar, ",") { | for _, envVar := range strings.Split(f.EnvVar, ",") { | ||||
| envVar = strings.TrimSpace(envVar) | envVar = strings.TrimSpace(envVar) | ||||
| if envVal := os.Getenv(envVar); envVal != "" { | |||||
| if envVal, ok := syscall.Getenv(envVar); ok { | |||||
| envValInt, err := strconv.ParseUint(envVal, 0, 64) | envValInt, err := strconv.ParseUint(envVal, 0, 64) | ||||
| if err == nil { | |||||
| f.Value = uint(envValInt) | |||||
| break | |||||
| if err != nil { | |||||
| return fmt.Errorf("could not parse %s as uint value for flag %s: %s", envVal, f.Name, err) | |||||
| } | } | ||||
| f.Value = uint(envValInt) | |||||
| break | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -391,19 +521,29 @@ func (f UintFlag) Apply(set *flag.FlagSet) { | |||||
| } | } | ||||
| set.Uint(name, f.Value, f.Usage) | set.Uint(name, f.Value, f.Usage) | ||||
| }) | }) | ||||
| return nil | |||||
| } | } | ||||
| // Apply populates the flag given the flag set and environment | // Apply populates the flag given the flag set and environment | ||||
| // Ignores errors | |||||
| func (f Uint64Flag) Apply(set *flag.FlagSet) { | func (f Uint64Flag) Apply(set *flag.FlagSet) { | ||||
| f.ApplyWithError(set) | |||||
| } | |||||
| // ApplyWithError populates the flag given the flag set and environment | |||||
| func (f Uint64Flag) ApplyWithError(set *flag.FlagSet) error { | |||||
| if f.EnvVar != "" { | if f.EnvVar != "" { | ||||
| for _, envVar := range strings.Split(f.EnvVar, ",") { | for _, envVar := range strings.Split(f.EnvVar, ",") { | ||||
| envVar = strings.TrimSpace(envVar) | envVar = strings.TrimSpace(envVar) | ||||
| if envVal := os.Getenv(envVar); envVal != "" { | |||||
| if envVal, ok := syscall.Getenv(envVar); ok { | |||||
| envValInt, err := strconv.ParseUint(envVal, 0, 64) | envValInt, err := strconv.ParseUint(envVal, 0, 64) | ||||
| if err == nil { | |||||
| f.Value = uint64(envValInt) | |||||
| break | |||||
| if err != nil { | |||||
| return fmt.Errorf("could not parse %s as uint64 value for flag %s: %s", envVal, f.Name, err) | |||||
| } | } | ||||
| f.Value = uint64(envValInt) | |||||
| break | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -415,19 +555,29 @@ func (f Uint64Flag) Apply(set *flag.FlagSet) { | |||||
| } | } | ||||
| set.Uint64(name, f.Value, f.Usage) | set.Uint64(name, f.Value, f.Usage) | ||||
| }) | }) | ||||
| return nil | |||||
| } | } | ||||
| // Apply populates the flag given the flag set and environment | // Apply populates the flag given the flag set and environment | ||||
| // Ignores errors | |||||
| func (f DurationFlag) Apply(set *flag.FlagSet) { | func (f DurationFlag) Apply(set *flag.FlagSet) { | ||||
| f.ApplyWithError(set) | |||||
| } | |||||
| // ApplyWithError populates the flag given the flag set and environment | |||||
| func (f DurationFlag) ApplyWithError(set *flag.FlagSet) error { | |||||
| if f.EnvVar != "" { | if f.EnvVar != "" { | ||||
| for _, envVar := range strings.Split(f.EnvVar, ",") { | for _, envVar := range strings.Split(f.EnvVar, ",") { | ||||
| envVar = strings.TrimSpace(envVar) | envVar = strings.TrimSpace(envVar) | ||||
| if envVal := os.Getenv(envVar); envVal != "" { | |||||
| if envVal, ok := syscall.Getenv(envVar); ok { | |||||
| envValDuration, err := time.ParseDuration(envVal) | envValDuration, err := time.ParseDuration(envVal) | ||||
| if err == nil { | |||||
| f.Value = envValDuration | |||||
| break | |||||
| if err != nil { | |||||
| return fmt.Errorf("could not parse %s as duration for flag %s: %s", envVal, f.Name, err) | |||||
| } | } | ||||
| f.Value = envValDuration | |||||
| break | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -439,18 +589,29 @@ func (f DurationFlag) Apply(set *flag.FlagSet) { | |||||
| } | } | ||||
| set.Duration(name, f.Value, f.Usage) | set.Duration(name, f.Value, f.Usage) | ||||
| }) | }) | ||||
| return nil | |||||
| } | } | ||||
| // Apply populates the flag given the flag set and environment | // Apply populates the flag given the flag set and environment | ||||
| // Ignores errors | |||||
| func (f Float64Flag) Apply(set *flag.FlagSet) { | func (f Float64Flag) Apply(set *flag.FlagSet) { | ||||
| f.ApplyWithError(set) | |||||
| } | |||||
| // ApplyWithError populates the flag given the flag set and environment | |||||
| func (f Float64Flag) ApplyWithError(set *flag.FlagSet) error { | |||||
| if f.EnvVar != "" { | if f.EnvVar != "" { | ||||
| for _, envVar := range strings.Split(f.EnvVar, ",") { | for _, envVar := range strings.Split(f.EnvVar, ",") { | ||||
| envVar = strings.TrimSpace(envVar) | envVar = strings.TrimSpace(envVar) | ||||
| if envVal := os.Getenv(envVar); envVal != "" { | |||||
| if envVal, ok := syscall.Getenv(envVar); ok { | |||||
| envValFloat, err := strconv.ParseFloat(envVal, 10) | envValFloat, err := strconv.ParseFloat(envVal, 10) | ||||
| if err == nil { | |||||
| f.Value = float64(envValFloat) | |||||
| if err != nil { | |||||
| return fmt.Errorf("could not parse %s as float64 value for flag %s: %s", envVal, f.Name, err) | |||||
| } | } | ||||
| f.Value = float64(envValFloat) | |||||
| break | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -462,12 +623,15 @@ func (f Float64Flag) Apply(set *flag.FlagSet) { | |||||
| } | } | ||||
| set.Float64(name, f.Value, f.Usage) | set.Float64(name, f.Value, f.Usage) | ||||
| }) | }) | ||||
| return nil | |||||
| } | } | ||||
| func visibleFlags(fl []Flag) []Flag { | func visibleFlags(fl []Flag) []Flag { | ||||
| visible := []Flag{} | visible := []Flag{} | ||||
| for _, flag := range fl { | for _, flag := range fl { | ||||
| if !flagValue(flag).FieldByName("Hidden").Bool() { | |||||
| field := flagValue(flag).FieldByName("Hidden") | |||||
| if !field.IsValid() || !field.Bool() { | |||||
| visible = append(visible, flag) | visible = append(visible, flag) | ||||
| } | } | ||||
| } | } | ||||
| @@ -560,9 +724,8 @@ func stringifyFlag(f Flag) string { | |||||
| needsPlaceholder := false | needsPlaceholder := false | ||||
| defaultValueString := "" | defaultValueString := "" | ||||
| val := fv.FieldByName("Value") | |||||
| if val.IsValid() { | |||||
| if val := fv.FieldByName("Value"); val.IsValid() { | |||||
| needsPlaceholder = true | needsPlaceholder = true | ||||
| defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface()) | defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface()) | ||||
| @@ -232,6 +232,13 @@ def _write_altsrc_flag_types(outfile, types): | |||||
| f.set = set | f.set = set | ||||
| f.{name}Flag.Apply(set) | f.{name}Flag.Apply(set) | ||||
| }} | }} | ||||
| // ApplyWithError saves the flagSet for later usage calls, then calls the | |||||
| // wrapped {name}Flag.ApplyWithError | |||||
| func (f *{name}Flag) ApplyWithError(set *flag.FlagSet) error {{ | |||||
| f.set = set | |||||
| return f.{name}Flag.ApplyWithError(set) | |||||
| }} | |||||
| """.format(**typedef)) | """.format(**typedef)) | ||||
| @@ -13,7 +13,7 @@ import ( | |||||
| // cli.go uses text/template to render templates. You can | // cli.go uses text/template to render templates. You can | ||||
| // render custom help text by setting this variable. | // render custom help text by setting this variable. | ||||
| var AppHelpTemplate = `NAME: | var AppHelpTemplate = `NAME: | ||||
| {{.Name}} - {{.Usage}} | |||||
| {{.Name}}{{if .Usage}} - {{.Usage}}{{end}} | |||||
| 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 .Version}}{{if not .HideVersion}} | {{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}} | ||||
| @@ -47,7 +47,7 @@ var CommandHelpTemplate = `NAME: | |||||
| {{.HelpName}} - {{.Usage}} | {{.HelpName}} - {{.Usage}} | ||||
| USAGE: | USAGE: | ||||
| {{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Category}} | |||||
| {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Category}} | |||||
| CATEGORY: | CATEGORY: | ||||
| {{.Category}}{{end}}{{if .Description}} | {{.Category}}{{end}}{{if .Description}} | ||||
| @@ -64,10 +64,10 @@ OPTIONS: | |||||
| // cli.go uses text/template to render templates. You can | // cli.go uses text/template to render templates. You can | ||||
| // render custom help text by setting this variable. | // render custom help text by setting this variable. | ||||
| var SubcommandHelpTemplate = `NAME: | var SubcommandHelpTemplate = `NAME: | ||||
| {{.HelpName}} - {{.Usage}} | |||||
| {{.HelpName}} - {{if .Description}}{{.Description}}{{else}}{{.Usage}}{{end}} | |||||
| USAGE: | USAGE: | ||||
| {{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} | |||||
| {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}} | |||||
| COMMANDS:{{range .VisibleCategories}}{{if .Name}} | COMMANDS:{{range .VisibleCategories}}{{if .Name}} | ||||
| {{.Name}}:{{end}}{{range .VisibleCommands}} | {{.Name}}:{{end}}{{range .VisibleCommands}} | ||||
| @@ -112,17 +112,42 @@ var helpSubcommand = Command{ | |||||
| // Prints help for the App or Command | // Prints help for the App or Command | ||||
| type helpPrinter func(w io.Writer, templ string, data interface{}) | type helpPrinter func(w io.Writer, templ string, data interface{}) | ||||
| // Prints help for the App or Command with custom template function. | |||||
| type helpPrinterCustom func(w io.Writer, templ string, data interface{}, customFunc map[string]interface{}) | |||||
| // HelpPrinter is a function that writes the help output. If not set a default | // HelpPrinter is a function that writes the help output. If not set a default | ||||
| // is used. The function signature is: | // is used. The function signature is: | ||||
| // func(w io.Writer, templ string, data interface{}) | // func(w io.Writer, templ string, data interface{}) | ||||
| var HelpPrinter helpPrinter = printHelp | var HelpPrinter helpPrinter = printHelp | ||||
| // HelpPrinterCustom is same as HelpPrinter but | |||||
| // takes a custom function for template function map. | |||||
| var HelpPrinterCustom helpPrinterCustom = printHelpCustom | |||||
| // VersionPrinter prints the version for the App | // VersionPrinter prints the version for the App | ||||
| var VersionPrinter = printVersion | var VersionPrinter = printVersion | ||||
| // ShowAppHelpAndExit - Prints the list of subcommands for the app and exits with exit code. | |||||
| func ShowAppHelpAndExit(c *Context, exitCode int) { | |||||
| ShowAppHelp(c) | |||||
| os.Exit(exitCode) | |||||
| } | |||||
| // ShowAppHelp is an action that displays the help. | // ShowAppHelp is an action that displays the help. | ||||
| func ShowAppHelp(c *Context) error { | |||||
| HelpPrinter(c.App.Writer, AppHelpTemplate, c.App) | |||||
| func ShowAppHelp(c *Context) (err error) { | |||||
| if c.App.CustomAppHelpTemplate == "" { | |||||
| HelpPrinter(c.App.Writer, AppHelpTemplate, c.App) | |||||
| return | |||||
| } | |||||
| customAppData := func() map[string]interface{} { | |||||
| if c.App.ExtraInfo == nil { | |||||
| return nil | |||||
| } | |||||
| return map[string]interface{}{ | |||||
| "ExtraInfo": c.App.ExtraInfo, | |||||
| } | |||||
| } | |||||
| HelpPrinterCustom(c.App.Writer, c.App.CustomAppHelpTemplate, c.App, customAppData()) | |||||
| return nil | return nil | ||||
| } | } | ||||
| @@ -138,6 +163,12 @@ func DefaultAppComplete(c *Context) { | |||||
| } | } | ||||
| } | } | ||||
| // ShowCommandHelpAndExit - exits with code after showing help | |||||
| func ShowCommandHelpAndExit(c *Context, command string, code int) { | |||||
| ShowCommandHelp(c, command) | |||||
| os.Exit(code) | |||||
| } | |||||
| // ShowCommandHelp prints help for the given command | // ShowCommandHelp prints help for the given command | ||||
| func ShowCommandHelp(ctx *Context, command string) error { | func ShowCommandHelp(ctx *Context, command string) error { | ||||
| // show the subcommand help for a command with subcommands | // show the subcommand help for a command with subcommands | ||||
| @@ -148,7 +179,11 @@ func ShowCommandHelp(ctx *Context, command string) error { | |||||
| for _, c := range ctx.App.Commands { | for _, c := range ctx.App.Commands { | ||||
| if c.HasName(command) { | if c.HasName(command) { | ||||
| HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c) | |||||
| if c.CustomHelpTemplate != "" { | |||||
| HelpPrinterCustom(ctx.App.Writer, c.CustomHelpTemplate, c, nil) | |||||
| } else { | |||||
| HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c) | |||||
| } | |||||
| return nil | return nil | ||||
| } | } | ||||
| } | } | ||||
| @@ -191,10 +226,15 @@ func ShowCommandCompletions(ctx *Context, command string) { | |||||
| } | } | ||||
| } | } | ||||
| func printHelp(out io.Writer, templ string, data interface{}) { | |||||
| func printHelpCustom(out io.Writer, templ string, data interface{}, customFunc map[string]interface{}) { | |||||
| funcMap := template.FuncMap{ | funcMap := template.FuncMap{ | ||||
| "join": strings.Join, | "join": strings.Join, | ||||
| } | } | ||||
| if customFunc != nil { | |||||
| for key, value := range customFunc { | |||||
| funcMap[key] = value | |||||
| } | |||||
| } | |||||
| w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0) | w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0) | ||||
| t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) | t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) | ||||
| @@ -210,10 +250,14 @@ func printHelp(out io.Writer, templ string, data interface{}) { | |||||
| w.Flush() | w.Flush() | ||||
| } | } | ||||
| func printHelp(out io.Writer, templ string, data interface{}) { | |||||
| printHelpCustom(out, templ, data, nil) | |||||
| } | |||||
| func checkVersion(c *Context) bool { | func checkVersion(c *Context) bool { | ||||
| found := false | found := false | ||||
| if VersionFlag.Name != "" { | |||||
| eachName(VersionFlag.Name, func(name string) { | |||||
| if VersionFlag.GetName() != "" { | |||||
| eachName(VersionFlag.GetName(), func(name string) { | |||||
| if c.GlobalBool(name) || c.Bool(name) { | if c.GlobalBool(name) || c.Bool(name) { | ||||
| found = true | found = true | ||||
| } | } | ||||
| @@ -224,8 +268,8 @@ func checkVersion(c *Context) bool { | |||||
| func checkHelp(c *Context) bool { | func checkHelp(c *Context) bool { | ||||
| found := false | found := false | ||||
| if HelpFlag.Name != "" { | |||||
| eachName(HelpFlag.Name, func(name string) { | |||||
| if HelpFlag.GetName() != "" { | |||||
| eachName(HelpFlag.GetName(), func(name string) { | |||||
| if c.GlobalBool(name) || c.Bool(name) { | if c.GlobalBool(name) || c.Bool(name) { | ||||
| found = true | found = true | ||||
| } | } | ||||
| @@ -252,20 +296,43 @@ func checkSubcommandHelp(c *Context) bool { | |||||
| return false | return false | ||||
| } | } | ||||
| func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) { | |||||
| if !a.EnableBashCompletion { | |||||
| return false, arguments | |||||
| } | |||||
| pos := len(arguments) - 1 | |||||
| lastArg := arguments[pos] | |||||
| if lastArg != "--"+BashCompletionFlag.GetName() { | |||||
| return false, arguments | |||||
| } | |||||
| return true, arguments[:pos] | |||||
| } | |||||
| func checkCompletions(c *Context) bool { | func checkCompletions(c *Context) bool { | ||||
| if (c.GlobalBool(BashCompletionFlag.Name) || c.Bool(BashCompletionFlag.Name)) && c.App.EnableBashCompletion { | |||||
| ShowCompletions(c) | |||||
| return true | |||||
| if !c.shellComplete { | |||||
| return false | |||||
| } | } | ||||
| return false | |||||
| if args := c.Args(); args.Present() { | |||||
| name := args.First() | |||||
| if cmd := c.App.Command(name); cmd != nil { | |||||
| // let the command handle the completion | |||||
| return false | |||||
| } | |||||
| } | |||||
| ShowCompletions(c) | |||||
| return true | |||||
| } | } | ||||
| func checkCommandCompletions(c *Context, name string) bool { | func checkCommandCompletions(c *Context, name string) bool { | ||||
| if c.Bool(BashCompletionFlag.Name) && c.App.EnableBashCompletion { | |||||
| ShowCommandCompletions(c, name) | |||||
| return true | |||||
| if !c.shellComplete { | |||||
| return false | |||||
| } | } | ||||
| return false | |||||
| ShowCommandCompletions(c, name) | |||||
| return true | |||||
| } | } | ||||
| @@ -321,7 +321,7 @@ github.com/syndtr/goleveldb/leveldb/util | |||||
| github.com/tinylib/msgp/msgp | github.com/tinylib/msgp/msgp | ||||
| # github.com/tstranex/u2f v1.0.0 | # github.com/tstranex/u2f v1.0.0 | ||||
| github.com/tstranex/u2f | github.com/tstranex/u2f | ||||
| # github.com/urfave/cli v0.0.0-20161102131801-d86a009f5e13 | |||||
| # github.com/urfave/cli v1.20.0 | |||||
| github.com/urfave/cli | github.com/urfave/cli | ||||
| # github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621 | # github.com/willf/bitset v0.0.0-20180426185212-8ce1146b8621 | ||||
| github.com/willf/bitset | github.com/willf/bitset | ||||