Merge branch 'v2' into show-bool-default
This commit is contained in:
commit
3b03164c92
@ -14,6 +14,8 @@ matrix:
|
|||||||
allow_failures:
|
allow_failures:
|
||||||
- go: master
|
- go: master
|
||||||
include:
|
include:
|
||||||
|
- go: 1.6.2
|
||||||
|
os: osx
|
||||||
- go: 1.1.2
|
- go: 1.1.2
|
||||||
install: go get -v .
|
install: go get -v .
|
||||||
before_script: echo skipping gfmxr on $TRAVIS_GO_VERSION
|
before_script: echo skipping gfmxr on $TRAVIS_GO_VERSION
|
||||||
@ -22,7 +24,7 @@ matrix:
|
|||||||
- ./runtests test
|
- ./runtests test
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- go get github.com/meatballhat/gfmxr/...
|
- go get github.com/urfave/gfmxr/...
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- ./runtests vet
|
- ./runtests vet
|
||||||
|
54
CHANGELOG.md
54
CHANGELOG.md
@ -34,6 +34,8 @@
|
|||||||
## [Unreleased] - (1.x series)
|
## [Unreleased] - (1.x series)
|
||||||
### Added
|
### Added
|
||||||
- `./runtests` test runner with coverage tracking by default
|
- `./runtests` test runner with coverage tracking by default
|
||||||
|
- testing on OS X
|
||||||
|
- testing on Windows
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Printing of command aliases in help text
|
- Printing of command aliases in help text
|
||||||
@ -57,7 +59,7 @@
|
|||||||
makes it easier to script around apps built using `cli` since they can trust
|
makes it easier to script around apps built using `cli` since they can trust
|
||||||
that a 0 exit code indicated a successful execution.
|
that a 0 exit code indicated a successful execution.
|
||||||
- cleanups based on [Go Report Card
|
- cleanups based on [Go Report Card
|
||||||
feedback](https://goreportcard.com/report/github.com/codegangsta/cli)
|
feedback](https://goreportcard.com/report/github.com/urfave/cli)
|
||||||
|
|
||||||
## [1.16.0] - 2016-05-02
|
## [1.16.0] - 2016-05-02
|
||||||
### Added
|
### Added
|
||||||
@ -317,28 +319,28 @@ signature of `func(*cli.Context) error`, as defined by `cli.ActionFunc`.
|
|||||||
### Added
|
### Added
|
||||||
- Initial implementation.
|
- Initial implementation.
|
||||||
|
|
||||||
[Unreleased]: https://github.com/codegangsta/cli/compare/v1.17.0...HEAD
|
[Unreleased]: https://github.com/urfave/cli/compare/v1.17.0...HEAD
|
||||||
[1.17.0]: https://github.com/codegangsta/cli/compare/v1.16.0...v1.17.0
|
[1.17.0]: https://github.com/urfave/cli/compare/v1.16.0...v1.17.0
|
||||||
[1.16.0]: https://github.com/codegangsta/cli/compare/v1.15.0...v1.16.0
|
[1.16.0]: https://github.com/urfave/cli/compare/v1.15.0...v1.16.0
|
||||||
[1.15.0]: https://github.com/codegangsta/cli/compare/v1.14.0...v1.15.0
|
[1.15.0]: https://github.com/urfave/cli/compare/v1.14.0...v1.15.0
|
||||||
[1.14.0]: https://github.com/codegangsta/cli/compare/v1.13.0...v1.14.0
|
[1.14.0]: https://github.com/urfave/cli/compare/v1.13.0...v1.14.0
|
||||||
[1.13.0]: https://github.com/codegangsta/cli/compare/v1.12.0...v1.13.0
|
[1.13.0]: https://github.com/urfave/cli/compare/v1.12.0...v1.13.0
|
||||||
[1.12.0]: https://github.com/codegangsta/cli/compare/v1.11.1...v1.12.0
|
[1.12.0]: https://github.com/urfave/cli/compare/v1.11.1...v1.12.0
|
||||||
[1.11.1]: https://github.com/codegangsta/cli/compare/v1.11.0...v1.11.1
|
[1.11.1]: https://github.com/urfave/cli/compare/v1.11.0...v1.11.1
|
||||||
[1.11.0]: https://github.com/codegangsta/cli/compare/v1.10.2...v1.11.0
|
[1.11.0]: https://github.com/urfave/cli/compare/v1.10.2...v1.11.0
|
||||||
[1.10.2]: https://github.com/codegangsta/cli/compare/v1.10.1...v1.10.2
|
[1.10.2]: https://github.com/urfave/cli/compare/v1.10.1...v1.10.2
|
||||||
[1.10.1]: https://github.com/codegangsta/cli/compare/v1.10.0...v1.10.1
|
[1.10.1]: https://github.com/urfave/cli/compare/v1.10.0...v1.10.1
|
||||||
[1.10.0]: https://github.com/codegangsta/cli/compare/v1.9.0...v1.10.0
|
[1.10.0]: https://github.com/urfave/cli/compare/v1.9.0...v1.10.0
|
||||||
[1.9.0]: https://github.com/codegangsta/cli/compare/v1.8.0...v1.9.0
|
[1.9.0]: https://github.com/urfave/cli/compare/v1.8.0...v1.9.0
|
||||||
[1.8.0]: https://github.com/codegangsta/cli/compare/v1.7.1...v1.8.0
|
[1.8.0]: https://github.com/urfave/cli/compare/v1.7.1...v1.8.0
|
||||||
[1.7.1]: https://github.com/codegangsta/cli/compare/v1.7.0...v1.7.1
|
[1.7.1]: https://github.com/urfave/cli/compare/v1.7.0...v1.7.1
|
||||||
[1.7.0]: https://github.com/codegangsta/cli/compare/v1.6.0...v1.7.0
|
[1.7.0]: https://github.com/urfave/cli/compare/v1.6.0...v1.7.0
|
||||||
[1.6.0]: https://github.com/codegangsta/cli/compare/v1.5.0...v1.6.0
|
[1.6.0]: https://github.com/urfave/cli/compare/v1.5.0...v1.6.0
|
||||||
[1.5.0]: https://github.com/codegangsta/cli/compare/v1.4.1...v1.5.0
|
[1.5.0]: https://github.com/urfave/cli/compare/v1.4.1...v1.5.0
|
||||||
[1.4.1]: https://github.com/codegangsta/cli/compare/v1.4.0...v1.4.1
|
[1.4.1]: https://github.com/urfave/cli/compare/v1.4.0...v1.4.1
|
||||||
[1.4.0]: https://github.com/codegangsta/cli/compare/v1.3.1...v1.4.0
|
[1.4.0]: https://github.com/urfave/cli/compare/v1.3.1...v1.4.0
|
||||||
[1.3.1]: https://github.com/codegangsta/cli/compare/v1.3.0...v1.3.1
|
[1.3.1]: https://github.com/urfave/cli/compare/v1.3.0...v1.3.1
|
||||||
[1.3.0]: https://github.com/codegangsta/cli/compare/v1.2.0...v1.3.0
|
[1.3.0]: https://github.com/urfave/cli/compare/v1.2.0...v1.3.0
|
||||||
[1.2.0]: https://github.com/codegangsta/cli/compare/v1.1.0...v1.2.0
|
[1.2.0]: https://github.com/urfave/cli/compare/v1.1.0...v1.2.0
|
||||||
[1.1.0]: https://github.com/codegangsta/cli/compare/v1.0.0...v1.1.0
|
[1.1.0]: https://github.com/urfave/cli/compare/v1.0.0...v1.1.0
|
||||||
[1.0.0]: https://github.com/codegangsta/cli/compare/v0.1.0...v1.0.0
|
[1.0.0]: https://github.com/urfave/cli/compare/v0.1.0...v1.0.0
|
||||||
|
123
README.md
123
README.md
@ -1,13 +1,18 @@
|
|||||||
[![Build Status](https://travis-ci.org/codegangsta/cli.svg?branch=master)](https://travis-ci.org/codegangsta/cli)
|
[![Build Status](https://travis-ci.org/urfave/cli.svg?branch=master)](https://travis-ci.org/urfave/cli)
|
||||||
[![GoDoc](https://godoc.org/github.com/codegangsta/cli?status.svg)](https://godoc.org/github.com/codegangsta/cli)
|
[![Windows Build Status](https://ci.appveyor.com/api/projects/status/rtgk5xufi932pb2v?svg=true)](https://ci.appveyor.com/project/meatballhat/cli)
|
||||||
[![codebeat](https://codebeat.co/badges/0a8f30aa-f975-404b-b878-5fab3ae1cc5f)](https://codebeat.co/projects/github-com-codegangsta-cli)
|
[![GoDoc](https://godoc.org/github.com/urfave/cli?status.svg)](https://godoc.org/github.com/urfave/cli)
|
||||||
[![Go Report Card](https://goreportcard.com/badge/codegangsta/cli)](https://goreportcard.com/report/codegangsta/cli)
|
[![codebeat](https://codebeat.co/badges/0a8f30aa-f975-404b-b878-5fab3ae1cc5f)](https://codebeat.co/projects/github-com-urfave-cli)
|
||||||
[![top level coverage](https://gocover.io/_badge/github.com/codegangsta/cli?0 "top level coverage")](http://gocover.io/github.com/codegangsta/cli) /
|
[![Go Report Card](https://goreportcard.com/badge/urfave/cli)](https://goreportcard.com/report/urfave/cli)
|
||||||
[![altsrc coverage](https://gocover.io/_badge/github.com/codegangsta/cli/altsrc?0 "altsrc coverage")](http://gocover.io/github.com/codegangsta/cli/altsrc)
|
[![top level coverage](https://gocover.io/_badge/github.com/urfave/cli?0 "top level coverage")](http://gocover.io/github.com/urfave/cli) /
|
||||||
|
[![altsrc coverage](https://gocover.io/_badge/github.com/urfave/cli/altsrc?0 "altsrc coverage")](http://gocover.io/github.com/urfave/cli/altsrc)
|
||||||
|
|
||||||
|
|
||||||
# cli
|
# cli
|
||||||
|
|
||||||
|
**Notice:** This is the library formally known as
|
||||||
|
`github.com/codegangsta/cli` -- Github will automatically redirect requests
|
||||||
|
to this repository, but we recommend updating your references for clarity.
|
||||||
|
|
||||||
cli is a simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way.
|
cli is a simple, fast, and fun package for building command line apps in Go. The goal is to enable developers to write fast and distributable command line applications in an expressive way.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
@ -25,7 +30,7 @@ instructions](http://golang.org/doc/install.html).
|
|||||||
|
|
||||||
To install cli, simply run:
|
To install cli, simply run:
|
||||||
```
|
```
|
||||||
$ go get github.com/codegangsta/cli
|
$ go get github.com/urfave/cli
|
||||||
```
|
```
|
||||||
|
|
||||||
Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands can be easily used:
|
Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands can be easily used:
|
||||||
@ -33,6 +38,12 @@ Make sure your `PATH` includes to the `$GOPATH/bin` directory so your commands c
|
|||||||
export PATH=$PATH:$GOPATH/bin
|
export PATH=$PATH:$GOPATH/bin
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Supported platforms
|
||||||
|
|
||||||
|
cli is tested against multiple versions of Go on Linux, and against the latest
|
||||||
|
released version of Go on OS X and Windows. For full details, see
|
||||||
|
[`./.travis.yml`](./.travis.yml) and [`./appveyor.yml`](./appveyor.yml).
|
||||||
|
|
||||||
### Using the `v2` branch
|
### Using the `v2` branch
|
||||||
|
|
||||||
There is currently a long-lived branch named `v2` that is intended to land as
|
There is currently a long-lived branch named `v2` that is intended to land as
|
||||||
@ -44,13 +55,13 @@ that, please use whatever version pinning of your preference, such as via
|
|||||||
`gopkg.in`:
|
`gopkg.in`:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ go get gopkg.in/codegangsta/cli.v2
|
$ go get gopkg.in/urfave/cli.v2
|
||||||
```
|
```
|
||||||
|
|
||||||
``` go
|
``` go
|
||||||
...
|
...
|
||||||
import (
|
import (
|
||||||
"gopkg.in/codegangsta/cli.v2" // imports as package "cli"
|
"gopkg.in/urfave/cli.v2" // imports as package "cli"
|
||||||
)
|
)
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
@ -62,13 +73,13 @@ to avoid any unexpected compatibility pains once `v2` becomes `master`, then
|
|||||||
pinning to the `v1` branch is an acceptable option, e.g.:
|
pinning to the `v1` branch is an acceptable option, e.g.:
|
||||||
|
|
||||||
```
|
```
|
||||||
$ go get gopkg.in/codegangsta/cli.v1
|
$ go get gopkg.in/urfave/cli.v1
|
||||||
```
|
```
|
||||||
|
|
||||||
``` go
|
``` go
|
||||||
...
|
...
|
||||||
import (
|
import (
|
||||||
"gopkg.in/codegangsta/cli.v1" // imports as package "cli"
|
"gopkg.in/urfave/cli.v1" // imports as package "cli"
|
||||||
)
|
)
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
@ -82,7 +93,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"github.com/codegangsta/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -102,7 +113,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -136,7 +147,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -205,7 +216,7 @@ Setting and querying flags is simple.
|
|||||||
``` go
|
``` go
|
||||||
...
|
...
|
||||||
app.Flags = []cli.Flag {
|
app.Flags = []cli.Flag {
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "lang",
|
Name: "lang",
|
||||||
Value: "english",
|
Value: "english",
|
||||||
Usage: "language for the greeting",
|
Usage: "language for the greeting",
|
||||||
@ -232,7 +243,7 @@ You can also set a destination variable for a flag, to which the content will be
|
|||||||
...
|
...
|
||||||
var language string
|
var language string
|
||||||
app.Flags = []cli.Flag {
|
app.Flags = []cli.Flag {
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "lang",
|
Name: "lang",
|
||||||
Value: "english",
|
Value: "english",
|
||||||
Usage: "language for the greeting",
|
Usage: "language for the greeting",
|
||||||
@ -254,7 +265,7 @@ app.Action = func(c *cli.Context) error {
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
See full list of flags at http://godoc.org/github.com/codegangsta/cli
|
See full list of flags at http://godoc.org/github.com/urfave/cli
|
||||||
|
|
||||||
#### Placeholder Values
|
#### Placeholder Values
|
||||||
|
|
||||||
@ -264,9 +275,10 @@ indicated with back quotes.
|
|||||||
For example this:
|
For example this:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "config, c",
|
Name: "config",
|
||||||
Usage: "Load configuration from `FILE`",
|
Aliases: []string{"c"},
|
||||||
|
Usage: "Load configuration from `FILE`",
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -284,10 +296,11 @@ You can set alternate (or short) names for flags by providing a comma-delimited
|
|||||||
|
|
||||||
``` go
|
``` go
|
||||||
app.Flags = []cli.Flag {
|
app.Flags = []cli.Flag {
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "lang, l",
|
Name: "lang",
|
||||||
Value: "english",
|
Aliases: []string{"l"},
|
||||||
Usage: "language for the greeting",
|
Value: "english",
|
||||||
|
Usage: "language for the greeting",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -296,28 +309,30 @@ That flag can then be set with `--lang spanish` or `-l spanish`. Note that givin
|
|||||||
|
|
||||||
#### Values from the Environment
|
#### Values from the Environment
|
||||||
|
|
||||||
You can also have the default value set from the environment via `EnvVar`. e.g.
|
You can also have the default value set from the environment via `EnvVars`. e.g.
|
||||||
|
|
||||||
``` go
|
``` go
|
||||||
app.Flags = []cli.Flag {
|
app.Flags = []cli.Flag {
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "lang, l",
|
Name: "lang",
|
||||||
Value: "english",
|
Aliases: []string{"l"},
|
||||||
Usage: "language for the greeting",
|
Value: "english",
|
||||||
EnvVar: "APP_LANG",
|
Usage: "language for the greeting",
|
||||||
|
EnvVars: []string{"APP_LANG"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `EnvVar` may also be given as a comma-delimited "cascade", where the first environment variable that resolves is used as the default.
|
If `EnvVars` contains more than one string, the first environment variable that resolves is used as the default.
|
||||||
|
|
||||||
``` go
|
``` go
|
||||||
app.Flags = []cli.Flag {
|
app.Flags = []cli.Flag {
|
||||||
cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "lang, l",
|
Name: "lang",
|
||||||
Value: "english",
|
Aliases: []string{"l"},
|
||||||
Usage: "language for the greeting",
|
Value: "english",
|
||||||
EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG",
|
Usage: "language for the greeting",
|
||||||
|
EnvVars: []string{"LEGACY_COMPAT_LANG", "APP_LANG", "LANG"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -329,7 +344,7 @@ There is a separate package altsrc that adds support for getting flag values fro
|
|||||||
In order to get values for a flag from an alternate input source the following code would be added to wrap an existing cli.Flag like below:
|
In order to get values for a flag from an alternate input source the following code would be added to wrap an existing cli.Flag like below:
|
||||||
|
|
||||||
``` go
|
``` go
|
||||||
altsrc.NewIntFlag(cli.IntFlag{Name: "test"})
|
altsrc.NewIntFlag(&cli.IntFlag{Name: "test"})
|
||||||
```
|
```
|
||||||
|
|
||||||
Initialization must also occur for these flags. Below is an example initializing getting data from a yaml file below.
|
Initialization must also occur for these flags. Below is an example initializing getting data from a yaml file below.
|
||||||
@ -358,8 +373,8 @@ Here is a more complete sample of a command using YAML support:
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
NewIntFlag(cli.IntFlag{Name: "test"}),
|
NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||||
cli.StringFlag{Name: "load"}},
|
&cli.StringFlag{Name: "load"}},
|
||||||
}
|
}
|
||||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
err := command.Run(c)
|
err := command.Run(c)
|
||||||
@ -371,7 +386,7 @@ Subcommands can be defined for a more git-like command line app.
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
...
|
...
|
||||||
app.Commands = []cli.Command{
|
app.Commands = []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "add",
|
Name: "add",
|
||||||
Aliases: []string{"a"},
|
Aliases: []string{"a"},
|
||||||
@ -394,7 +409,7 @@ app.Commands = []cli.Command{
|
|||||||
Name: "template",
|
Name: "template",
|
||||||
Aliases: []string{"r"},
|
Aliases: []string{"r"},
|
||||||
Usage: "options for task templates",
|
Usage: "options for task templates",
|
||||||
Subcommands: []cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "add",
|
Name: "add",
|
||||||
Usage: "add a new template",
|
Usage: "add a new template",
|
||||||
@ -427,7 +442,7 @@ E.g.
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
...
|
...
|
||||||
app.Commands = []cli.Command{
|
app.Commands = []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "noop",
|
Name: "noop",
|
||||||
},
|
},
|
||||||
@ -469,13 +484,13 @@ package main
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.Flags = []cli.Flag{
|
app.Flags = []cli.Flag{
|
||||||
cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "ginger-crouton",
|
Name: "ginger-crouton",
|
||||||
Value: true,
|
Value: true,
|
||||||
Usage: "is it in the soup?",
|
Usage: "is it in the soup?",
|
||||||
@ -483,7 +498,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
app.Action = func(ctx *cli.Context) error {
|
app.Action = func(ctx *cli.Context) error {
|
||||||
if !ctx.Bool("ginger-crouton") {
|
if !ctx.Bool("ginger-crouton") {
|
||||||
return cli.NewExitError("it is not in the soup", 86)
|
return cli.Exit("it is not in the soup", 86)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -504,7 +519,7 @@ the App or its subcommands.
|
|||||||
var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
|
var tasks = []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
|
||||||
app := cli.NewApp()
|
app := cli.NewApp()
|
||||||
app.EnableBashCompletion = true
|
app.EnableBashCompletion = true
|
||||||
app.Commands = []cli.Command{
|
app.Commands = []*cli.Command{
|
||||||
{
|
{
|
||||||
Name: "complete",
|
Name: "complete",
|
||||||
Aliases: []string{"c"},
|
Aliases: []string{"c"},
|
||||||
@ -569,7 +584,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -618,8 +633,16 @@ VERSION:
|
|||||||
|
|
||||||
## Contribution Guidelines
|
## Contribution Guidelines
|
||||||
|
|
||||||
Feel free to put up a pull request to fix a bug or maybe add a feature. I will give it a code review and make sure that it does not break backwards compatibility. If I or any other collaborators agree that it is in line with the vision of the project, we will work with you to get the code into a mergeable state and merge it into the master branch.
|
Feel free to put up a pull request to fix a bug or maybe add a feature. I will
|
||||||
|
give it a code review and make sure that it does not break backwards
|
||||||
|
compatibility. If I or any other collaborators agree that it is in line with
|
||||||
|
the vision of the project, we will work with you to get the code into
|
||||||
|
a mergeable state and merge it into the master branch.
|
||||||
|
|
||||||
If you have contributed something significant to the project, I will most likely add you as a collaborator. As a collaborator you are given the ability to merge others pull requests. It is very important that new code does not break existing code, so be careful about what code you do choose to merge. If you have any questions feel free to link @codegangsta to the issue in question and we can review it together.
|
If you have contributed something significant to the project, we will most
|
||||||
|
likely add you as a collaborator. As a collaborator you are given the ability
|
||||||
|
to merge others pull requests. It is very important that new code does not
|
||||||
|
break existing code, so be careful about what code you do choose to merge.
|
||||||
|
|
||||||
If you feel like you have contributed to the project but have not yet been added as a collaborator, I probably forgot to add you. Hit @codegangsta up over email and we will get it figured out.
|
If you feel like you have contributed to the project but have not yet been
|
||||||
|
added as a collaborator, we probably forgot to add you, please open an issue.
|
||||||
|
128
altsrc/flag.go
128
altsrc/flag.go
@ -5,9 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FlagInputSourceExtension is an extension interface of cli.Flag that
|
// FlagInputSourceExtension is an extension interface of cli.Flag that
|
||||||
@ -63,30 +62,30 @@ func InitInputSourceWithContext(flags []cli.Flag, createInputSource func(context
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenericFlag is the flag type that wraps cli.GenericFlag to allow
|
// GenericFlag is the flag type that wraps *cli.GenericFlag to allow
|
||||||
// for other values to be specified
|
// for other values to be specified
|
||||||
type GenericFlag struct {
|
type GenericFlag struct {
|
||||||
cli.GenericFlag
|
*cli.GenericFlag
|
||||||
set *flag.FlagSet
|
set *flag.FlagSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGenericFlag creates a new GenericFlag
|
// NewGenericFlag creates a new GenericFlag
|
||||||
func NewGenericFlag(flag cli.GenericFlag) *GenericFlag {
|
func NewGenericFlag(flag *cli.GenericFlag) *GenericFlag {
|
||||||
return &GenericFlag{GenericFlag: flag, set: nil}
|
return &GenericFlag{GenericFlag: flag, set: nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyInputSourceValue applies a generic value to the flagSet if required
|
// ApplyInputSourceValue applies a generic value to the flagSet if required
|
||||||
func (f *GenericFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
func (f *GenericFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||||
if f.set != nil {
|
if f.set != nil {
|
||||||
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVars) {
|
||||||
value, err := isc.Generic(f.GenericFlag.Name)
|
value, err := isc.Generic(f.GenericFlag.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if value != nil {
|
if value != nil {
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
f.set.Set(f.Name, value.String())
|
f.set.Set(name, value.String())
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,34 +100,34 @@ func (f *GenericFlag) Apply(set *flag.FlagSet) {
|
|||||||
f.GenericFlag.Apply(set)
|
f.GenericFlag.Apply(set)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StringSliceFlag is the flag type that wraps cli.StringSliceFlag to allow
|
// StringSliceFlag is the flag type that wraps *cli.StringSliceFlag to allow
|
||||||
// for other values to be specified
|
// for other values to be specified
|
||||||
type StringSliceFlag struct {
|
type StringSliceFlag struct {
|
||||||
cli.StringSliceFlag
|
*cli.StringSliceFlag
|
||||||
set *flag.FlagSet
|
set *flag.FlagSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStringSliceFlag creates a new StringSliceFlag
|
// NewStringSliceFlag creates a new StringSliceFlag
|
||||||
func NewStringSliceFlag(flag cli.StringSliceFlag) *StringSliceFlag {
|
func NewStringSliceFlag(flag *cli.StringSliceFlag) *StringSliceFlag {
|
||||||
return &StringSliceFlag{StringSliceFlag: flag, set: nil}
|
return &StringSliceFlag{StringSliceFlag: flag, set: nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyInputSourceValue applies a StringSlice value to the flagSet if required
|
// ApplyInputSourceValue applies a StringSlice value to the flagSet if required
|
||||||
func (f *StringSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
func (f *StringSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||||
if f.set != nil {
|
if f.set != nil {
|
||||||
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVars) {
|
||||||
value, err := isc.StringSlice(f.StringSliceFlag.Name)
|
value, err := isc.StringSlice(f.StringSliceFlag.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if value != nil {
|
if value != nil {
|
||||||
var sliceValue cli.StringSlice = *(cli.NewStringSlice(value...))
|
var sliceValue cli.StringSlice = *(cli.NewStringSlice(value...))
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
underlyingFlag := f.set.Lookup(f.Name)
|
underlyingFlag := f.set.Lookup(name)
|
||||||
if underlyingFlag != nil {
|
if underlyingFlag != nil {
|
||||||
underlyingFlag.Value = &sliceValue
|
underlyingFlag.Value = &sliceValue
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,34 +141,34 @@ func (f *StringSliceFlag) Apply(set *flag.FlagSet) {
|
|||||||
f.StringSliceFlag.Apply(set)
|
f.StringSliceFlag.Apply(set)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IntSliceFlag is the flag type that wraps cli.IntSliceFlag to allow
|
// IntSliceFlag is the flag type that wraps *cli.IntSliceFlag to allow
|
||||||
// for other values to be specified
|
// for other values to be specified
|
||||||
type IntSliceFlag struct {
|
type IntSliceFlag struct {
|
||||||
cli.IntSliceFlag
|
*cli.IntSliceFlag
|
||||||
set *flag.FlagSet
|
set *flag.FlagSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIntSliceFlag creates a new IntSliceFlag
|
// NewIntSliceFlag creates a new IntSliceFlag
|
||||||
func NewIntSliceFlag(flag cli.IntSliceFlag) *IntSliceFlag {
|
func NewIntSliceFlag(flag *cli.IntSliceFlag) *IntSliceFlag {
|
||||||
return &IntSliceFlag{IntSliceFlag: flag, set: nil}
|
return &IntSliceFlag{IntSliceFlag: flag, set: nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyInputSourceValue applies a IntSlice value if required
|
// ApplyInputSourceValue applies a IntSlice value if required
|
||||||
func (f *IntSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
func (f *IntSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||||
if f.set != nil {
|
if f.set != nil {
|
||||||
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVars) {
|
||||||
value, err := isc.IntSlice(f.IntSliceFlag.Name)
|
value, err := isc.IntSlice(f.IntSliceFlag.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if value != nil {
|
if value != nil {
|
||||||
var sliceValue cli.IntSlice = *(cli.NewIntSlice(value...))
|
var sliceValue cli.IntSlice = *(cli.NewIntSlice(value...))
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
underlyingFlag := f.set.Lookup(f.Name)
|
underlyingFlag := f.set.Lookup(name)
|
||||||
if underlyingFlag != nil {
|
if underlyingFlag != nil {
|
||||||
underlyingFlag.Value = &sliceValue
|
underlyingFlag.Value = &sliceValue
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,30 +182,30 @@ func (f *IntSliceFlag) Apply(set *flag.FlagSet) {
|
|||||||
f.IntSliceFlag.Apply(set)
|
f.IntSliceFlag.Apply(set)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BoolFlag is the flag type that wraps cli.BoolFlag to allow
|
// BoolFlag is the flag type that wraps *cli.BoolFlag to allow
|
||||||
// for other values to be specified
|
// for other values to be specified
|
||||||
type BoolFlag struct {
|
type BoolFlag struct {
|
||||||
cli.BoolFlag
|
*cli.BoolFlag
|
||||||
set *flag.FlagSet
|
set *flag.FlagSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBoolFlag creates a new BoolFlag
|
// NewBoolFlag creates a new BoolFlag
|
||||||
func NewBoolFlag(flag cli.BoolFlag) *BoolFlag {
|
func NewBoolFlag(flag *cli.BoolFlag) *BoolFlag {
|
||||||
return &BoolFlag{BoolFlag: flag, set: nil}
|
return &BoolFlag{BoolFlag: flag, set: nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyInputSourceValue applies a Bool value to the flagSet if required
|
// ApplyInputSourceValue applies a Bool value to the flagSet if required
|
||||||
func (f *BoolFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
func (f *BoolFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||||
if f.set != nil {
|
if f.set != nil {
|
||||||
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) {
|
if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVars) {
|
||||||
value, err := isc.Bool(f.BoolFlag.Name)
|
value, err := isc.Bool(f.BoolFlag.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if value {
|
if value {
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
f.set.Set(f.Name, strconv.FormatBool(value))
|
f.set.Set(name, strconv.FormatBool(value))
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,30 +219,30 @@ func (f *BoolFlag) Apply(set *flag.FlagSet) {
|
|||||||
f.BoolFlag.Apply(set)
|
f.BoolFlag.Apply(set)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StringFlag is the flag type that wraps cli.StringFlag to allow
|
// StringFlag is the flag type that wraps *cli.StringFlag to allow
|
||||||
// for other values to be specified
|
// for other values to be specified
|
||||||
type StringFlag struct {
|
type StringFlag struct {
|
||||||
cli.StringFlag
|
*cli.StringFlag
|
||||||
set *flag.FlagSet
|
set *flag.FlagSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStringFlag creates a new StringFlag
|
// NewStringFlag creates a new StringFlag
|
||||||
func NewStringFlag(flag cli.StringFlag) *StringFlag {
|
func NewStringFlag(flag *cli.StringFlag) *StringFlag {
|
||||||
return &StringFlag{StringFlag: flag, set: nil}
|
return &StringFlag{StringFlag: flag, set: nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyInputSourceValue applies a String value to the flagSet if required
|
// ApplyInputSourceValue applies a String value to the flagSet if required
|
||||||
func (f *StringFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
func (f *StringFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||||
if f.set != nil {
|
if f.set != nil {
|
||||||
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVars)) {
|
||||||
value, err := isc.String(f.StringFlag.Name)
|
value, err := isc.String(f.StringFlag.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if value != "" {
|
if value != "" {
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
f.set.Set(f.Name, value)
|
f.set.Set(name, value)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -258,30 +257,30 @@ func (f *StringFlag) Apply(set *flag.FlagSet) {
|
|||||||
f.StringFlag.Apply(set)
|
f.StringFlag.Apply(set)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IntFlag is the flag type that wraps cli.IntFlag to allow
|
// IntFlag is the flag type that wraps *cli.IntFlag to allow
|
||||||
// for other values to be specified
|
// for other values to be specified
|
||||||
type IntFlag struct {
|
type IntFlag struct {
|
||||||
cli.IntFlag
|
*cli.IntFlag
|
||||||
set *flag.FlagSet
|
set *flag.FlagSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIntFlag creates a new IntFlag
|
// NewIntFlag creates a new IntFlag
|
||||||
func NewIntFlag(flag cli.IntFlag) *IntFlag {
|
func NewIntFlag(flag *cli.IntFlag) *IntFlag {
|
||||||
return &IntFlag{IntFlag: flag, set: nil}
|
return &IntFlag{IntFlag: flag, set: nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyInputSourceValue applies a int value to the flagSet if required
|
// ApplyInputSourceValue applies a int value to the flagSet if required
|
||||||
func (f *IntFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
func (f *IntFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||||
if f.set != nil {
|
if f.set != nil {
|
||||||
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVars)) {
|
||||||
value, err := isc.Int(f.IntFlag.Name)
|
value, err := isc.Int(f.IntFlag.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if value > 0 {
|
if value > 0 {
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
f.set.Set(f.Name, strconv.FormatInt(int64(value), 10))
|
f.set.Set(name, strconv.FormatInt(int64(value), 10))
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,30 +294,30 @@ func (f *IntFlag) Apply(set *flag.FlagSet) {
|
|||||||
f.IntFlag.Apply(set)
|
f.IntFlag.Apply(set)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DurationFlag is the flag type that wraps cli.DurationFlag to allow
|
// DurationFlag is the flag type that wraps *cli.DurationFlag to allow
|
||||||
// for other values to be specified
|
// for other values to be specified
|
||||||
type DurationFlag struct {
|
type DurationFlag struct {
|
||||||
cli.DurationFlag
|
*cli.DurationFlag
|
||||||
set *flag.FlagSet
|
set *flag.FlagSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDurationFlag creates a new DurationFlag
|
// NewDurationFlag creates a new DurationFlag
|
||||||
func NewDurationFlag(flag cli.DurationFlag) *DurationFlag {
|
func NewDurationFlag(flag *cli.DurationFlag) *DurationFlag {
|
||||||
return &DurationFlag{DurationFlag: flag, set: nil}
|
return &DurationFlag{DurationFlag: flag, set: nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyInputSourceValue applies a Duration value to the flagSet if required
|
// ApplyInputSourceValue applies a Duration value to the flagSet if required
|
||||||
func (f *DurationFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
func (f *DurationFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||||
if f.set != nil {
|
if f.set != nil {
|
||||||
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVars)) {
|
||||||
value, err := isc.Duration(f.DurationFlag.Name)
|
value, err := isc.Duration(f.DurationFlag.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if value > 0 {
|
if value > 0 {
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
f.set.Set(f.Name, value.String())
|
f.set.Set(name, value.String())
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -333,31 +332,31 @@ func (f *DurationFlag) Apply(set *flag.FlagSet) {
|
|||||||
f.DurationFlag.Apply(set)
|
f.DurationFlag.Apply(set)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Float64Flag is the flag type that wraps cli.Float64Flag to allow
|
// Float64Flag is the flag type that wraps *cli.Float64Flag to allow
|
||||||
// for other values to be specified
|
// for other values to be specified
|
||||||
type Float64Flag struct {
|
type Float64Flag struct {
|
||||||
cli.Float64Flag
|
*cli.Float64Flag
|
||||||
set *flag.FlagSet
|
set *flag.FlagSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFloat64Flag creates a new Float64Flag
|
// NewFloat64Flag creates a new Float64Flag
|
||||||
func NewFloat64Flag(flag cli.Float64Flag) *Float64Flag {
|
func NewFloat64Flag(flag *cli.Float64Flag) *Float64Flag {
|
||||||
return &Float64Flag{Float64Flag: flag, set: nil}
|
return &Float64Flag{Float64Flag: flag, set: nil}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplyInputSourceValue applies a Float64 value to the flagSet if required
|
// ApplyInputSourceValue applies a Float64 value to the flagSet if required
|
||||||
func (f *Float64Flag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
func (f *Float64Flag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error {
|
||||||
if f.set != nil {
|
if f.set != nil {
|
||||||
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) {
|
if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVars)) {
|
||||||
value, err := isc.Float64(f.Float64Flag.Name)
|
value, err := isc.Float64(f.Float64Flag.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if value > 0 {
|
if value > 0 {
|
||||||
floatStr := float64ToString(value)
|
floatStr := float64ToString(value)
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
f.set.Set(f.Name, floatStr)
|
f.set.Set(name, floatStr)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -372,9 +371,8 @@ func (f *Float64Flag) Apply(set *flag.FlagSet) {
|
|||||||
f.Float64Flag.Apply(set)
|
f.Float64Flag.Apply(set)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isEnvVarSet(envVars string) bool {
|
func isEnvVarSet(envVars []string) bool {
|
||||||
for _, envVar := range strings.Split(envVars, ",") {
|
for _, envVar := range envVars {
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
// TODO: Can't use this for bools as
|
// TODO: Can't use this for bools as
|
||||||
// set means that it was true or false based on
|
// set means that it was true or false based on
|
||||||
@ -391,11 +389,3 @@ func isEnvVarSet(envVars string) bool {
|
|||||||
func float64ToString(f float64) string {
|
func float64ToString(f float64) string {
|
||||||
return fmt.Sprintf("%v", f)
|
return fmt.Sprintf("%v", f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func eachName(longName string, fn func(string)) {
|
|
||||||
parts := strings.Split(longName, ",")
|
|
||||||
for _, name := range parts {
|
|
||||||
name = strings.Trim(name, " ")
|
|
||||||
fn(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
type testApplyInputSource struct {
|
type testApplyInputSource struct {
|
||||||
@ -26,7 +26,7 @@ type testApplyInputSource struct {
|
|||||||
func TestGenericApplyInputSourceValue(t *testing.T) {
|
func TestGenericApplyInputSourceValue(t *testing.T) {
|
||||||
v := &Parser{"abc", "def"}
|
v := &Parser{"abc", "def"}
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewGenericFlag(cli.GenericFlag{Name: "test", Value: &Parser{}}),
|
Flag: NewGenericFlag(&cli.GenericFlag{Name: "test", Value: &Parser{}}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: v,
|
MapValue: v,
|
||||||
})
|
})
|
||||||
@ -36,7 +36,7 @@ func TestGenericApplyInputSourceValue(t *testing.T) {
|
|||||||
func TestGenericApplyInputSourceMethodContextSet(t *testing.T) {
|
func TestGenericApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
p := &Parser{"abc", "def"}
|
p := &Parser{"abc", "def"}
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewGenericFlag(cli.GenericFlag{Name: "test", Value: &Parser{}}),
|
Flag: NewGenericFlag(&cli.GenericFlag{Name: "test", Value: &Parser{}}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: &Parser{"efg", "hig"},
|
MapValue: &Parser{"efg", "hig"},
|
||||||
ContextValueString: p.String(),
|
ContextValueString: p.String(),
|
||||||
@ -46,7 +46,11 @@ func TestGenericApplyInputSourceMethodContextSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestGenericApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
func TestGenericApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewGenericFlag(cli.GenericFlag{Name: "test", Value: &Parser{}, EnvVar: "TEST"}),
|
Flag: NewGenericFlag(&cli.GenericFlag{
|
||||||
|
Name: "test",
|
||||||
|
Value: &Parser{},
|
||||||
|
EnvVars: []string{"TEST"},
|
||||||
|
}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: &Parser{"efg", "hij"},
|
MapValue: &Parser{"efg", "hij"},
|
||||||
EnvVarName: "TEST",
|
EnvVarName: "TEST",
|
||||||
@ -57,7 +61,7 @@ func TestGenericApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestStringSliceApplyInputSourceValue(t *testing.T) {
|
func TestStringSliceApplyInputSourceValue(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewStringSliceFlag(cli.StringSliceFlag{Name: "test"}),
|
Flag: NewStringSliceFlag(&cli.StringSliceFlag{Name: "test"}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: []string{"hello", "world"},
|
MapValue: []string{"hello", "world"},
|
||||||
})
|
})
|
||||||
@ -66,7 +70,7 @@ func TestStringSliceApplyInputSourceValue(t *testing.T) {
|
|||||||
|
|
||||||
func TestStringSliceApplyInputSourceMethodContextSet(t *testing.T) {
|
func TestStringSliceApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewStringSliceFlag(cli.StringSliceFlag{Name: "test"}),
|
Flag: NewStringSliceFlag(&cli.StringSliceFlag{Name: "test"}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: []string{"hello", "world"},
|
MapValue: []string{"hello", "world"},
|
||||||
ContextValueString: "ohno",
|
ContextValueString: "ohno",
|
||||||
@ -76,7 +80,7 @@ func TestStringSliceApplyInputSourceMethodContextSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestStringSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
func TestStringSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewStringSliceFlag(cli.StringSliceFlag{Name: "test", EnvVar: "TEST"}),
|
Flag: NewStringSliceFlag(&cli.StringSliceFlag{Name: "test", EnvVars: []string{"TEST"}}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: []string{"hello", "world"},
|
MapValue: []string{"hello", "world"},
|
||||||
EnvVarName: "TEST",
|
EnvVarName: "TEST",
|
||||||
@ -87,7 +91,7 @@ func TestStringSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestIntSliceApplyInputSourceValue(t *testing.T) {
|
func TestIntSliceApplyInputSourceValue(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewIntSliceFlag(cli.IntSliceFlag{Name: "test"}),
|
Flag: NewIntSliceFlag(&cli.IntSliceFlag{Name: "test"}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: []int{1, 2},
|
MapValue: []int{1, 2},
|
||||||
})
|
})
|
||||||
@ -96,7 +100,7 @@ func TestIntSliceApplyInputSourceValue(t *testing.T) {
|
|||||||
|
|
||||||
func TestIntSliceApplyInputSourceMethodContextSet(t *testing.T) {
|
func TestIntSliceApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewIntSliceFlag(cli.IntSliceFlag{Name: "test"}),
|
Flag: NewIntSliceFlag(&cli.IntSliceFlag{Name: "test"}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: []int{1, 2},
|
MapValue: []int{1, 2},
|
||||||
ContextValueString: "3",
|
ContextValueString: "3",
|
||||||
@ -106,7 +110,7 @@ func TestIntSliceApplyInputSourceMethodContextSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestIntSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
func TestIntSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewIntSliceFlag(cli.IntSliceFlag{Name: "test", EnvVar: "TEST"}),
|
Flag: NewIntSliceFlag(&cli.IntSliceFlag{Name: "test", EnvVars: []string{"TEST"}}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: []int{1, 2},
|
MapValue: []int{1, 2},
|
||||||
EnvVarName: "TEST",
|
EnvVarName: "TEST",
|
||||||
@ -117,7 +121,7 @@ func TestIntSliceApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestBoolApplyInputSourceMethodSet(t *testing.T) {
|
func TestBoolApplyInputSourceMethodSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewBoolFlag(cli.BoolFlag{Name: "test"}),
|
Flag: NewBoolFlag(&cli.BoolFlag{Name: "test"}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: true,
|
MapValue: true,
|
||||||
})
|
})
|
||||||
@ -126,7 +130,7 @@ func TestBoolApplyInputSourceMethodSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestBoolApplyInputSourceMethodContextSet(t *testing.T) {
|
func TestBoolApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewBoolFlag(cli.BoolFlag{Name: "test"}),
|
Flag: NewBoolFlag(&cli.BoolFlag{Name: "test"}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: false,
|
MapValue: false,
|
||||||
ContextValueString: "true",
|
ContextValueString: "true",
|
||||||
@ -136,7 +140,7 @@ func TestBoolApplyInputSourceMethodContextSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestBoolApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
func TestBoolApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewBoolFlag(cli.BoolFlag{Name: "test", EnvVar: "TEST"}),
|
Flag: NewBoolFlag(&cli.BoolFlag{Name: "test", EnvVars: []string{"TEST"}}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: false,
|
MapValue: false,
|
||||||
EnvVarName: "TEST",
|
EnvVarName: "TEST",
|
||||||
@ -147,7 +151,7 @@ func TestBoolApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestStringApplyInputSourceMethodSet(t *testing.T) {
|
func TestStringApplyInputSourceMethodSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewStringFlag(cli.StringFlag{Name: "test"}),
|
Flag: NewStringFlag(&cli.StringFlag{Name: "test"}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: "hello",
|
MapValue: "hello",
|
||||||
})
|
})
|
||||||
@ -156,7 +160,7 @@ func TestStringApplyInputSourceMethodSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestStringApplyInputSourceMethodContextSet(t *testing.T) {
|
func TestStringApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewStringFlag(cli.StringFlag{Name: "test"}),
|
Flag: NewStringFlag(&cli.StringFlag{Name: "test"}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: "hello",
|
MapValue: "hello",
|
||||||
ContextValueString: "goodbye",
|
ContextValueString: "goodbye",
|
||||||
@ -166,7 +170,7 @@ func TestStringApplyInputSourceMethodContextSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestStringApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
func TestStringApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewStringFlag(cli.StringFlag{Name: "test", EnvVar: "TEST"}),
|
Flag: NewStringFlag(&cli.StringFlag{Name: "test", EnvVars: []string{"TEST"}}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: "hello",
|
MapValue: "hello",
|
||||||
EnvVarName: "TEST",
|
EnvVarName: "TEST",
|
||||||
@ -177,7 +181,7 @@ func TestStringApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestIntApplyInputSourceMethodSet(t *testing.T) {
|
func TestIntApplyInputSourceMethodSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewIntFlag(cli.IntFlag{Name: "test"}),
|
Flag: NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: 15,
|
MapValue: 15,
|
||||||
})
|
})
|
||||||
@ -186,7 +190,7 @@ func TestIntApplyInputSourceMethodSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestIntApplyInputSourceMethodContextSet(t *testing.T) {
|
func TestIntApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewIntFlag(cli.IntFlag{Name: "test"}),
|
Flag: NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: 15,
|
MapValue: 15,
|
||||||
ContextValueString: "7",
|
ContextValueString: "7",
|
||||||
@ -196,7 +200,7 @@ func TestIntApplyInputSourceMethodContextSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestIntApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
func TestIntApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewIntFlag(cli.IntFlag{Name: "test", EnvVar: "TEST"}),
|
Flag: NewIntFlag(&cli.IntFlag{Name: "test", EnvVars: []string{"TEST"}}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: 15,
|
MapValue: 15,
|
||||||
EnvVarName: "TEST",
|
EnvVarName: "TEST",
|
||||||
@ -207,7 +211,7 @@ func TestIntApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestDurationApplyInputSourceMethodSet(t *testing.T) {
|
func TestDurationApplyInputSourceMethodSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewDurationFlag(cli.DurationFlag{Name: "test"}),
|
Flag: NewDurationFlag(&cli.DurationFlag{Name: "test"}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: time.Duration(30 * time.Second),
|
MapValue: time.Duration(30 * time.Second),
|
||||||
})
|
})
|
||||||
@ -216,7 +220,7 @@ func TestDurationApplyInputSourceMethodSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestDurationApplyInputSourceMethodContextSet(t *testing.T) {
|
func TestDurationApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewDurationFlag(cli.DurationFlag{Name: "test"}),
|
Flag: NewDurationFlag(&cli.DurationFlag{Name: "test"}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: time.Duration(30 * time.Second),
|
MapValue: time.Duration(30 * time.Second),
|
||||||
ContextValueString: time.Duration(15 * time.Second).String(),
|
ContextValueString: time.Duration(15 * time.Second).String(),
|
||||||
@ -226,7 +230,7 @@ func TestDurationApplyInputSourceMethodContextSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestDurationApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
func TestDurationApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewDurationFlag(cli.DurationFlag{Name: "test", EnvVar: "TEST"}),
|
Flag: NewDurationFlag(&cli.DurationFlag{Name: "test", EnvVars: []string{"TEST"}}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: time.Duration(30 * time.Second),
|
MapValue: time.Duration(30 * time.Second),
|
||||||
EnvVarName: "TEST",
|
EnvVarName: "TEST",
|
||||||
@ -237,7 +241,7 @@ func TestDurationApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestFloat64ApplyInputSourceMethodSet(t *testing.T) {
|
func TestFloat64ApplyInputSourceMethodSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewFloat64Flag(cli.Float64Flag{Name: "test"}),
|
Flag: NewFloat64Flag(&cli.Float64Flag{Name: "test"}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: 1.3,
|
MapValue: 1.3,
|
||||||
})
|
})
|
||||||
@ -246,7 +250,7 @@ func TestFloat64ApplyInputSourceMethodSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestFloat64ApplyInputSourceMethodContextSet(t *testing.T) {
|
func TestFloat64ApplyInputSourceMethodContextSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewFloat64Flag(cli.Float64Flag{Name: "test"}),
|
Flag: NewFloat64Flag(&cli.Float64Flag{Name: "test"}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: 1.3,
|
MapValue: 1.3,
|
||||||
ContextValueString: fmt.Sprintf("%v", 1.4),
|
ContextValueString: fmt.Sprintf("%v", 1.4),
|
||||||
@ -256,7 +260,7 @@ func TestFloat64ApplyInputSourceMethodContextSet(t *testing.T) {
|
|||||||
|
|
||||||
func TestFloat64ApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
func TestFloat64ApplyInputSourceMethodEnvVarSet(t *testing.T) {
|
||||||
c := runTest(t, testApplyInputSource{
|
c := runTest(t, testApplyInputSource{
|
||||||
Flag: NewFloat64Flag(cli.Float64Flag{Name: "test", EnvVar: "TEST"}),
|
Flag: NewFloat64Flag(&cli.Float64Flag{Name: "test", EnvVars: []string{"TEST"}}),
|
||||||
FlagName: "test",
|
FlagName: "test",
|
||||||
MapValue: 1.3,
|
MapValue: 1.3,
|
||||||
EnvVarName: "TEST",
|
EnvVarName: "TEST",
|
||||||
|
@ -3,7 +3,7 @@ package altsrc
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InputSourceContext is an interface used to allow
|
// InputSourceContext is an interface used to allow
|
||||||
|
@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MapInputSource implements InputSourceContext to return
|
// MapInputSource implements InputSourceContext to return
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCommandYamlFileTest(t *testing.T) {
|
func TestCommandYamlFileTest(t *testing.T) {
|
||||||
@ -35,8 +35,8 @@ func TestCommandYamlFileTest(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
NewIntFlag(cli.IntFlag{Name: "test"}),
|
NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||||
cli.StringFlag{Name: "load"}},
|
&cli.StringFlag{Name: "load"}},
|
||||||
}
|
}
|
||||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
err := command.Run(c)
|
err := command.Run(c)
|
||||||
@ -68,8 +68,8 @@ func TestCommandYamlFileTestGlobalEnvVarWins(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
NewIntFlag(cli.IntFlag{Name: "test", EnvVar: "THE_TEST"}),
|
NewIntFlag(&cli.IntFlag{Name: "test", EnvVars: []string{"THE_TEST"}}),
|
||||||
cli.StringFlag{Name: "load"}},
|
&cli.StringFlag{Name: "load"}},
|
||||||
}
|
}
|
||||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
|
|
||||||
@ -103,8 +103,8 @@ func TestCommandYamlFileTestGlobalEnvVarWinsNested(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
NewIntFlag(cli.IntFlag{Name: "top.test", EnvVar: "THE_TEST"}),
|
NewIntFlag(&cli.IntFlag{Name: "top.test", EnvVars: []string{"THE_TEST"}}),
|
||||||
cli.StringFlag{Name: "load"}},
|
&cli.StringFlag{Name: "load"}},
|
||||||
}
|
}
|
||||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
|
|
||||||
@ -135,8 +135,8 @@ func TestCommandYamlFileTestSpecifiedFlagWins(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
NewIntFlag(cli.IntFlag{Name: "test"}),
|
NewIntFlag(&cli.IntFlag{Name: "test"}),
|
||||||
cli.StringFlag{Name: "load"}},
|
&cli.StringFlag{Name: "load"}},
|
||||||
}
|
}
|
||||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
|
|
||||||
@ -168,8 +168,8 @@ func TestCommandYamlFileTestSpecifiedFlagWinsNested(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
NewIntFlag(cli.IntFlag{Name: "top.test"}),
|
NewIntFlag(&cli.IntFlag{Name: "top.test"}),
|
||||||
cli.StringFlag{Name: "load"}},
|
&cli.StringFlag{Name: "load"}},
|
||||||
}
|
}
|
||||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
|
|
||||||
@ -200,8 +200,8 @@ func TestCommandYamlFileTestDefaultValueFileWins(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
NewIntFlag(cli.IntFlag{Name: "test", Value: 7}),
|
NewIntFlag(&cli.IntFlag{Name: "test", Value: 7}),
|
||||||
cli.StringFlag{Name: "load"}},
|
&cli.StringFlag{Name: "load"}},
|
||||||
}
|
}
|
||||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
|
|
||||||
@ -233,8 +233,8 @@ func TestCommandYamlFileTestDefaultValueFileWinsNested(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
NewIntFlag(cli.IntFlag{Name: "top.test", Value: 7}),
|
NewIntFlag(&cli.IntFlag{Name: "top.test", Value: 7}),
|
||||||
cli.StringFlag{Name: "load"}},
|
&cli.StringFlag{Name: "load"}},
|
||||||
}
|
}
|
||||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
|
|
||||||
@ -268,8 +268,8 @@ func TestCommandYamlFileFlagHasDefaultGlobalEnvYamlSetGlobalEnvWins(t *testing.T
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
NewIntFlag(cli.IntFlag{Name: "test", Value: 7, EnvVar: "THE_TEST"}),
|
NewIntFlag(&cli.IntFlag{Name: "test", Value: 7, EnvVars: []string{"THE_TEST"}}),
|
||||||
cli.StringFlag{Name: "load"}},
|
&cli.StringFlag{Name: "load"}},
|
||||||
}
|
}
|
||||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
err := command.Run(c)
|
err := command.Run(c)
|
||||||
@ -303,8 +303,8 @@ func TestCommandYamlFileFlagHasDefaultGlobalEnvYamlSetGlobalEnvWinsNested(t *tes
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
NewIntFlag(cli.IntFlag{Name: "top.test", Value: 7, EnvVar: "THE_TEST"}),
|
NewIntFlag(&cli.IntFlag{Name: "top.test", Value: 7, EnvVars: []string{"THE_TEST"}}),
|
||||||
cli.StringFlag{Name: "load"}},
|
&cli.StringFlag{Name: "load"}},
|
||||||
}
|
}
|
||||||
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
command.Before = InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
|
||||||
err := command.Run(c)
|
err := command.Run(c)
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/codegangsta/cli"
|
"github.com/urfave/cli"
|
||||||
|
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
78
app.go
78
app.go
@ -6,6 +6,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -26,7 +27,7 @@ type App struct {
|
|||||||
// Version of the program
|
// Version of the program
|
||||||
Version string
|
Version 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
|
||||||
Flags []Flag
|
Flags []Flag
|
||||||
// Boolean to enable bash completion commands
|
// Boolean to enable bash completion commands
|
||||||
@ -35,8 +36,8 @@ type App struct {
|
|||||||
HideHelp bool
|
HideHelp bool
|
||||||
// Boolean to hide built-in version flag and the VERSION section of help
|
// Boolean to hide built-in version flag and the VERSION section of help
|
||||||
HideVersion bool
|
HideVersion bool
|
||||||
// Populate on app startup, only gettable through method Categories()
|
// Categories contains the categorized commands and is populated on app startup
|
||||||
categories CommandCategories
|
Categories CommandCategories
|
||||||
// An action to execute when the bash-completion flag is set
|
// An action to execute when the bash-completion flag is set
|
||||||
BashComplete BashCompleteFunc
|
BashComplete BashCompleteFunc
|
||||||
// An action to execute before any subcommands are run, but after the context is ready
|
// An action to execute before any subcommands are run, but after the context is ready
|
||||||
@ -54,7 +55,7 @@ type App struct {
|
|||||||
// Compilation date
|
// Compilation date
|
||||||
Compiled time.Time
|
Compiled time.Time
|
||||||
// List of all authors who contributed
|
// List of all authors who contributed
|
||||||
Authors []Author
|
Authors []*Author
|
||||||
// Copyright of the binary if any
|
// Copyright of the binary if any
|
||||||
Copyright string
|
Copyright string
|
||||||
// Writer writer to write output to
|
// Writer writer to write output to
|
||||||
@ -103,7 +104,7 @@ func (a *App) Setup() {
|
|||||||
|
|
||||||
a.didSetup = true
|
a.didSetup = true
|
||||||
|
|
||||||
newCmds := []Command{}
|
newCmds := []*Command{}
|
||||||
for _, c := range a.Commands {
|
for _, c := range a.Commands {
|
||||||
if c.HelpName == "" {
|
if c.HelpName == "" {
|
||||||
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
|
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
|
||||||
@ -112,16 +113,17 @@ func (a *App) Setup() {
|
|||||||
}
|
}
|
||||||
a.Commands = newCmds
|
a.Commands = newCmds
|
||||||
|
|
||||||
a.categories = CommandCategories{}
|
a.Categories = newCommandCategories()
|
||||||
for _, command := range a.Commands {
|
for _, command := range a.Commands {
|
||||||
a.categories = a.categories.AddCommand(command.Category, command)
|
a.Categories.AddCommand(command.Category, command)
|
||||||
}
|
}
|
||||||
sort.Sort(a.categories)
|
sort.Sort(a.Categories.(*commandCategories))
|
||||||
|
|
||||||
// append help to commands
|
// append help to commands
|
||||||
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
if a.Command(helpCommand.Name) == nil && !a.HideHelp {
|
||||||
a.Commands = append(a.Commands, helpCommand)
|
a.appendCommand(helpCommand)
|
||||||
if (HelpFlag != BoolFlag{}) {
|
|
||||||
|
if HelpFlag != nil {
|
||||||
a.appendFlag(HelpFlag)
|
a.appendFlag(HelpFlag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,7 +165,7 @@ func (a *App) Run(arguments []string) (err error) {
|
|||||||
HandleExitCoder(err)
|
HandleExitCoder(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.")
|
fmt.Fprintf(a.Writer, "Incorrect Usage: %s\n\n", err)
|
||||||
ShowAppHelp(context)
|
ShowAppHelp(context)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -182,7 +184,7 @@ func (a *App) Run(arguments []string) (err error) {
|
|||||||
defer func() {
|
defer func() {
|
||||||
if afterErr := a.After(context); afterErr != nil {
|
if afterErr := a.After(context); afterErr != nil {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = NewMultiError(err, afterErr)
|
err = newMultiError(err, afterErr)
|
||||||
} else {
|
} else {
|
||||||
err = afterErr
|
err = afterErr
|
||||||
}
|
}
|
||||||
@ -223,14 +225,15 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
|||||||
// 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 {
|
||||||
a.Commands = append(a.Commands, helpCommand)
|
a.appendCommand(helpCommand)
|
||||||
if (HelpFlag != BoolFlag{}) {
|
|
||||||
|
if HelpFlag != nil {
|
||||||
a.appendFlag(HelpFlag)
|
a.appendFlag(HelpFlag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newCmds := []Command{}
|
newCmds := []*Command{}
|
||||||
for _, c := range a.Commands {
|
for _, c := range a.Commands {
|
||||||
if c.HelpName == "" {
|
if c.HelpName == "" {
|
||||||
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
|
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
|
||||||
@ -272,7 +275,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
|||||||
HandleExitCoder(err)
|
HandleExitCoder(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.")
|
fmt.Fprintf(a.Writer, "Incorrect Usage: %s\n\n", err)
|
||||||
ShowSubcommandHelp(context)
|
ShowSubcommandHelp(context)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -293,7 +296,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
|||||||
if afterErr != nil {
|
if afterErr != nil {
|
||||||
HandleExitCoder(err)
|
HandleExitCoder(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = NewMultiError(err, afterErr)
|
err = newMultiError(err, afterErr)
|
||||||
} else {
|
} else {
|
||||||
err = afterErr
|
err = afterErr
|
||||||
}
|
}
|
||||||
@ -330,28 +333,21 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
|
|||||||
func (a *App) Command(name string) *Command {
|
func (a *App) Command(name string) *Command {
|
||||||
for _, c := range a.Commands {
|
for _, c := range a.Commands {
|
||||||
if c.HasName(name) {
|
if c.HasName(name) {
|
||||||
return &c
|
return c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Categories returns a slice containing all the categories with the commands they contain
|
|
||||||
func (a *App) Categories() CommandCategories {
|
|
||||||
return a.categories
|
|
||||||
}
|
|
||||||
|
|
||||||
// VisibleCategories returns a slice of categories and commands that are
|
// VisibleCategories returns a slice of categories and commands that are
|
||||||
// Hidden=false
|
// Hidden=false
|
||||||
func (a *App) VisibleCategories() []*CommandCategory {
|
func (a *App) VisibleCategories() []CommandCategory {
|
||||||
ret := []*CommandCategory{}
|
ret := []CommandCategory{}
|
||||||
for _, category := range a.categories {
|
for _, category := range a.Categories.Categories() {
|
||||||
if visible := func() *CommandCategory {
|
if visible := func() CommandCategory {
|
||||||
for _, command := range category.Commands {
|
if len(category.VisibleCommands()) > 0 {
|
||||||
if !command.Hidden {
|
return category
|
||||||
return category
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}(); visible != nil {
|
}(); visible != nil {
|
||||||
@ -362,8 +358,8 @@ func (a *App) VisibleCategories() []*CommandCategory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// VisibleCommands returns a slice of the Commands with Hidden=false
|
// VisibleCommands returns a slice of the Commands with Hidden=false
|
||||||
func (a *App) VisibleCommands() []Command {
|
func (a *App) VisibleCommands() []*Command {
|
||||||
ret := []Command{}
|
ret := []*Command{}
|
||||||
for _, command := range a.Commands {
|
for _, command := range a.Commands {
|
||||||
if !command.Hidden {
|
if !command.Hidden {
|
||||||
ret = append(ret, command)
|
ret = append(ret, command)
|
||||||
@ -379,7 +375,7 @@ func (a *App) VisibleFlags() []Flag {
|
|||||||
|
|
||||||
func (a *App) hasFlag(flag Flag) bool {
|
func (a *App) hasFlag(flag Flag) bool {
|
||||||
for _, f := range a.Flags {
|
for _, f := range a.Flags {
|
||||||
if flag == f {
|
if reflect.DeepEqual(flag, f) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -397,9 +393,15 @@ func (a *App) errWriter() io.Writer {
|
|||||||
return a.ErrWriter
|
return a.ErrWriter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) appendFlag(flag Flag) {
|
func (a *App) appendFlag(fl Flag) {
|
||||||
if !a.hasFlag(flag) {
|
if !hasFlag(a.Flags, fl) {
|
||||||
a.Flags = append(a.Flags, flag)
|
a.Flags = append(a.Flags, fl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *App) appendCommand(c *Command) {
|
||||||
|
if !hasCommand(a.Commands, c) {
|
||||||
|
a.Commands = append(a.Commands, c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -410,7 +412,7 @@ type Author struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
|
// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
|
||||||
func (a Author) String() string {
|
func (a *Author) String() string {
|
||||||
e := ""
|
e := ""
|
||||||
if a.Email != "" {
|
if a.Email != "" {
|
||||||
e = "<" + a.Email + "> "
|
e = "<" + a.Email + "> "
|
||||||
|
276
app_test.go
276
app_test.go
@ -24,14 +24,14 @@ func ExampleApp_Run() {
|
|||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Name = "greet"
|
app.Name = "greet"
|
||||||
app.Flags = []Flag{
|
app.Flags = []Flag{
|
||||||
StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
|
&StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
|
||||||
}
|
}
|
||||||
app.Action = func(c *Context) error {
|
app.Action = func(c *Context) error {
|
||||||
fmt.Printf("Hello %v\n", c.String("name"))
|
fmt.Printf("Hello %v\n", c.String("name"))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
app.UsageText = "app [first_arg] [second_arg]"
|
app.UsageText = "app [first_arg] [second_arg]"
|
||||||
app.Authors = []Author{{Name: "Oliver Allen", Email: "oliver@toyshop.example.com"}}
|
app.Authors = []*Author{{Name: "Oliver Allen", Email: "oliver@toyshop.example.com"}}
|
||||||
app.Run(os.Args)
|
app.Run(os.Args)
|
||||||
// Output:
|
// Output:
|
||||||
// Hello Jeremy
|
// Hello Jeremy
|
||||||
@ -42,20 +42,20 @@ func ExampleApp_Run_subcommand() {
|
|||||||
os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
|
os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Name = "say"
|
app.Name = "say"
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "hello",
|
Name: "hello",
|
||||||
Aliases: []string{"hi"},
|
Aliases: []string{"hi"},
|
||||||
Usage: "use it to see a description",
|
Usage: "use it to see a description",
|
||||||
Description: "This is how we describe hello the function",
|
Description: "This is how we describe hello the function",
|
||||||
Subcommands: []Command{
|
Subcommands: []*Command{
|
||||||
{
|
{
|
||||||
Name: "english",
|
Name: "english",
|
||||||
Aliases: []string{"en"},
|
Aliases: []string{"en"},
|
||||||
Usage: "sends a greeting in english",
|
Usage: "sends a greeting in english",
|
||||||
Description: "greets someone in english",
|
Description: "greets someone in english",
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringFlag{
|
&StringFlag{
|
||||||
Name: "name",
|
Name: "name",
|
||||||
Value: "Bob",
|
Value: "Bob",
|
||||||
Usage: "Name of the person to greet",
|
Usage: "Name of the person to greet",
|
||||||
@ -82,9 +82,9 @@ func ExampleApp_Run_help() {
|
|||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Name = "greet"
|
app.Name = "greet"
|
||||||
app.Flags = []Flag{
|
app.Flags = []Flag{
|
||||||
StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
|
&StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
|
||||||
}
|
}
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "describeit",
|
Name: "describeit",
|
||||||
Aliases: []string{"d"},
|
Aliases: []string{"d"},
|
||||||
@ -115,7 +115,7 @@ func ExampleApp_Run_bashComplete() {
|
|||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Name = "greet"
|
app.Name = "greet"
|
||||||
app.EnableBashCompletion = true
|
app.EnableBashCompletion = true
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "describeit",
|
Name: "describeit",
|
||||||
Aliases: []string{"d"},
|
Aliases: []string{"d"},
|
||||||
@ -175,9 +175,9 @@ var commandAppTests = []struct {
|
|||||||
|
|
||||||
func TestApp_Command(t *testing.T) {
|
func TestApp_Command(t *testing.T) {
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
fooCommand := Command{Name: "foobar", Aliases: []string{"f"}}
|
fooCommand := &Command{Name: "foobar", Aliases: []string{"f"}}
|
||||||
batCommand := Command{Name: "batbaz", Aliases: []string{"b"}}
|
batCommand := &Command{Name: "batbaz", Aliases: []string{"b"}}
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
fooCommand,
|
fooCommand,
|
||||||
batCommand,
|
batCommand,
|
||||||
}
|
}
|
||||||
@ -191,7 +191,7 @@ func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
|
|||||||
var context *Context
|
var context *Context
|
||||||
|
|
||||||
a := NewApp()
|
a := NewApp()
|
||||||
a.Commands = []Command{
|
a.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Action: func(c *Context) error {
|
Action: func(c *Context) error {
|
||||||
@ -199,7 +199,7 @@ func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringFlag{
|
&StringFlag{
|
||||||
Name: "lang",
|
Name: "lang",
|
||||||
Value: "english",
|
Value: "english",
|
||||||
Usage: "language for the greeting",
|
Usage: "language for the greeting",
|
||||||
@ -216,13 +216,13 @@ func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
|
|||||||
|
|
||||||
func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
|
func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
|
||||||
var parsedOption string
|
var parsedOption string
|
||||||
var args []string
|
var args Args
|
||||||
|
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
command := Command{
|
command := &Command{
|
||||||
Name: "cmd",
|
Name: "cmd",
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringFlag{Name: "option", Value: "", Usage: "some option"},
|
&StringFlag{Name: "option", Value: "", Usage: "some option"},
|
||||||
},
|
},
|
||||||
Action: func(c *Context) error {
|
Action: func(c *Context) error {
|
||||||
parsedOption = c.String("option")
|
parsedOption = c.String("option")
|
||||||
@ -230,58 +230,58 @@ func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
app.Commands = []Command{command}
|
app.Commands = []*Command{command}
|
||||||
|
|
||||||
app.Run([]string{"", "cmd", "--option", "my-option", "my-arg", "--", "--notARealFlag"})
|
app.Run([]string{"", "cmd", "--option", "my-option", "my-arg", "--", "--notARealFlag"})
|
||||||
|
|
||||||
expect(t, parsedOption, "my-option")
|
expect(t, parsedOption, "my-option")
|
||||||
expect(t, args[0], "my-arg")
|
expect(t, args.Get(0), "my-arg")
|
||||||
expect(t, args[1], "--")
|
expect(t, args.Get(1), "--")
|
||||||
expect(t, args[2], "--notARealFlag")
|
expect(t, args.Get(2), "--notARealFlag")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestApp_CommandWithDash(t *testing.T) {
|
func TestApp_CommandWithDash(t *testing.T) {
|
||||||
var args []string
|
var args Args
|
||||||
|
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
command := Command{
|
command := &Command{
|
||||||
Name: "cmd",
|
Name: "cmd",
|
||||||
Action: func(c *Context) error {
|
Action: func(c *Context) error {
|
||||||
args = c.Args()
|
args = c.Args()
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
app.Commands = []Command{command}
|
app.Commands = []*Command{command}
|
||||||
|
|
||||||
app.Run([]string{"", "cmd", "my-arg", "-"})
|
app.Run([]string{"", "cmd", "my-arg", "-"})
|
||||||
|
|
||||||
expect(t, args[0], "my-arg")
|
expect(t, args.Get(0), "my-arg")
|
||||||
expect(t, args[1], "-")
|
expect(t, args.Get(1), "-")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
|
func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
|
||||||
var args []string
|
var args Args
|
||||||
|
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
command := Command{
|
command := &Command{
|
||||||
Name: "cmd",
|
Name: "cmd",
|
||||||
Action: func(c *Context) error {
|
Action: func(c *Context) error {
|
||||||
args = c.Args()
|
args = c.Args()
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
app.Commands = []Command{command}
|
app.Commands = []*Command{command}
|
||||||
|
|
||||||
app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"})
|
app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"})
|
||||||
|
|
||||||
expect(t, args[0], "my-arg")
|
expect(t, args.Get(0), "my-arg")
|
||||||
expect(t, args[1], "--")
|
expect(t, args.Get(1), "--")
|
||||||
expect(t, args[2], "notAFlagAtAll")
|
expect(t, args.Get(2), "notAFlagAtAll")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestApp_VisibleCommands(t *testing.T) {
|
func TestApp_VisibleCommands(t *testing.T) {
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "frob",
|
Name: "frob",
|
||||||
HelpName: "foo frob",
|
HelpName: "foo frob",
|
||||||
@ -296,7 +296,7 @@ func TestApp_VisibleCommands(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.Setup()
|
app.Setup()
|
||||||
expected := []Command{
|
expected := []*Command{
|
||||||
app.Commands[0],
|
app.Commands[0],
|
||||||
app.Commands[2], // help
|
app.Commands[2], // help
|
||||||
}
|
}
|
||||||
@ -310,14 +310,22 @@ func TestApp_VisibleCommands(t *testing.T) {
|
|||||||
expect(t, fmt.Sprintf("%p", expectedCommand.Action), fmt.Sprintf("%p", actualCommand.Action))
|
expect(t, fmt.Sprintf("%p", expectedCommand.Action), fmt.Sprintf("%p", actualCommand.Action))
|
||||||
}
|
}
|
||||||
|
|
||||||
// nil out funcs, as they cannot be compared
|
func() {
|
||||||
// (https://github.com/golang/go/issues/8554)
|
// nil out funcs, as they cannot be compared
|
||||||
expectedCommand.Action = nil
|
// (https://github.com/golang/go/issues/8554)
|
||||||
actualCommand.Action = nil
|
expectedAction := expectedCommand.Action
|
||||||
|
actualAction := actualCommand.Action
|
||||||
|
defer func() {
|
||||||
|
expectedCommand.Action = expectedAction
|
||||||
|
actualCommand.Action = actualAction
|
||||||
|
}()
|
||||||
|
expectedCommand.Action = nil
|
||||||
|
actualCommand.Action = nil
|
||||||
|
|
||||||
if !reflect.DeepEqual(expectedCommand, actualCommand) {
|
if !reflect.DeepEqual(expectedCommand, actualCommand) {
|
||||||
t.Errorf("expected\n%#v\n!=\n%#v", expectedCommand, actualCommand)
|
t.Errorf("expected\n%#v\n!=\n%#v", expectedCommand, actualCommand)
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,7 +334,7 @@ func TestApp_Float64Flag(t *testing.T) {
|
|||||||
|
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Flags = []Flag{
|
app.Flags = []Flag{
|
||||||
Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
|
&Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
|
||||||
}
|
}
|
||||||
app.Action = func(c *Context) error {
|
app.Action = func(c *Context) error {
|
||||||
meters = c.Float64("height")
|
meters = c.Float64("height")
|
||||||
@ -343,11 +351,11 @@ func TestApp_ParseSliceFlags(t *testing.T) {
|
|||||||
var parsedStringSlice []string
|
var parsedStringSlice []string
|
||||||
|
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
command := Command{
|
command := &Command{
|
||||||
Name: "cmd",
|
Name: "cmd",
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntSliceFlag{Name: "p", Value: NewIntSlice(), Usage: "set one or more ip addr"},
|
&IntSliceFlag{Name: "p", Value: NewIntSlice(), Usage: "set one or more ip addr"},
|
||||||
StringSliceFlag{Name: "ip", Value: NewStringSlice(), Usage: "set one or more ports to open"},
|
&StringSliceFlag{Name: "ip", Value: NewStringSlice(), Usage: "set one or more ports to open"},
|
||||||
},
|
},
|
||||||
Action: func(c *Context) error {
|
Action: func(c *Context) error {
|
||||||
parsedIntSlice = c.IntSlice("p")
|
parsedIntSlice = c.IntSlice("p")
|
||||||
@ -357,7 +365,7 @@ func TestApp_ParseSliceFlags(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
app.Commands = []Command{command}
|
app.Commands = []*Command{command}
|
||||||
|
|
||||||
app.Run([]string{"", "cmd", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4", "my-arg"})
|
app.Run([]string{"", "cmd", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4", "my-arg"})
|
||||||
|
|
||||||
@ -401,11 +409,11 @@ func TestApp_ParseSliceFlagsWithMissingValue(t *testing.T) {
|
|||||||
var parsedStringSlice []string
|
var parsedStringSlice []string
|
||||||
|
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
command := Command{
|
command := &Command{
|
||||||
Name: "cmd",
|
Name: "cmd",
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntSliceFlag{Name: "a", Usage: "set numbers"},
|
&IntSliceFlag{Name: "a", Usage: "set numbers"},
|
||||||
StringSliceFlag{Name: "str", Usage: "set strings"},
|
&StringSliceFlag{Name: "str", Usage: "set strings"},
|
||||||
},
|
},
|
||||||
Action: func(c *Context) error {
|
Action: func(c *Context) error {
|
||||||
parsedIntSlice = c.IntSlice("a")
|
parsedIntSlice = c.IntSlice("a")
|
||||||
@ -413,7 +421,7 @@ func TestApp_ParseSliceFlagsWithMissingValue(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
app.Commands = []Command{command}
|
app.Commands = []*Command{command}
|
||||||
|
|
||||||
app.Run([]string{"", "cmd", "-a", "2", "-str", "A", "my-arg"})
|
app.Run([]string{"", "cmd", "-a", "2", "-str", "A", "my-arg"})
|
||||||
|
|
||||||
@ -491,7 +499,7 @@ func TestApp_BeforeFunc(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "sub",
|
Name: "sub",
|
||||||
Action: func(c *Context) error {
|
Action: func(c *Context) error {
|
||||||
@ -503,7 +511,7 @@ func TestApp_BeforeFunc(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.Flags = []Flag{
|
app.Flags = []Flag{
|
||||||
StringFlag{Name: "opt"},
|
&StringFlag{Name: "opt"},
|
||||||
}
|
}
|
||||||
|
|
||||||
// run with the Before() func succeeding
|
// run with the Before() func succeeding
|
||||||
@ -583,7 +591,7 @@ func TestApp_AfterFunc(t *testing.T) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "sub",
|
Name: "sub",
|
||||||
Action: func(c *Context) error {
|
Action: func(c *Context) error {
|
||||||
@ -595,7 +603,7 @@ func TestApp_AfterFunc(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.Flags = []Flag{
|
app.Flags = []Flag{
|
||||||
StringFlag{Name: "opt"},
|
&StringFlag{Name: "opt"},
|
||||||
}
|
}
|
||||||
|
|
||||||
// run with the After() func succeeding
|
// run with the After() func succeeding
|
||||||
@ -639,7 +647,7 @@ func TestAppNoHelpFlag(t *testing.T) {
|
|||||||
HelpFlag = oldFlag
|
HelpFlag = oldFlag
|
||||||
}()
|
}()
|
||||||
|
|
||||||
HelpFlag = BoolFlag{}
|
HelpFlag = nil
|
||||||
|
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Writer = ioutil.Discard
|
app.Writer = ioutil.Discard
|
||||||
@ -698,7 +706,7 @@ func TestApp_CommandNotFound(t *testing.T) {
|
|||||||
counts.CommandNotFound = counts.Total
|
counts.CommandNotFound = counts.Total
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
Action: func(c *Context) error {
|
Action: func(c *Context) error {
|
||||||
@ -765,7 +773,7 @@ func TestApp_OrderOfOperations(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.After = afterNoError
|
app.After = afterNoError
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
Action: func(c *Context) error {
|
Action: func(c *Context) error {
|
||||||
@ -871,21 +879,21 @@ func TestApp_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) {
|
|||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
app.Writer = buf
|
app.Writer = buf
|
||||||
|
|
||||||
subCmdBar := Command{
|
subCmdBar := &Command{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
Usage: "does bar things",
|
Usage: "does bar things",
|
||||||
}
|
}
|
||||||
subCmdBaz := Command{
|
subCmdBaz := &Command{
|
||||||
Name: "baz",
|
Name: "baz",
|
||||||
Usage: "does baz things",
|
Usage: "does baz things",
|
||||||
}
|
}
|
||||||
cmd := Command{
|
cmd := &Command{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Description: "descriptive wall of text about how it does foo things",
|
Description: "descriptive wall of text about how it does foo things",
|
||||||
Subcommands: []Command{subCmdBar, subCmdBaz},
|
Subcommands: []*Command{subCmdBar, subCmdBaz},
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Commands = []Command{cmd}
|
app.Commands = []*Command{cmd}
|
||||||
err := app.Run(flagSet)
|
err := app.Run(flagSet)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -916,16 +924,16 @@ func TestApp_Run_SubcommandFullPath(t *testing.T) {
|
|||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
app.Writer = buf
|
app.Writer = buf
|
||||||
app.Name = "command"
|
app.Name = "command"
|
||||||
subCmd := Command{
|
subCmd := &Command{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
Usage: "does bar things",
|
Usage: "does bar things",
|
||||||
}
|
}
|
||||||
cmd := Command{
|
cmd := &Command{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Description: "foo commands",
|
Description: "foo commands",
|
||||||
Subcommands: []Command{subCmd},
|
Subcommands: []*Command{subCmd},
|
||||||
}
|
}
|
||||||
app.Commands = []Command{cmd}
|
app.Commands = []*Command{cmd}
|
||||||
|
|
||||||
err := app.Run([]string{"command", "foo", "bar", "--help"})
|
err := app.Run([]string{"command", "foo", "bar", "--help"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -933,11 +941,14 @@ func TestApp_Run_SubcommandFullPath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
output := buf.String()
|
output := buf.String()
|
||||||
if !strings.Contains(output, "command foo bar - does bar things") {
|
expected := "command foo bar - does bar things"
|
||||||
t.Errorf("expected full path to subcommand: %s", output)
|
if !strings.Contains(output, expected) {
|
||||||
|
t.Errorf("expected %q in output: %s", expected, output)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, "command foo bar [arguments...]") {
|
|
||||||
t.Errorf("expected full path to subcommand: %s", output)
|
expected = "command foo bar [command options] [arguments...]"
|
||||||
|
if !strings.Contains(output, expected) {
|
||||||
|
t.Errorf("expected %q in output: %s", expected, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -946,17 +957,17 @@ func TestApp_Run_SubcommandHelpName(t *testing.T) {
|
|||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
app.Writer = buf
|
app.Writer = buf
|
||||||
app.Name = "command"
|
app.Name = "command"
|
||||||
subCmd := Command{
|
subCmd := &Command{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
HelpName: "custom",
|
HelpName: "custom",
|
||||||
Usage: "does bar things",
|
Usage: "does bar things",
|
||||||
}
|
}
|
||||||
cmd := Command{
|
cmd := &Command{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Description: "foo commands",
|
Description: "foo commands",
|
||||||
Subcommands: []Command{subCmd},
|
Subcommands: []*Command{subCmd},
|
||||||
}
|
}
|
||||||
app.Commands = []Command{cmd}
|
app.Commands = []*Command{cmd}
|
||||||
|
|
||||||
err := app.Run([]string{"command", "foo", "bar", "--help"})
|
err := app.Run([]string{"command", "foo", "bar", "--help"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -964,11 +975,15 @@ func TestApp_Run_SubcommandHelpName(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
output := buf.String()
|
output := buf.String()
|
||||||
if !strings.Contains(output, "custom - does bar things") {
|
|
||||||
t.Errorf("expected HelpName for subcommand: %s", output)
|
expected := "custom - does bar things"
|
||||||
|
if !strings.Contains(output, expected) {
|
||||||
|
t.Errorf("expected %q in output: %s", expected, output)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, "custom [arguments...]") {
|
|
||||||
t.Errorf("expected HelpName to subcommand: %s", output)
|
expected = "custom [command options] [arguments...]"
|
||||||
|
if !strings.Contains(output, expected) {
|
||||||
|
t.Errorf("expected %q in output: %s", expected, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -977,17 +992,17 @@ func TestApp_Run_CommandHelpName(t *testing.T) {
|
|||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
app.Writer = buf
|
app.Writer = buf
|
||||||
app.Name = "command"
|
app.Name = "command"
|
||||||
subCmd := Command{
|
subCmd := &Command{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
Usage: "does bar things",
|
Usage: "does bar things",
|
||||||
}
|
}
|
||||||
cmd := Command{
|
cmd := &Command{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
HelpName: "custom",
|
HelpName: "custom",
|
||||||
Description: "foo commands",
|
Description: "foo commands",
|
||||||
Subcommands: []Command{subCmd},
|
Subcommands: []*Command{subCmd},
|
||||||
}
|
}
|
||||||
app.Commands = []Command{cmd}
|
app.Commands = []*Command{cmd}
|
||||||
|
|
||||||
err := app.Run([]string{"command", "foo", "bar", "--help"})
|
err := app.Run([]string{"command", "foo", "bar", "--help"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -995,11 +1010,15 @@ func TestApp_Run_CommandHelpName(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
output := buf.String()
|
output := buf.String()
|
||||||
if !strings.Contains(output, "command foo bar - does bar things") {
|
|
||||||
t.Errorf("expected full path to subcommand: %s", output)
|
expected := "command foo bar - does bar things"
|
||||||
|
if !strings.Contains(output, expected) {
|
||||||
|
t.Errorf("expected %q in output: %s", expected, output)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, "command foo bar [arguments...]") {
|
|
||||||
t.Errorf("expected full path to subcommand: %s", output)
|
expected = "command foo bar [command options] [arguments...]"
|
||||||
|
if !strings.Contains(output, expected) {
|
||||||
|
t.Errorf("expected %q in output: %s", expected, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1008,17 +1027,17 @@ func TestApp_Run_CommandSubcommandHelpName(t *testing.T) {
|
|||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
app.Writer = buf
|
app.Writer = buf
|
||||||
app.Name = "base"
|
app.Name = "base"
|
||||||
subCmd := Command{
|
subCmd := &Command{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
HelpName: "custom",
|
HelpName: "custom",
|
||||||
Usage: "does bar things",
|
Usage: "does bar things",
|
||||||
}
|
}
|
||||||
cmd := Command{
|
cmd := &Command{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Description: "foo commands",
|
Description: "foo commands",
|
||||||
Subcommands: []Command{subCmd},
|
Subcommands: []*Command{subCmd},
|
||||||
}
|
}
|
||||||
app.Commands = []Command{cmd}
|
app.Commands = []*Command{cmd}
|
||||||
|
|
||||||
err := app.Run([]string{"command", "foo", "--help"})
|
err := app.Run([]string{"command", "foo", "--help"})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1026,11 +1045,15 @@ func TestApp_Run_CommandSubcommandHelpName(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
output := buf.String()
|
output := buf.String()
|
||||||
if !strings.Contains(output, "base foo - foo commands") {
|
|
||||||
t.Errorf("expected full path to subcommand: %s", output)
|
expected := "base foo - foo commands"
|
||||||
|
if !strings.Contains(output, expected) {
|
||||||
|
t.Errorf("expected %q in output: %q", expected, output)
|
||||||
}
|
}
|
||||||
if !strings.Contains(output, "base foo command [command options] [arguments...]") {
|
|
||||||
t.Errorf("expected full path to subcommand: %s", output)
|
expected = "base foo command [command options] [arguments...]"
|
||||||
|
if !strings.Contains(output, expected) {
|
||||||
|
t.Errorf("expected %q in output: %q", expected, output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1100,7 +1123,7 @@ func TestApp_Run_Version(t *testing.T) {
|
|||||||
func TestApp_Run_Categories(t *testing.T) {
|
func TestApp_Run_Categories(t *testing.T) {
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Name = "categories"
|
app.Name = "categories"
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "command1",
|
Name: "command1",
|
||||||
Category: "1",
|
Category: "1",
|
||||||
@ -1119,23 +1142,24 @@ func TestApp_Run_Categories(t *testing.T) {
|
|||||||
|
|
||||||
app.Run([]string{"categories"})
|
app.Run([]string{"categories"})
|
||||||
|
|
||||||
expect := CommandCategories{
|
expect := commandCategories([]*commandCategory{
|
||||||
&CommandCategory{
|
{
|
||||||
Name: "1",
|
name: "1",
|
||||||
Commands: []Command{
|
commands: []*Command{
|
||||||
app.Commands[0],
|
app.Commands[0],
|
||||||
app.Commands[1],
|
app.Commands[1],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
&CommandCategory{
|
{
|
||||||
Name: "2",
|
name: "2",
|
||||||
Commands: []Command{
|
commands: []*Command{
|
||||||
app.Commands[2],
|
app.Commands[2],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
})
|
||||||
if !reflect.DeepEqual(app.Categories(), expect) {
|
|
||||||
t.Fatalf("expected categories %#v, to equal %#v", app.Categories(), expect)
|
if !reflect.DeepEqual(app.Categories, &expect) {
|
||||||
|
t.Fatalf("expected categories %#v, to equal %#v", app.Categories, &expect)
|
||||||
}
|
}
|
||||||
|
|
||||||
output := buf.String()
|
output := buf.String()
|
||||||
@ -1149,7 +1173,7 @@ func TestApp_Run_Categories(t *testing.T) {
|
|||||||
func TestApp_VisibleCategories(t *testing.T) {
|
func TestApp_VisibleCategories(t *testing.T) {
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Name = "visible-categories"
|
app.Name = "visible-categories"
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "command1",
|
Name: "command1",
|
||||||
Category: "1",
|
Category: "1",
|
||||||
@ -1168,16 +1192,16 @@ func TestApp_VisibleCategories(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := []*CommandCategory{
|
expected := []CommandCategory{
|
||||||
{
|
&commandCategory{
|
||||||
Name: "2",
|
name: "2",
|
||||||
Commands: []Command{
|
commands: []*Command{
|
||||||
app.Commands[1],
|
app.Commands[1],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
&commandCategory{
|
||||||
Name: "3",
|
name: "3",
|
||||||
Commands: []Command{
|
commands: []*Command{
|
||||||
app.Commands[2],
|
app.Commands[2],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1188,7 +1212,7 @@ func TestApp_VisibleCategories(t *testing.T) {
|
|||||||
|
|
||||||
app = NewApp()
|
app = NewApp()
|
||||||
app.Name = "visible-categories"
|
app.Name = "visible-categories"
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "command1",
|
Name: "command1",
|
||||||
Category: "1",
|
Category: "1",
|
||||||
@ -1208,10 +1232,10 @@ func TestApp_VisibleCategories(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
expected = []*CommandCategory{
|
expected = []CommandCategory{
|
||||||
{
|
&commandCategory{
|
||||||
Name: "3",
|
name: "3",
|
||||||
Commands: []Command{
|
commands: []*Command{
|
||||||
app.Commands[2],
|
app.Commands[2],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1222,7 +1246,7 @@ func TestApp_VisibleCategories(t *testing.T) {
|
|||||||
|
|
||||||
app = NewApp()
|
app = NewApp()
|
||||||
app.Name = "visible-categories"
|
app.Name = "visible-categories"
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "command1",
|
Name: "command1",
|
||||||
Category: "1",
|
Category: "1",
|
||||||
@ -1243,10 +1267,8 @@ func TestApp_VisibleCategories(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
expected = []*CommandCategory{}
|
|
||||||
|
|
||||||
app.Setup()
|
app.Setup()
|
||||||
expect(t, expected, app.VisibleCategories())
|
expect(t, []CommandCategory{}, app.VisibleCategories())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
|
func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
|
||||||
@ -1270,9 +1292,9 @@ func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
|
|||||||
|
|
||||||
func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
|
func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Subcommands: []Command{
|
Subcommands: []*Command{
|
||||||
{
|
{
|
||||||
Name: "sub",
|
Name: "sub",
|
||||||
},
|
},
|
||||||
@ -1299,7 +1321,7 @@ func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
|
|||||||
func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) {
|
func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) {
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Flags = []Flag{
|
app.Flags = []Flag{
|
||||||
IntFlag{Name: "flag"},
|
&IntFlag{Name: "flag"},
|
||||||
}
|
}
|
||||||
app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
|
app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
|
||||||
if isSubcommand {
|
if isSubcommand {
|
||||||
@ -1310,7 +1332,7 @@ func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) {
|
|||||||
}
|
}
|
||||||
return errors.New("intercepted: " + err.Error())
|
return errors.New("intercepted: " + err.Error())
|
||||||
}
|
}
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
},
|
},
|
||||||
@ -1329,7 +1351,7 @@ func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) {
|
|||||||
func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) {
|
func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) {
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Flags = []Flag{
|
app.Flags = []Flag{
|
||||||
IntFlag{Name: "flag"},
|
&IntFlag{Name: "flag"},
|
||||||
}
|
}
|
||||||
app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
|
app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
|
||||||
if isSubcommand {
|
if isSubcommand {
|
||||||
@ -1340,7 +1362,7 @@ func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) {
|
|||||||
}
|
}
|
||||||
return errors.New("intercepted: " + err.Error())
|
return errors.New("intercepted: " + err.Error())
|
||||||
}
|
}
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
},
|
},
|
||||||
|
27
appveyor.yml
27
appveyor.yml
@ -2,15 +2,24 @@ version: "{build}"
|
|||||||
|
|
||||||
os: Windows Server 2012 R2
|
os: Windows Server 2012 R2
|
||||||
|
|
||||||
|
clone_folder: c:\gopath\src\github.com\urfave\cli
|
||||||
|
|
||||||
|
environment:
|
||||||
|
GOPATH: C:\gopath
|
||||||
|
GOVERSION: 1.6
|
||||||
|
PYTHON: C:\Python27-x64
|
||||||
|
PYTHON_VERSION: 2.7.x
|
||||||
|
PYTHON_ARCH: 64
|
||||||
|
GFMXR_DEBUG: 1
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- go version
|
- set PATH=%GOPATH%\bin;C:\go\bin;%PATH%
|
||||||
- go env
|
- go version
|
||||||
|
- go env
|
||||||
|
- go get github.com/urfave/gfmxr/...
|
||||||
|
- go get -v -t ./...
|
||||||
|
|
||||||
build_script:
|
build_script:
|
||||||
- cd %APPVEYOR_BUILD_FOLDER%
|
- python runtests vet
|
||||||
- go vet ./...
|
- python runtests test
|
||||||
- go test -v ./...
|
- python runtests gfmxr
|
||||||
|
|
||||||
test: off
|
|
||||||
|
|
||||||
deploy: off
|
|
||||||
|
60
args.go
Normal file
60
args.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package cli
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var (
|
||||||
|
argsRangeErr = errors.New("index out of range")
|
||||||
|
)
|
||||||
|
|
||||||
|
type Args interface {
|
||||||
|
// Get returns the nth argument, or else a blank string
|
||||||
|
Get(n int) string
|
||||||
|
// First returns the first argument, or else a blank string
|
||||||
|
First() string
|
||||||
|
// Tail returns the rest of the arguments (not the first one)
|
||||||
|
// or else an empty string slice
|
||||||
|
Tail() []string
|
||||||
|
// Len returns the length of the wrapped slice
|
||||||
|
Len() int
|
||||||
|
// Present checks if there are any arguments present
|
||||||
|
Present() bool
|
||||||
|
// Slice returns a copy of the internal slice
|
||||||
|
Slice() []string
|
||||||
|
}
|
||||||
|
|
||||||
|
type args []string
|
||||||
|
|
||||||
|
func (a *args) Get(n int) string {
|
||||||
|
if len(*a) > n {
|
||||||
|
return (*a)[n]
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *args) First() string {
|
||||||
|
return a.Get(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *args) Tail() []string {
|
||||||
|
if a.Len() >= 2 {
|
||||||
|
tail := []string((*a)[1:])
|
||||||
|
ret := make([]string, len(tail))
|
||||||
|
copy(ret, tail)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *args) Len() int {
|
||||||
|
return len(*a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *args) Present() bool {
|
||||||
|
return a.Len() != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *args) Slice() []string {
|
||||||
|
ret := make([]string, len(*a))
|
||||||
|
copy(ret, []string(*a))
|
||||||
|
return ret
|
||||||
|
}
|
89
category.go
89
category.go
@ -1,41 +1,82 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
// CommandCategories is a slice of *CommandCategory.
|
type CommandCategories interface {
|
||||||
type CommandCategories []*CommandCategory
|
// AddCommand adds a command to a category, creating a new category if necessary.
|
||||||
|
AddCommand(category string, command *Command)
|
||||||
// CommandCategory is a category containing commands.
|
// Categories returns a copy of the category slice
|
||||||
type CommandCategory struct {
|
Categories() []CommandCategory
|
||||||
Name string
|
|
||||||
Commands Commands
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c CommandCategories) Less(i, j int) bool {
|
type commandCategories []*commandCategory
|
||||||
return c[i].Name < c[j].Name
|
|
||||||
|
func newCommandCategories() CommandCategories {
|
||||||
|
ret := commandCategories([]*commandCategory{})
|
||||||
|
return &ret
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c CommandCategories) Len() int {
|
func (c *commandCategories) Less(i, j int) bool {
|
||||||
return len(c)
|
return (*c)[i].Name() < (*c)[j].Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c CommandCategories) Swap(i, j int) {
|
func (c *commandCategories) Len() int {
|
||||||
c[i], c[j] = c[j], c[i]
|
return len(*c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddCommand adds a command to a category.
|
func (c *commandCategories) Swap(i, j int) {
|
||||||
func (c CommandCategories) AddCommand(category string, command Command) CommandCategories {
|
(*c)[i], (*c)[j] = (*c)[j], (*c)[i]
|
||||||
for _, commandCategory := range c {
|
}
|
||||||
if commandCategory.Name == category {
|
|
||||||
commandCategory.Commands = append(commandCategory.Commands, command)
|
func (c *commandCategories) AddCommand(category string, command *Command) {
|
||||||
return c
|
for _, commandCategory := range []*commandCategory(*c) {
|
||||||
|
if commandCategory.name == category {
|
||||||
|
commandCategory.commands = append(commandCategory.commands, command)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return append(c, &CommandCategory{Name: category, Commands: []Command{command}})
|
newVal := commandCategories(append(*c,
|
||||||
|
&commandCategory{name: category, commands: []*Command{command}}))
|
||||||
|
(*c) = newVal
|
||||||
}
|
}
|
||||||
|
|
||||||
// VisibleCommands returns a slice of the Commands with Hidden=false
|
func (c *commandCategories) Categories() []CommandCategory {
|
||||||
func (c *CommandCategory) VisibleCommands() []Command {
|
ret := make([]CommandCategory, len(*c))
|
||||||
ret := []Command{}
|
for i, cat := range *c {
|
||||||
for _, command := range c.Commands {
|
ret[i] = cat
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// CommandCategory is a category containing commands.
|
||||||
|
type CommandCategory interface {
|
||||||
|
// Name returns the category name string
|
||||||
|
Name() string
|
||||||
|
// VisibleCommands returns a slice of the Commands with Hidden=false
|
||||||
|
VisibleCommands() []*Command
|
||||||
|
}
|
||||||
|
|
||||||
|
type commandCategory struct {
|
||||||
|
name string
|
||||||
|
commands []*Command
|
||||||
|
}
|
||||||
|
|
||||||
|
func newCommandCategory(name string) *commandCategory {
|
||||||
|
return &commandCategory{
|
||||||
|
name: name,
|
||||||
|
commands: []*Command{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *commandCategory) Name() string {
|
||||||
|
return c.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *commandCategory) VisibleCommands() []*Command {
|
||||||
|
if c.commands == nil {
|
||||||
|
c.commands = []*Command{}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret := []*Command{}
|
||||||
|
for _, command := range c.commands {
|
||||||
if !command.Hidden {
|
if !command.Hidden {
|
||||||
ret = append(ret, command)
|
ret = append(ret, command)
|
||||||
}
|
}
|
||||||
|
55
command.go
55
command.go
@ -36,7 +36,7 @@ type Command struct {
|
|||||||
// Execute this function if a usage error occurs.
|
// Execute this function if a usage error occurs.
|
||||||
OnUsageError OnUsageErrorFunc
|
OnUsageError OnUsageErrorFunc
|
||||||
// List of child commands
|
// List of child commands
|
||||||
Subcommands Commands
|
Subcommands []*Command
|
||||||
// List of flags to parse
|
// List of flags to parse
|
||||||
Flags []Flag
|
Flags []Flag
|
||||||
// Treat all flags as normal arguments if true
|
// Treat all flags as normal arguments if true
|
||||||
@ -53,32 +53,26 @@ type Command struct {
|
|||||||
|
|
||||||
// FullName returns the full name of the command.
|
// FullName returns the full name of the command.
|
||||||
// For subcommands this ensures that parent commands are part of the command path
|
// For subcommands this ensures that parent commands are part of the command path
|
||||||
func (c Command) FullName() string {
|
func (c *Command) FullName() string {
|
||||||
if c.commandNamePath == nil {
|
if c.commandNamePath == nil {
|
||||||
return c.Name
|
return c.Name
|
||||||
}
|
}
|
||||||
return strings.Join(c.commandNamePath, " ")
|
return strings.Join(c.commandNamePath, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commands is a slice of Command
|
|
||||||
type Commands []Command
|
|
||||||
|
|
||||||
// Run invokes the command given the context, parses ctx.Args() to generate command-specific flags
|
// Run invokes the command given the context, parses ctx.Args() to generate command-specific flags
|
||||||
func (c Command) Run(ctx *Context) (err error) {
|
func (c *Command) Run(ctx *Context) (err error) {
|
||||||
if len(c.Subcommands) > 0 {
|
if len(c.Subcommands) > 0 {
|
||||||
return c.startApp(ctx)
|
return c.startApp(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.HideHelp && (HelpFlag != BoolFlag{}) {
|
if !c.HideHelp && HelpFlag != nil {
|
||||||
// append help to flags
|
// append help to flags
|
||||||
c.Flags = append(
|
c.appendFlag(HelpFlag)
|
||||||
c.Flags,
|
|
||||||
HelpFlag,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.App.EnableBashCompletion {
|
if ctx.App.EnableBashCompletion {
|
||||||
c.Flags = append(c.Flags, BashCompletionFlag)
|
c.appendFlag(BashCompletionFlag)
|
||||||
}
|
}
|
||||||
|
|
||||||
set := flagSet(c.Name, c.Flags)
|
set := flagSet(c.Name, c.Flags)
|
||||||
@ -96,7 +90,7 @@ func (c Command) Run(ctx *Context) (err error) {
|
|||||||
HandleExitCoder(err)
|
HandleExitCoder(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.")
|
fmt.Fprintf(ctx.App.Writer, "Incorrect Usage: %s\n\n", err)
|
||||||
fmt.Fprintln(ctx.App.Writer)
|
fmt.Fprintln(ctx.App.Writer)
|
||||||
ShowCommandHelp(ctx, c.Name)
|
ShowCommandHelp(ctx, c.Name)
|
||||||
return err
|
return err
|
||||||
@ -126,7 +120,7 @@ func (c Command) Run(ctx *Context) (err error) {
|
|||||||
if afterErr != nil {
|
if afterErr != nil {
|
||||||
HandleExitCoder(err)
|
HandleExitCoder(err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = NewMultiError(err, afterErr)
|
err = newMultiError(err, afterErr)
|
||||||
} else {
|
} else {
|
||||||
err = afterErr
|
err = afterErr
|
||||||
}
|
}
|
||||||
@ -155,13 +149,12 @@ func (c Command) Run(ctx *Context) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Names returns the names including short names and aliases.
|
// Names returns the names including short names and aliases.
|
||||||
func (c Command) Names() []string {
|
func (c *Command) Names() []string {
|
||||||
names := []string{c.Name}
|
return append([]string{c.Name}, c.Aliases...)
|
||||||
return append(names, c.Aliases...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasName returns true if Command.Name matches given name
|
// HasName returns true if Command.Name matches given name
|
||||||
func (c Command) HasName(name string) bool {
|
func (c *Command) HasName(name string) bool {
|
||||||
for _, n := range c.Names() {
|
for _, n := range c.Names() {
|
||||||
if n == name {
|
if n == name {
|
||||||
return true
|
return true
|
||||||
@ -170,7 +163,7 @@ func (c Command) HasName(name string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Command) startApp(ctx *Context) error {
|
func (c *Command) startApp(ctx *Context) error {
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Metadata = ctx.App.Metadata
|
app.Metadata = ctx.App.Metadata
|
||||||
// set the name and usage
|
// set the name and usage
|
||||||
@ -200,12 +193,12 @@ func (c Command) startApp(ctx *Context) error {
|
|||||||
app.Compiled = ctx.App.Compiled
|
app.Compiled = ctx.App.Compiled
|
||||||
app.Writer = ctx.App.Writer
|
app.Writer = ctx.App.Writer
|
||||||
|
|
||||||
app.categories = CommandCategories{}
|
app.Categories = newCommandCategories()
|
||||||
for _, command := range c.Subcommands {
|
for _, command := range c.Subcommands {
|
||||||
app.categories = app.categories.AddCommand(command.Category, command)
|
app.Categories.AddCommand(command.Category, command)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(app.categories)
|
sort.Sort(app.Categories.(*commandCategories))
|
||||||
|
|
||||||
// bash completion
|
// bash completion
|
||||||
app.EnableBashCompletion = ctx.App.EnableBashCompletion
|
app.EnableBashCompletion = ctx.App.EnableBashCompletion
|
||||||
@ -230,6 +223,22 @@ func (c Command) startApp(ctx *Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// VisibleFlags returns a slice of the Flags with Hidden=false
|
// VisibleFlags returns a slice of the Flags with Hidden=false
|
||||||
func (c Command) VisibleFlags() []Flag {
|
func (c *Command) VisibleFlags() []Flag {
|
||||||
return visibleFlags(c.Flags)
|
return visibleFlags(c.Flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Command) appendFlag(fl Flag) {
|
||||||
|
if !hasFlag(c.Flags, fl) {
|
||||||
|
c.Flags = append(c.Flags, fl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasCommand(commands []*Command, command *Command) bool {
|
||||||
|
for _, existing := range commands {
|
||||||
|
if command == existing {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -42,13 +42,13 @@ func TestCommandFlagParsing(t *testing.T) {
|
|||||||
err := command.Run(context)
|
err := command.Run(context)
|
||||||
|
|
||||||
expect(t, err, c.expectedErr)
|
expect(t, err, c.expectedErr)
|
||||||
expect(t, []string(context.Args()), c.testArgs)
|
expect(t, context.Args().Slice(), c.testArgs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
|
func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
Before: func(c *Context) error {
|
Before: func(c *Context) error {
|
||||||
@ -75,11 +75,11 @@ func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
|
|||||||
|
|
||||||
func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) {
|
func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) {
|
||||||
app := NewApp()
|
app := NewApp()
|
||||||
app.Commands = []Command{
|
app.Commands = []*Command{
|
||||||
{
|
{
|
||||||
Name: "bar",
|
Name: "bar",
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntFlag{Name: "flag"},
|
&IntFlag{Name: "flag"},
|
||||||
},
|
},
|
||||||
OnUsageError: func(c *Context, err error, _ bool) error {
|
OnUsageError: func(c *Context, err error, _ bool) error {
|
||||||
if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") {
|
if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") {
|
||||||
|
51
context.go
51
context.go
@ -10,11 +10,11 @@ import (
|
|||||||
|
|
||||||
// Context is a type that is passed through to
|
// Context is a type that is passed through to
|
||||||
// each Handler action in a cli application. Context
|
// each Handler action in a cli application. Context
|
||||||
// can be used to retrieve context-specific Args and
|
// can be used to retrieve context-specific args and
|
||||||
// parsed command-line options.
|
// parsed command-line options.
|
||||||
type Context struct {
|
type Context struct {
|
||||||
App *App
|
App *App
|
||||||
Command Command
|
Command *Command
|
||||||
|
|
||||||
flagSet *flag.FlagSet
|
flagSet *flag.FlagSet
|
||||||
parentContext *Context
|
parentContext *Context
|
||||||
@ -147,54 +147,15 @@ func (c *Context) Lineage() []*Context {
|
|||||||
return lineage
|
return lineage
|
||||||
}
|
}
|
||||||
|
|
||||||
// Args contains apps console arguments
|
|
||||||
type Args []string
|
|
||||||
|
|
||||||
// Args returns the command line arguments associated with the context.
|
// Args returns the command line arguments associated with the context.
|
||||||
func (c *Context) Args() Args {
|
func (c *Context) Args() Args {
|
||||||
args := Args(c.flagSet.Args())
|
ret := args(c.flagSet.Args())
|
||||||
return args
|
return &ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// NArg returns the number of the command line arguments.
|
// NArg returns the number of the command line arguments.
|
||||||
func (c *Context) NArg() int {
|
func (c *Context) NArg() int {
|
||||||
return len(c.Args())
|
return c.Args().Len()
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the nth argument, or else a blank string
|
|
||||||
func (a Args) Get(n int) string {
|
|
||||||
if len(a) > n {
|
|
||||||
return a[n]
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// First returns the first argument, or else a blank string
|
|
||||||
func (a Args) First() string {
|
|
||||||
return a.Get(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tail returns the rest of the arguments (not the first one)
|
|
||||||
// or else an empty string slice
|
|
||||||
func (a Args) Tail() []string {
|
|
||||||
if len(a) >= 2 {
|
|
||||||
return []string(a)[1:]
|
|
||||||
}
|
|
||||||
return []string{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Present checks if there are any arguments present
|
|
||||||
func (a Args) Present() bool {
|
|
||||||
return len(a) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Swap swaps arguments at the given indexes
|
|
||||||
func (a Args) Swap(from, to int) error {
|
|
||||||
if from >= len(a) || to >= len(a) {
|
|
||||||
return errors.New("index out of range")
|
|
||||||
}
|
|
||||||
a[from], a[to] = a[to], a[from]
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookupFlagSet(name string, ctx *Context) *flag.FlagSet {
|
func lookupFlagSet(name string, ctx *Context) *flag.FlagSet {
|
||||||
@ -310,7 +271,7 @@ func normalizeFlags(flags []Flag, set *flag.FlagSet) error {
|
|||||||
visited[f.Name] = true
|
visited[f.Name] = true
|
||||||
})
|
})
|
||||||
for _, f := range flags {
|
for _, f := range flags {
|
||||||
parts := strings.Split(f.GetName(), ",")
|
parts := f.Names()
|
||||||
if len(parts) == 1 {
|
if len(parts) == 1 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ func TestNewContext(t *testing.T) {
|
|||||||
globalSet.Int("myflag", 42, "doc")
|
globalSet.Int("myflag", 42, "doc")
|
||||||
globalSet.Float64("myflag64", float64(47), "doc")
|
globalSet.Float64("myflag64", float64(47), "doc")
|
||||||
globalCtx := NewContext(nil, globalSet, nil)
|
globalCtx := NewContext(nil, globalSet, nil)
|
||||||
command := Command{Name: "mycommand"}
|
command := &Command{Name: "mycommand"}
|
||||||
c := NewContext(nil, set, globalCtx)
|
c := NewContext(nil, set, globalCtx)
|
||||||
c.Command = command
|
c.Command = command
|
||||||
expect(t, c.Int("myflag"), 12)
|
expect(t, c.Int("myflag"), 12)
|
||||||
@ -63,7 +63,7 @@ func TestContext_Args(t *testing.T) {
|
|||||||
set.Bool("myflag", false, "doc")
|
set.Bool("myflag", false, "doc")
|
||||||
c := NewContext(nil, set, nil)
|
c := NewContext(nil, set, nil)
|
||||||
set.Parse([]string{"--myflag", "bat", "baz"})
|
set.Parse([]string{"--myflag", "bat", "baz"})
|
||||||
expect(t, len(c.Args()), 2)
|
expect(t, c.Args().Len(), 2)
|
||||||
expect(t, c.Bool("myflag"), true)
|
expect(t, c.Bool("myflag"), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
50
errors.go
50
errors.go
@ -15,25 +15,39 @@ var OsExiter = os.Exit
|
|||||||
var ErrWriter io.Writer = os.Stderr
|
var ErrWriter io.Writer = os.Stderr
|
||||||
|
|
||||||
// MultiError is an error that wraps multiple errors.
|
// MultiError is an error that wraps multiple errors.
|
||||||
type MultiError struct {
|
type MultiError interface {
|
||||||
Errors []error
|
error
|
||||||
|
// Errors returns a copy of the errors slice
|
||||||
|
Errors() []error
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMultiError creates a new MultiError. Pass in one or more errors.
|
// NewMultiError creates a new MultiError. Pass in one or more errors.
|
||||||
func NewMultiError(err ...error) MultiError {
|
func newMultiError(err ...error) MultiError {
|
||||||
return MultiError{Errors: err}
|
ret := multiError(err)
|
||||||
|
return &ret
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error implents the error interface.
|
type multiError []error
|
||||||
func (m MultiError) Error() string {
|
|
||||||
errs := make([]string, len(m.Errors))
|
// Error implements the error interface.
|
||||||
for i, err := range m.Errors {
|
func (m *multiError) Error() string {
|
||||||
|
errs := make([]string, len(*m))
|
||||||
|
for i, err := range *m {
|
||||||
errs[i] = err.Error()
|
errs[i] = err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.Join(errs, "\n")
|
return strings.Join(errs, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Errors returns a copy of the errors slice
|
||||||
|
func (m *multiError) Errors() []error {
|
||||||
|
errs := make([]error, len(*m))
|
||||||
|
for _, err := range *m {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
// 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 {
|
||||||
@ -41,29 +55,25 @@ type ExitCoder interface {
|
|||||||
ExitCode() int
|
ExitCode() int
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExitError fulfills both the builtin `error` interface and `ExitCoder`
|
type exitError struct {
|
||||||
type ExitError struct {
|
|
||||||
exitCode int
|
exitCode int
|
||||||
message string
|
message string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewExitError makes a new *ExitError
|
// Exit wraps a message and exit code into an ExitCoder suitable for handling by
|
||||||
func NewExitError(message string, exitCode int) *ExitError {
|
// HandleExitCoder
|
||||||
return &ExitError{
|
func Exit(message string, exitCode int) ExitCoder {
|
||||||
|
return &exitError{
|
||||||
exitCode: exitCode,
|
exitCode: exitCode,
|
||||||
message: message,
|
message: message,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error returns the string message, fulfilling the interface required by
|
func (ee *exitError) Error() string {
|
||||||
// `error`
|
|
||||||
func (ee *ExitError) Error() string {
|
|
||||||
return ee.message
|
return ee.message
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExitCode returns the exit code, fulfilling the interface required by
|
func (ee *exitError) ExitCode() int {
|
||||||
// `ExitCoder`
|
|
||||||
func (ee *ExitError) ExitCode() int {
|
|
||||||
return ee.exitCode
|
return ee.exitCode
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,7 +95,7 @@ func HandleExitCoder(err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if multiErr, ok := err.(MultiError); ok {
|
if multiErr, ok := err.(MultiError); ok {
|
||||||
for _, merr := range multiErr.Errors {
|
for _, merr := range multiErr.Errors() {
|
||||||
HandleExitCoder(merr)
|
HandleExitCoder(merr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ func TestHandleExitCoder_ExitCoder(t *testing.T) {
|
|||||||
|
|
||||||
defer func() { OsExiter = os.Exit }()
|
defer func() { OsExiter = os.Exit }()
|
||||||
|
|
||||||
HandleExitCoder(NewExitError("galactic perimeter breach", 9))
|
HandleExitCoder(Exit("galactic perimeter breach", 9))
|
||||||
|
|
||||||
expect(t, exitCode, 9)
|
expect(t, exitCode, 9)
|
||||||
expect(t, called, true)
|
expect(t, called, true)
|
||||||
@ -51,8 +51,8 @@ func TestHandleExitCoder_MultiErrorWithExitCoder(t *testing.T) {
|
|||||||
|
|
||||||
defer func() { OsExiter = os.Exit }()
|
defer func() { OsExiter = os.Exit }()
|
||||||
|
|
||||||
exitErr := NewExitError("galactic perimeter breach", 9)
|
exitErr := Exit("galactic perimeter breach", 9)
|
||||||
err := NewMultiError(errors.New("wowsa"), errors.New("egad"), exitErr)
|
err := newMultiError(errors.New("wowsa"), errors.New("egad"), exitErr)
|
||||||
HandleExitCoder(err)
|
HandleExitCoder(err)
|
||||||
|
|
||||||
expect(t, exitCode, 9)
|
expect(t, exitCode, 9)
|
||||||
|
356
flag.go
356
flag.go
@ -6,6 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@ -14,26 +15,32 @@ import (
|
|||||||
|
|
||||||
const defaultPlaceholder = "value"
|
const defaultPlaceholder = "value"
|
||||||
|
|
||||||
var slPfx = fmt.Sprintf("sl:::%d:::", time.Now().UTC().UnixNano())
|
var (
|
||||||
|
slPfx = fmt.Sprintf("sl:::%d:::", time.Now().UTC().UnixNano())
|
||||||
|
|
||||||
|
commaWhitespace = regexp.MustCompile("[, ]+.*")
|
||||||
|
)
|
||||||
|
|
||||||
// BashCompletionFlag enables bash-completion for all commands and subcommands
|
// BashCompletionFlag enables bash-completion for all commands and subcommands
|
||||||
var BashCompletionFlag = BoolFlag{
|
var BashCompletionFlag = &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 = &BoolFlag{
|
||||||
Name: "version, v",
|
Name: "version",
|
||||||
Usage: "print the version",
|
Aliases: []string{"v"},
|
||||||
|
Usage: "print the version",
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 nil to disable the flag. The subcommand
|
||||||
// unless HideHelp is set to true)
|
// will still be added unless HideHelp is set to true.
|
||||||
var HelpFlag = BoolFlag{
|
var HelpFlag = &BoolFlag{
|
||||||
Name: "help, h",
|
Name: "help",
|
||||||
Usage: "show help",
|
Aliases: []string{"h"},
|
||||||
|
Usage: "show help",
|
||||||
}
|
}
|
||||||
|
|
||||||
// FlagStringer converts a flag definition to a string. This is used by help
|
// FlagStringer converts a flag definition to a string. This is used by help
|
||||||
@ -52,7 +59,7 @@ type Flag interface {
|
|||||||
fmt.Stringer
|
fmt.Stringer
|
||||||
// Apply Flag settings to the given flag set
|
// Apply Flag settings to the given flag set
|
||||||
Apply(*flag.FlagSet)
|
Apply(*flag.FlagSet)
|
||||||
GetName() string
|
Names() []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func flagSet(name string, flags []Flag) *flag.FlagSet {
|
func flagSet(name string, flags []Flag) *flag.FlagSet {
|
||||||
@ -64,14 +71,6 @@ func flagSet(name string, flags []Flag) *flag.FlagSet {
|
|||||||
return set
|
return set
|
||||||
}
|
}
|
||||||
|
|
||||||
func eachName(longName string, fn func(string)) {
|
|
||||||
parts := strings.Split(longName, ",")
|
|
||||||
for _, name := range parts {
|
|
||||||
name = strings.Trim(name, " ")
|
|
||||||
fn(name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic is a generic parseable type identified by a specific flag
|
// Generic is a generic parseable type identified by a specific flag
|
||||||
type Generic interface {
|
type Generic interface {
|
||||||
Set(value string) error
|
Set(value string) error
|
||||||
@ -80,27 +79,27 @@ type Generic interface {
|
|||||||
|
|
||||||
// GenericFlag is the flag type for types implementing Generic
|
// GenericFlag is the flag type for types implementing Generic
|
||||||
type GenericFlag struct {
|
type GenericFlag struct {
|
||||||
Name string
|
Name string
|
||||||
Value Generic
|
Aliases []string
|
||||||
Usage string
|
Value Generic
|
||||||
EnvVar string
|
Usage string
|
||||||
Hidden bool
|
EnvVars []string
|
||||||
|
Hidden bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the string representation of the generic flag to display the
|
// String returns the string representation of the generic flag to display the
|
||||||
// help text to the user (uses the String() method of the generic flag to show
|
// help text to the user (uses the String() method of the generic flag to show
|
||||||
// the value)
|
// the value)
|
||||||
func (f GenericFlag) String() string {
|
func (f *GenericFlag) String() string {
|
||||||
return FlagStringer(f)
|
return FlagStringer(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
func (f GenericFlag) Apply(set *flag.FlagSet) {
|
func (f *GenericFlag) Apply(set *flag.FlagSet) {
|
||||||
val := f.Value
|
val := f.Value
|
||||||
if f.EnvVar != "" {
|
if f.EnvVars != nil {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range f.EnvVars {
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
val.Set(envVal)
|
val.Set(envVal)
|
||||||
break
|
break
|
||||||
@ -108,14 +107,14 @@ func (f GenericFlag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
set.Var(f.Value, name, f.Usage)
|
set.Var(val, name, f.Usage)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetName returns the name of a flag.
|
// Names returns the names of a flag.
|
||||||
func (f GenericFlag) GetName() string {
|
func (f *GenericFlag) Names() []string {
|
||||||
return f.Name
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StringSlice wraps a []string to satisfy flag.Value
|
// StringSlice wraps a []string to satisfy flag.Value
|
||||||
@ -166,23 +165,23 @@ func (f *StringSlice) Value() []string {
|
|||||||
// StringSliceFlag is a string flag that can be specified multiple times on the
|
// StringSliceFlag is a string flag that can be specified multiple times on the
|
||||||
// command-line
|
// command-line
|
||||||
type StringSliceFlag struct {
|
type StringSliceFlag struct {
|
||||||
Name string
|
Name string
|
||||||
Value *StringSlice
|
Aliases []string
|
||||||
Usage string
|
Value *StringSlice
|
||||||
EnvVar string
|
Usage string
|
||||||
Hidden bool
|
EnvVars []string
|
||||||
|
Hidden bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the usage
|
// String returns the usage
|
||||||
func (f StringSliceFlag) String() string {
|
func (f *StringSliceFlag) String() string {
|
||||||
return FlagStringer(f)
|
return FlagStringer(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
func (f StringSliceFlag) Apply(set *flag.FlagSet) {
|
func (f *StringSliceFlag) Apply(set *flag.FlagSet) {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVars != nil {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range f.EnvVars {
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
newVal := NewStringSlice()
|
newVal := NewStringSlice()
|
||||||
for _, s := range strings.Split(envVal, ",") {
|
for _, s := range strings.Split(envVal, ",") {
|
||||||
@ -199,14 +198,14 @@ func (f StringSliceFlag) Apply(set *flag.FlagSet) {
|
|||||||
f.Value = NewStringSlice()
|
f.Value = NewStringSlice()
|
||||||
}
|
}
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
set.Var(f.Value, name, f.Usage)
|
set.Var(f.Value, name, f.Usage)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetName returns the name of a flag.
|
// Names returns the name of a flag.
|
||||||
func (f StringSliceFlag) GetName() string {
|
func (f *StringSliceFlag) Names() []string {
|
||||||
return f.Name
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IntSlice wraps an []int to satisfy flag.Value
|
// IntSlice wraps an []int to satisfy flag.Value
|
||||||
@ -272,23 +271,23 @@ func (i *IntSlice) Value() []int {
|
|||||||
// IntSliceFlag is an int flag that can be specified multiple times on the
|
// IntSliceFlag is an int flag that can be specified multiple times on the
|
||||||
// command-line
|
// command-line
|
||||||
type IntSliceFlag struct {
|
type IntSliceFlag struct {
|
||||||
Name string
|
Name string
|
||||||
Value *IntSlice
|
Aliases []string
|
||||||
Usage string
|
Value *IntSlice
|
||||||
EnvVar string
|
Usage string
|
||||||
Hidden bool
|
EnvVars []string
|
||||||
|
Hidden bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the usage
|
// String returns the usage
|
||||||
func (f IntSliceFlag) String() string {
|
func (f *IntSliceFlag) String() string {
|
||||||
return FlagStringer(f)
|
return FlagStringer(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
func (f IntSliceFlag) Apply(set *flag.FlagSet) {
|
func (f *IntSliceFlag) Apply(set *flag.FlagSet) {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVars != nil {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range f.EnvVars {
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
newVal := NewIntSlice()
|
newVal := NewIntSlice()
|
||||||
for _, s := range strings.Split(envVal, ",") {
|
for _, s := range strings.Split(envVal, ",") {
|
||||||
@ -308,36 +307,36 @@ func (f IntSliceFlag) Apply(set *flag.FlagSet) {
|
|||||||
f.Value = NewIntSlice()
|
f.Value = NewIntSlice()
|
||||||
}
|
}
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
set.Var(f.Value, name, f.Usage)
|
set.Var(f.Value, name, f.Usage)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetName returns the name of the flag.
|
// Names returns the name of the flag.
|
||||||
func (f IntSliceFlag) GetName() string {
|
func (f *IntSliceFlag) Names() []string {
|
||||||
return f.Name
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BoolFlag is a switch that defaults to false
|
// BoolFlag is a switch that defaults to false
|
||||||
type BoolFlag struct {
|
type BoolFlag struct {
|
||||||
Name string
|
Name string
|
||||||
|
Aliases []string
|
||||||
Value bool
|
Value bool
|
||||||
Usage string
|
Usage string
|
||||||
EnvVar string
|
EnvVars []string
|
||||||
Destination *bool
|
Destination *bool
|
||||||
Hidden bool
|
Hidden bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a readable representation of this value (for usage defaults)
|
// String returns a readable representation of this value (for usage defaults)
|
||||||
func (f BoolFlag) String() string {
|
func (f *BoolFlag) String() string {
|
||||||
return FlagStringer(f)
|
return FlagStringer(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
func (f BoolFlag) Apply(set *flag.FlagSet) {
|
func (f *BoolFlag) Apply(set *flag.FlagSet) {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVars != nil {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range f.EnvVars {
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
envValBool, err := strconv.ParseBool(envVal)
|
envValBool, err := strconv.ParseBool(envVal)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -348,40 +347,40 @@ func (f BoolFlag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
if f.Destination != nil {
|
if f.Destination != nil {
|
||||||
set.BoolVar(f.Destination, name, f.Value, f.Usage)
|
set.BoolVar(f.Destination, name, f.Value, f.Usage)
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
set.Bool(name, f.Value, f.Usage)
|
set.Bool(name, f.Value, f.Usage)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetName returns the name of the flag.
|
// Names returns the name of the flag.
|
||||||
func (f BoolFlag) GetName() string {
|
func (f *BoolFlag) Names() []string {
|
||||||
return f.Name
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StringFlag represents a flag that takes as string value
|
// StringFlag represents a flag that takes as string value
|
||||||
type StringFlag struct {
|
type StringFlag struct {
|
||||||
Name string
|
Name string
|
||||||
|
Aliases []string
|
||||||
Value string
|
Value string
|
||||||
Usage string
|
Usage string
|
||||||
EnvVar string
|
EnvVars []string
|
||||||
Destination *string
|
Destination *string
|
||||||
Hidden bool
|
Hidden bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the usage
|
// String returns the usage
|
||||||
func (f StringFlag) String() string {
|
func (f *StringFlag) String() string {
|
||||||
return FlagStringer(f)
|
return FlagStringer(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
func (f StringFlag) Apply(set *flag.FlagSet) {
|
func (f *StringFlag) Apply(set *flag.FlagSet) {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVars != nil {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range f.EnvVars {
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
f.Value = envVal
|
f.Value = envVal
|
||||||
break
|
break
|
||||||
@ -389,41 +388,41 @@ func (f StringFlag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
if f.Destination != nil {
|
if f.Destination != nil {
|
||||||
set.StringVar(f.Destination, name, f.Value, f.Usage)
|
set.StringVar(f.Destination, name, f.Value, f.Usage)
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
set.String(name, f.Value, f.Usage)
|
set.String(name, f.Value, f.Usage)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetName returns the name of the flag.
|
// Names returns the name of the flag.
|
||||||
func (f StringFlag) GetName() string {
|
func (f *StringFlag) Names() []string {
|
||||||
return f.Name
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IntFlag is a flag that takes an integer
|
// IntFlag is a flag that takes an integer
|
||||||
// Errors if the value provided cannot be parsed
|
// Errors if the value provided cannot be parsed
|
||||||
type IntFlag struct {
|
type IntFlag struct {
|
||||||
Name string
|
Name string
|
||||||
|
Aliases []string
|
||||||
Value int
|
Value int
|
||||||
Usage string
|
Usage string
|
||||||
EnvVar string
|
EnvVars []string
|
||||||
Destination *int
|
Destination *int
|
||||||
Hidden bool
|
Hidden bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the usage
|
// String returns the usage
|
||||||
func (f IntFlag) String() string {
|
func (f *IntFlag) String() string {
|
||||||
return FlagStringer(f)
|
return FlagStringer(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
func (f IntFlag) Apply(set *flag.FlagSet) {
|
func (f *IntFlag) Apply(set *flag.FlagSet) {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVars != nil {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range f.EnvVars {
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
envValInt, err := strconv.ParseInt(envVal, 0, 64)
|
envValInt, err := strconv.ParseInt(envVal, 0, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -434,41 +433,41 @@ func (f IntFlag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
if f.Destination != nil {
|
if f.Destination != nil {
|
||||||
set.IntVar(f.Destination, name, f.Value, f.Usage)
|
set.IntVar(f.Destination, name, f.Value, f.Usage)
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
set.Int(name, f.Value, f.Usage)
|
set.Int(name, f.Value, f.Usage)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetName returns the name of the flag.
|
// Names returns the name of the flag.
|
||||||
func (f IntFlag) GetName() string {
|
func (f *IntFlag) Names() []string {
|
||||||
return f.Name
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DurationFlag is a flag that takes a duration specified in Go's duration
|
// DurationFlag is a flag that takes a duration specified in Go's duration
|
||||||
// format: https://golang.org/pkg/time/#ParseDuration
|
// format: https://golang.org/pkg/time/#ParseDuration
|
||||||
type DurationFlag struct {
|
type DurationFlag struct {
|
||||||
Name string
|
Name string
|
||||||
|
Aliases []string
|
||||||
Value time.Duration
|
Value time.Duration
|
||||||
Usage string
|
Usage string
|
||||||
EnvVar string
|
EnvVars []string
|
||||||
Destination *time.Duration
|
Destination *time.Duration
|
||||||
Hidden bool
|
Hidden bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns a readable representation of this value (for usage defaults)
|
// String returns a readable representation of this value (for usage defaults)
|
||||||
func (f DurationFlag) String() string {
|
func (f *DurationFlag) String() string {
|
||||||
return FlagStringer(f)
|
return FlagStringer(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
func (f DurationFlag) Apply(set *flag.FlagSet) {
|
func (f *DurationFlag) Apply(set *flag.FlagSet) {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVars != nil {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range f.EnvVars {
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
envValDuration, err := time.ParseDuration(envVal)
|
envValDuration, err := time.ParseDuration(envVal)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -479,41 +478,41 @@ func (f DurationFlag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
if f.Destination != nil {
|
if f.Destination != nil {
|
||||||
set.DurationVar(f.Destination, name, f.Value, f.Usage)
|
set.DurationVar(f.Destination, name, f.Value, f.Usage)
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
set.Duration(name, f.Value, f.Usage)
|
set.Duration(name, f.Value, f.Usage)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetName returns the name of the flag.
|
// Names returns the name of the flag.
|
||||||
func (f DurationFlag) GetName() string {
|
func (f *DurationFlag) Names() []string {
|
||||||
return f.Name
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Float64Flag is a flag that takes an float value
|
// Float64Flag is a flag that takes an float value
|
||||||
// Errors if the value provided cannot be parsed
|
// Errors if the value provided cannot be parsed
|
||||||
type Float64Flag struct {
|
type Float64Flag struct {
|
||||||
Name string
|
Name string
|
||||||
|
Aliases []string
|
||||||
Value float64
|
Value float64
|
||||||
Usage string
|
Usage string
|
||||||
EnvVar string
|
EnvVars []string
|
||||||
Destination *float64
|
Destination *float64
|
||||||
Hidden bool
|
Hidden bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// String returns the usage
|
// String returns the usage
|
||||||
func (f Float64Flag) String() string {
|
func (f *Float64Flag) String() string {
|
||||||
return FlagStringer(f)
|
return FlagStringer(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply populates the flag given the flag set and environment
|
// Apply populates the flag given the flag set and environment
|
||||||
func (f Float64Flag) Apply(set *flag.FlagSet) {
|
func (f *Float64Flag) Apply(set *flag.FlagSet) {
|
||||||
if f.EnvVar != "" {
|
if f.EnvVars != nil {
|
||||||
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
for _, envVar := range f.EnvVars {
|
||||||
envVar = strings.TrimSpace(envVar)
|
|
||||||
if envVal := os.Getenv(envVar); envVal != "" {
|
if envVal := os.Getenv(envVar); envVal != "" {
|
||||||
envValFloat, err := strconv.ParseFloat(envVal, 10)
|
envValFloat, err := strconv.ParseFloat(envVal, 10)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -523,24 +522,24 @@ func (f Float64Flag) Apply(set *flag.FlagSet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eachName(f.Name, func(name string) {
|
for _, name := range f.Names() {
|
||||||
if f.Destination != nil {
|
if f.Destination != nil {
|
||||||
set.Float64Var(f.Destination, name, f.Value, f.Usage)
|
set.Float64Var(f.Destination, name, f.Value, f.Usage)
|
||||||
return
|
continue
|
||||||
}
|
}
|
||||||
set.Float64(name, f.Value, f.Usage)
|
set.Float64(name, f.Value, f.Usage)
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetName returns the name of the flag.
|
// Names returns the name of the flag.
|
||||||
func (f Float64Flag) GetName() string {
|
func (f *Float64Flag) Names() []string {
|
||||||
return f.Name
|
return flagNames(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func visibleFlags(fl []Flag) []Flag {
|
func visibleFlags(fl []Flag) []Flag {
|
||||||
visible := []Flag{}
|
visible := []Flag{}
|
||||||
for _, flag := range fl {
|
for _, flag := range fl {
|
||||||
if !reflect.ValueOf(flag).FieldByName("Hidden").Bool() {
|
if !flagValue(flag).FieldByName("Hidden").Bool() {
|
||||||
visible = append(visible, flag)
|
visible = append(visible, flag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -574,25 +573,27 @@ func unquoteUsage(usage string) (string, string) {
|
|||||||
return "", usage
|
return "", usage
|
||||||
}
|
}
|
||||||
|
|
||||||
func prefixedNames(fullName, placeholder string) string {
|
func prefixedNames(names []string, placeholder string) string {
|
||||||
var prefixed string
|
var prefixed string
|
||||||
parts := strings.Split(fullName, ",")
|
for i, name := range names {
|
||||||
for i, name := range parts {
|
if name == "" {
|
||||||
name = strings.Trim(name, " ")
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
prefixed += prefixFor(name) + name
|
prefixed += prefixFor(name) + name
|
||||||
if placeholder != "" {
|
if placeholder != "" {
|
||||||
prefixed += " " + placeholder
|
prefixed += " " + placeholder
|
||||||
}
|
}
|
||||||
if i < len(parts)-1 {
|
if i < len(names)-1 {
|
||||||
prefixed += ", "
|
prefixed += ", "
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return prefixed
|
return prefixed
|
||||||
}
|
}
|
||||||
|
|
||||||
func withEnvHint(envVar, str string) string {
|
func withEnvHint(envVars []string, str string) string {
|
||||||
envText := ""
|
envText := ""
|
||||||
if envVar != "" {
|
if envVars != nil && len(envVars) > 0 {
|
||||||
prefix := "$"
|
prefix := "$"
|
||||||
suffix := ""
|
suffix := ""
|
||||||
sep := ", $"
|
sep := ", $"
|
||||||
@ -601,21 +602,66 @@ func withEnvHint(envVar, str string) string {
|
|||||||
suffix = "%"
|
suffix = "%"
|
||||||
sep = "%, %"
|
sep = "%, %"
|
||||||
}
|
}
|
||||||
envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(strings.Split(envVar, ","), sep), suffix)
|
envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(envVars, sep), suffix)
|
||||||
}
|
}
|
||||||
return str + envText
|
return str + envText
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringifyFlag(f Flag) string {
|
func flagNames(f Flag) []string {
|
||||||
|
ret := []string{}
|
||||||
|
|
||||||
|
name := flagStringField(f, "Name")
|
||||||
|
aliases := flagStringSliceField(f, "Aliases")
|
||||||
|
|
||||||
|
for _, part := range append([]string{name}, aliases...) {
|
||||||
|
// v1 -> v2 migration warning zone:
|
||||||
|
// Strip off anything after the first found comma or space, which
|
||||||
|
// *hopefully* makes it a tiny bit more obvious that unexpected behavior is
|
||||||
|
// caused by using the v1 form of stringly typed "Name".
|
||||||
|
ret = append(ret, commaWhitespace.ReplaceAllString(part, ""))
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func flagStringSliceField(f Flag, name string) []string {
|
||||||
|
fv := flagValue(f)
|
||||||
|
field := fv.FieldByName(name)
|
||||||
|
|
||||||
|
if field.IsValid() {
|
||||||
|
return field.Interface().([]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
return []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func flagStringField(f Flag, name string) string {
|
||||||
|
fv := flagValue(f)
|
||||||
|
field := fv.FieldByName(name)
|
||||||
|
|
||||||
|
if field.IsValid() {
|
||||||
|
return field.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func flagValue(f Flag) reflect.Value {
|
||||||
fv := reflect.ValueOf(f)
|
fv := reflect.ValueOf(f)
|
||||||
|
for fv.Kind() == reflect.Ptr {
|
||||||
|
fv = reflect.Indirect(fv)
|
||||||
|
}
|
||||||
|
return fv
|
||||||
|
}
|
||||||
|
|
||||||
|
func stringifyFlag(f Flag) string {
|
||||||
|
fv := flagValue(f)
|
||||||
|
|
||||||
switch f.(type) {
|
switch f.(type) {
|
||||||
case IntSliceFlag:
|
case *IntSliceFlag:
|
||||||
return withEnvHint(fv.FieldByName("EnvVar").String(),
|
return withEnvHint(flagStringSliceField(f, "EnvVars"), stringifyIntSliceFlag(f.(*IntSliceFlag)))
|
||||||
stringifyIntSliceFlag(f.(IntSliceFlag)))
|
case *StringSliceFlag:
|
||||||
case StringSliceFlag:
|
return withEnvHint(flagStringSliceField(f, "EnvVars"), stringifyStringSliceFlag(f.(*StringSliceFlag)))
|
||||||
return withEnvHint(fv.FieldByName("EnvVar").String(),
|
|
||||||
stringifyStringSliceFlag(f.(StringSliceFlag)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String())
|
placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String())
|
||||||
@ -643,11 +689,11 @@ func stringifyFlag(f Flag) string {
|
|||||||
|
|
||||||
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultValueString))
|
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultValueString))
|
||||||
|
|
||||||
return withEnvHint(fv.FieldByName("EnvVar").String(),
|
return withEnvHint(flagStringSliceField(f, "EnvVars"),
|
||||||
fmt.Sprintf("%s\t%s", prefixedNames(fv.FieldByName("Name").String(), placeholder), usageWithDefault))
|
fmt.Sprintf("%s\t%s", prefixedNames(f.Names(), placeholder), usageWithDefault))
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringifyIntSliceFlag(f IntSliceFlag) string {
|
func stringifyIntSliceFlag(f *IntSliceFlag) string {
|
||||||
defaultVals := []string{}
|
defaultVals := []string{}
|
||||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
if f.Value != nil && len(f.Value.Value()) > 0 {
|
||||||
for _, i := range f.Value.Value() {
|
for _, i := range f.Value.Value() {
|
||||||
@ -655,10 +701,10 @@ func stringifyIntSliceFlag(f IntSliceFlag) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return stringifySliceFlag(f.Usage, f.Name, defaultVals)
|
return stringifySliceFlag(f.Usage, append([]string{f.Name}, f.Aliases...), defaultVals)
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringifyStringSliceFlag(f StringSliceFlag) string {
|
func stringifyStringSliceFlag(f *StringSliceFlag) string {
|
||||||
defaultVals := []string{}
|
defaultVals := []string{}
|
||||||
if f.Value != nil && len(f.Value.Value()) > 0 {
|
if f.Value != nil && len(f.Value.Value()) > 0 {
|
||||||
for _, s := range f.Value.Value() {
|
for _, s := range f.Value.Value() {
|
||||||
@ -668,10 +714,10 @@ func stringifyStringSliceFlag(f StringSliceFlag) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return stringifySliceFlag(f.Usage, f.Name, defaultVals)
|
return stringifySliceFlag(f.Usage, append([]string{f.Name}, f.Aliases...), defaultVals)
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringifySliceFlag(usage, name string, defaultVals []string) string {
|
func stringifySliceFlag(usage string, names, defaultVals []string) string {
|
||||||
placeholder, usage := unquoteUsage(usage)
|
placeholder, usage := unquoteUsage(usage)
|
||||||
if placeholder == "" {
|
if placeholder == "" {
|
||||||
placeholder = defaultPlaceholder
|
placeholder = defaultPlaceholder
|
||||||
@ -683,5 +729,15 @@ func stringifySliceFlag(usage, name string, defaultVals []string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal))
|
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal))
|
||||||
return fmt.Sprintf("%s\t%s", prefixedNames(name, placeholder), usageWithDefault)
|
return fmt.Sprintf("%s\t%s", prefixedNames(names, placeholder), usageWithDefault)
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasFlag(flags []Flag, fl Flag) bool {
|
||||||
|
for _, existing := range flags {
|
||||||
|
if fl == existing {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
239
flag_test.go
239
flag_test.go
@ -1,6 +1,7 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -20,7 +21,7 @@ var boolFlagTests = []struct {
|
|||||||
|
|
||||||
func TestBoolFlagHelpOutput(t *testing.T) {
|
func TestBoolFlagHelpOutput(t *testing.T) {
|
||||||
for _, test := range boolFlagTests {
|
for _, test := range boolFlagTests {
|
||||||
flag := BoolFlag{Name: test.name}
|
flag := &BoolFlag{Name: test.name}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
if output != test.expected {
|
if output != test.expected {
|
||||||
@ -29,23 +30,35 @@ func TestBoolFlagHelpOutput(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBoolFlagApply_SetsAllNames(t *testing.T) {
|
||||||
|
v := false
|
||||||
|
fl := BoolFlag{Name: "wat", Aliases: []string{"W", "huh"}, Destination: &v}
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
fl.Apply(set)
|
||||||
|
|
||||||
|
err := set.Parse([]string{"--wat", "-W", "--huh"})
|
||||||
|
expect(t, err, nil)
|
||||||
|
expect(t, v, true)
|
||||||
|
}
|
||||||
|
|
||||||
var stringFlagTests = []struct {
|
var stringFlagTests = []struct {
|
||||||
name string
|
name string
|
||||||
|
aliases []string
|
||||||
usage string
|
usage string
|
||||||
value string
|
value string
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
{"foo", "", "", "--foo value\t"},
|
{"foo", nil, "", "", "--foo value\t"},
|
||||||
{"f", "", "", "-f value\t"},
|
{"f", nil, "", "", "-f value\t"},
|
||||||
{"f", "The total `foo` desired", "all", "-f foo\tThe total foo desired (default: \"all\")"},
|
{"f", nil, "The total `foo` desired", "all", "-f foo\tThe total foo desired (default: \"all\")"},
|
||||||
{"test", "", "Something", "--test value\t(default: \"Something\")"},
|
{"test", nil, "", "Something", "--test value\t(default: \"Something\")"},
|
||||||
{"config,c", "Load configuration from `FILE`", "", "--config FILE, -c FILE\tLoad configuration from FILE"},
|
{"config", []string{"c"}, "Load configuration from `FILE`", "", "--config FILE, -c FILE\tLoad configuration from FILE"},
|
||||||
{"config,c", "Load configuration from `CONFIG`", "config.json", "--config CONFIG, -c CONFIG\tLoad configuration from CONFIG (default: \"config.json\")"},
|
{"config", []string{"c"}, "Load configuration from `CONFIG`", "config.json", "--config CONFIG, -c CONFIG\tLoad configuration from CONFIG (default: \"config.json\")"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStringFlagHelpOutput(t *testing.T) {
|
func TestStringFlagHelpOutput(t *testing.T) {
|
||||||
for _, test := range stringFlagTests {
|
for _, test := range stringFlagTests {
|
||||||
flag := StringFlag{Name: test.name, Usage: test.usage, Value: test.value}
|
flag := &StringFlag{Name: test.name, Aliases: test.aliases, Usage: test.usage, Value: test.value}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
if output != test.expected {
|
if output != test.expected {
|
||||||
@ -58,7 +71,7 @@ func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("APP_FOO", "derp")
|
os.Setenv("APP_FOO", "derp")
|
||||||
for _, test := range stringFlagTests {
|
for _, test := range stringFlagTests {
|
||||||
flag := StringFlag{Name: test.name, Value: test.value, EnvVar: "APP_FOO"}
|
flag := &StringFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_FOO"}}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
expectedSuffix := " [$APP_FOO]"
|
expectedSuffix := " [$APP_FOO]"
|
||||||
@ -71,21 +84,33 @@ func TestStringFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStringFlagApply_SetsAllNames(t *testing.T) {
|
||||||
|
v := "mmm"
|
||||||
|
fl := StringFlag{Name: "hay", Aliases: []string{"H", "hayyy"}, Destination: &v}
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
fl.Apply(set)
|
||||||
|
|
||||||
|
err := set.Parse([]string{"--hay", "u", "-H", "yuu", "--hayyy", "YUUUU"})
|
||||||
|
expect(t, err, nil)
|
||||||
|
expect(t, v, "YUUUU")
|
||||||
|
}
|
||||||
|
|
||||||
var stringSliceFlagTests = []struct {
|
var stringSliceFlagTests = []struct {
|
||||||
name string
|
name string
|
||||||
|
aliases []string
|
||||||
value *StringSlice
|
value *StringSlice
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
{"foo", NewStringSlice(""), "--foo value\t"},
|
{"foo", nil, NewStringSlice(""), "--foo value\t"},
|
||||||
{"f", NewStringSlice(""), "-f value\t"},
|
{"f", nil, NewStringSlice(""), "-f value\t"},
|
||||||
{"f", NewStringSlice("Lipstick"), "-f value\t(default: \"Lipstick\")"},
|
{"f", nil, NewStringSlice("Lipstick"), "-f value\t(default: \"Lipstick\")"},
|
||||||
{"test", NewStringSlice("Something"), "--test value\t(default: \"Something\")"},
|
{"test", nil, NewStringSlice("Something"), "--test value\t(default: \"Something\")"},
|
||||||
{"d, dee", NewStringSlice("Inka", "Dinka", "dooo"), "-d value, --dee value\t(default: \"Inka\", \"Dinka\", \"dooo\")"},
|
{"dee", []string{"d"}, NewStringSlice("Inka", "Dinka", "dooo"), "--dee value, -d value\t(default: \"Inka\", \"Dinka\", \"dooo\")"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStringSliceFlagHelpOutput(t *testing.T) {
|
func TestStringSliceFlagHelpOutput(t *testing.T) {
|
||||||
for _, test := range stringSliceFlagTests {
|
for _, test := range stringSliceFlagTests {
|
||||||
flag := StringSliceFlag{Name: test.name, Value: test.value}
|
flag := &StringSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
if output != test.expected {
|
if output != test.expected {
|
||||||
@ -98,7 +123,7 @@ func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("APP_QWWX", "11,4")
|
os.Setenv("APP_QWWX", "11,4")
|
||||||
for _, test := range stringSliceFlagTests {
|
for _, test := range stringSliceFlagTests {
|
||||||
flag := StringSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_QWWX"}
|
flag := &StringSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_QWWX"}}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
expectedSuffix := " [$APP_QWWX]"
|
expectedSuffix := " [$APP_QWWX]"
|
||||||
@ -111,6 +136,15 @@ func TestStringSliceFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStringSliceFlagApply_SetsAllNames(t *testing.T) {
|
||||||
|
fl := StringSliceFlag{Name: "goat", Aliases: []string{"G", "gooots"}}
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
fl.Apply(set)
|
||||||
|
|
||||||
|
err := set.Parse([]string{"--goat", "aaa", "-G", "bbb", "--gooots", "eeeee"})
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
var intFlagTests = []struct {
|
var intFlagTests = []struct {
|
||||||
name string
|
name string
|
||||||
expected string
|
expected string
|
||||||
@ -121,7 +155,7 @@ var intFlagTests = []struct {
|
|||||||
|
|
||||||
func TestIntFlagHelpOutput(t *testing.T) {
|
func TestIntFlagHelpOutput(t *testing.T) {
|
||||||
for _, test := range intFlagTests {
|
for _, test := range intFlagTests {
|
||||||
flag := IntFlag{Name: test.name, Value: 9}
|
flag := &IntFlag{Name: test.name, Value: 9}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
if output != test.expected {
|
if output != test.expected {
|
||||||
@ -134,7 +168,7 @@ func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("APP_BAR", "2")
|
os.Setenv("APP_BAR", "2")
|
||||||
for _, test := range intFlagTests {
|
for _, test := range intFlagTests {
|
||||||
flag := IntFlag{Name: test.name, EnvVar: "APP_BAR"}
|
flag := &IntFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
expectedSuffix := " [$APP_BAR]"
|
expectedSuffix := " [$APP_BAR]"
|
||||||
@ -147,6 +181,17 @@ func TestIntFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIntFlagApply_SetsAllNames(t *testing.T) {
|
||||||
|
v := 3
|
||||||
|
fl := IntFlag{Name: "banana", Aliases: []string{"B", "banannanana"}, Destination: &v}
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
fl.Apply(set)
|
||||||
|
|
||||||
|
err := set.Parse([]string{"--banana", "1", "-B", "2", "--banannanana", "5"})
|
||||||
|
expect(t, err, nil)
|
||||||
|
expect(t, v, 5)
|
||||||
|
}
|
||||||
|
|
||||||
var durationFlagTests = []struct {
|
var durationFlagTests = []struct {
|
||||||
name string
|
name string
|
||||||
expected string
|
expected string
|
||||||
@ -157,7 +202,7 @@ var durationFlagTests = []struct {
|
|||||||
|
|
||||||
func TestDurationFlagHelpOutput(t *testing.T) {
|
func TestDurationFlagHelpOutput(t *testing.T) {
|
||||||
for _, test := range durationFlagTests {
|
for _, test := range durationFlagTests {
|
||||||
flag := DurationFlag{Name: test.name, Value: 1 * time.Second}
|
flag := &DurationFlag{Name: test.name, Value: 1 * time.Second}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
if output != test.expected {
|
if output != test.expected {
|
||||||
@ -170,7 +215,7 @@ func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("APP_BAR", "2h3m6s")
|
os.Setenv("APP_BAR", "2h3m6s")
|
||||||
for _, test := range durationFlagTests {
|
for _, test := range durationFlagTests {
|
||||||
flag := DurationFlag{Name: test.name, EnvVar: "APP_BAR"}
|
flag := &DurationFlag{Name: test.name, EnvVars: []string{"APP_BAR"}}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
expectedSuffix := " [$APP_BAR]"
|
expectedSuffix := " [$APP_BAR]"
|
||||||
@ -183,19 +228,31 @@ func TestDurationFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDurationFlagApply_SetsAllNames(t *testing.T) {
|
||||||
|
v := time.Second * 20
|
||||||
|
fl := DurationFlag{Name: "howmuch", Aliases: []string{"H", "whyyy"}, Destination: &v}
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
fl.Apply(set)
|
||||||
|
|
||||||
|
err := set.Parse([]string{"--howmuch", "30s", "-H", "5m", "--whyyy", "30h"})
|
||||||
|
expect(t, err, nil)
|
||||||
|
expect(t, v, time.Hour*30)
|
||||||
|
}
|
||||||
|
|
||||||
var intSliceFlagTests = []struct {
|
var intSliceFlagTests = []struct {
|
||||||
name string
|
name string
|
||||||
|
aliases []string
|
||||||
value *IntSlice
|
value *IntSlice
|
||||||
expected string
|
expected string
|
||||||
}{
|
}{
|
||||||
{"heads", NewIntSlice(), "--heads value\t"},
|
{"heads", nil, NewIntSlice(), "--heads value\t"},
|
||||||
{"H", NewIntSlice(), "-H value\t"},
|
{"H", nil, NewIntSlice(), "-H value\t"},
|
||||||
{"H, heads", NewIntSlice(9, 3), "-H value, --heads value\t(default: 9, 3)"},
|
{"H", []string{"heads"}, NewIntSlice(9, 3), "-H value, --heads value\t(default: 9, 3)"},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIntSliceFlagHelpOutput(t *testing.T) {
|
func TestIntSliceFlagHelpOutput(t *testing.T) {
|
||||||
for _, test := range intSliceFlagTests {
|
for _, test := range intSliceFlagTests {
|
||||||
flag := IntSliceFlag{Name: test.name, Value: test.value}
|
flag := &IntSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
if output != test.expected {
|
if output != test.expected {
|
||||||
@ -208,7 +265,7 @@ func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("APP_SMURF", "42,3")
|
os.Setenv("APP_SMURF", "42,3")
|
||||||
for _, test := range intSliceFlagTests {
|
for _, test := range intSliceFlagTests {
|
||||||
flag := IntSliceFlag{Name: test.name, Value: test.value, EnvVar: "APP_SMURF"}
|
flag := &IntSliceFlag{Name: test.name, Aliases: test.aliases, Value: test.value, EnvVars: []string{"APP_SMURF"}}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
expectedSuffix := " [$APP_SMURF]"
|
expectedSuffix := " [$APP_SMURF]"
|
||||||
@ -221,6 +278,15 @@ func TestIntSliceFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIntSliceFlagApply_SetsAllNames(t *testing.T) {
|
||||||
|
fl := IntSliceFlag{Name: "bits", Aliases: []string{"B", "bips"}}
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
fl.Apply(set)
|
||||||
|
|
||||||
|
err := set.Parse([]string{"--bits", "23", "-B", "3", "--bips", "99"})
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
var float64FlagTests = []struct {
|
var float64FlagTests = []struct {
|
||||||
name string
|
name string
|
||||||
expected string
|
expected string
|
||||||
@ -231,7 +297,7 @@ var float64FlagTests = []struct {
|
|||||||
|
|
||||||
func TestFloat64FlagHelpOutput(t *testing.T) {
|
func TestFloat64FlagHelpOutput(t *testing.T) {
|
||||||
for _, test := range float64FlagTests {
|
for _, test := range float64FlagTests {
|
||||||
flag := Float64Flag{Name: test.name, Value: float64(0.1)}
|
flag := &Float64Flag{Name: test.name, Value: float64(0.1)}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
if output != test.expected {
|
if output != test.expected {
|
||||||
@ -244,7 +310,7 @@ func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("APP_BAZ", "99.4")
|
os.Setenv("APP_BAZ", "99.4")
|
||||||
for _, test := range float64FlagTests {
|
for _, test := range float64FlagTests {
|
||||||
flag := Float64Flag{Name: test.name, EnvVar: "APP_BAZ"}
|
flag := &Float64Flag{Name: test.name, EnvVars: []string{"APP_BAZ"}}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
expectedSuffix := " [$APP_BAZ]"
|
expectedSuffix := " [$APP_BAZ]"
|
||||||
@ -257,6 +323,17 @@ func TestFloat64FlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFloat64FlagApply_SetsAllNames(t *testing.T) {
|
||||||
|
v := float64(99.1)
|
||||||
|
fl := Float64Flag{Name: "noodles", Aliases: []string{"N", "nurbles"}, Destination: &v}
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
fl.Apply(set)
|
||||||
|
|
||||||
|
err := set.Parse([]string{"--noodles", "1.3", "-N", "11", "--nurbles", "43.33333"})
|
||||||
|
expect(t, err, nil)
|
||||||
|
expect(t, v, float64(43.33333))
|
||||||
|
}
|
||||||
|
|
||||||
var genericFlagTests = []struct {
|
var genericFlagTests = []struct {
|
||||||
name string
|
name string
|
||||||
value Generic
|
value Generic
|
||||||
@ -268,7 +345,7 @@ var genericFlagTests = []struct {
|
|||||||
|
|
||||||
func TestGenericFlagHelpOutput(t *testing.T) {
|
func TestGenericFlagHelpOutput(t *testing.T) {
|
||||||
for _, test := range genericFlagTests {
|
for _, test := range genericFlagTests {
|
||||||
flag := GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
|
flag := &GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
if output != test.expected {
|
if output != test.expected {
|
||||||
@ -281,7 +358,7 @@ func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
os.Clearenv()
|
os.Clearenv()
|
||||||
os.Setenv("APP_ZAP", "3")
|
os.Setenv("APP_ZAP", "3")
|
||||||
for _, test := range genericFlagTests {
|
for _, test := range genericFlagTests {
|
||||||
flag := GenericFlag{Name: test.name, EnvVar: "APP_ZAP"}
|
flag := &GenericFlag{Name: test.name, EnvVars: []string{"APP_ZAP"}}
|
||||||
output := flag.String()
|
output := flag.String()
|
||||||
|
|
||||||
expectedSuffix := " [$APP_ZAP]"
|
expectedSuffix := " [$APP_ZAP]"
|
||||||
@ -294,10 +371,19 @@ func TestGenericFlagWithEnvVarHelpOutput(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGenericFlagApply_SetsAllNames(t *testing.T) {
|
||||||
|
fl := GenericFlag{Name: "orbs", Aliases: []string{"O", "obrs"}, Value: &Parser{}}
|
||||||
|
set := flag.NewFlagSet("test", 0)
|
||||||
|
fl.Apply(set)
|
||||||
|
|
||||||
|
err := set.Parse([]string{"--orbs", "eleventy,3", "-O", "4,bloop", "--obrs", "19,s"})
|
||||||
|
expect(t, err, nil)
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseMultiString(t *testing.T) {
|
func TestParseMultiString(t *testing.T) {
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringFlag{Name: "serve, s"},
|
&StringFlag{Name: "serve", Aliases: []string{"s"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if ctx.String("serve") != "10" {
|
if ctx.String("serve") != "10" {
|
||||||
@ -315,7 +401,7 @@ func TestParseDestinationString(t *testing.T) {
|
|||||||
var dest string
|
var dest string
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringFlag{
|
&StringFlag{
|
||||||
Name: "dest",
|
Name: "dest",
|
||||||
Destination: &dest,
|
Destination: &dest,
|
||||||
},
|
},
|
||||||
@ -335,7 +421,7 @@ func TestParseMultiStringFromEnv(t *testing.T) {
|
|||||||
os.Setenv("APP_COUNT", "20")
|
os.Setenv("APP_COUNT", "20")
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringFlag{Name: "count, c", EnvVar: "APP_COUNT"},
|
&StringFlag{Name: "count", Aliases: []string{"c"}, EnvVars: []string{"APP_COUNT"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if ctx.String("count") != "20" {
|
if ctx.String("count") != "20" {
|
||||||
@ -354,7 +440,7 @@ func TestParseMultiStringFromEnvCascade(t *testing.T) {
|
|||||||
os.Setenv("APP_COUNT", "20")
|
os.Setenv("APP_COUNT", "20")
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringFlag{Name: "count, c", EnvVar: "COMPAT_COUNT,APP_COUNT"},
|
&StringFlag{Name: "count", Aliases: []string{"c"}, EnvVars: []string{"COMPAT_COUNT", "APP_COUNT"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if ctx.String("count") != "20" {
|
if ctx.String("count") != "20" {
|
||||||
@ -371,7 +457,7 @@ func TestParseMultiStringFromEnvCascade(t *testing.T) {
|
|||||||
func TestParseMultiStringSlice(t *testing.T) {
|
func TestParseMultiStringSlice(t *testing.T) {
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringSliceFlag{Name: "serve, s", Value: NewStringSlice()},
|
&StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewStringSlice()},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
expected := []string{"10", "20"}
|
expected := []string{"10", "20"}
|
||||||
@ -389,7 +475,7 @@ func TestParseMultiStringSlice(t *testing.T) {
|
|||||||
func TestParseMultiStringSliceWithDefaults(t *testing.T) {
|
func TestParseMultiStringSliceWithDefaults(t *testing.T) {
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringSliceFlag{Name: "serve, s", Value: NewStringSlice("9", "2")},
|
&StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewStringSlice("9", "2")},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
expected := []string{"10", "20"}
|
expected := []string{"10", "20"}
|
||||||
@ -407,7 +493,7 @@ func TestParseMultiStringSliceWithDefaults(t *testing.T) {
|
|||||||
func TestParseMultiStringSliceWithDefaultsUnset(t *testing.T) {
|
func TestParseMultiStringSliceWithDefaultsUnset(t *testing.T) {
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringSliceFlag{Name: "serve, s", Value: NewStringSlice("9", "2")},
|
&StringSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewStringSlice("9", "2")},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"9", "2"}) {
|
if !reflect.DeepEqual(ctx.StringSlice("serve"), []string{"9", "2"}) {
|
||||||
@ -427,7 +513,7 @@ func TestParseMultiStringSliceFromEnv(t *testing.T) {
|
|||||||
|
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringSliceFlag{Name: "intervals, i", Value: NewStringSlice(), EnvVar: "APP_INTERVALS"},
|
&StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice(), EnvVars: []string{"APP_INTERVALS"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
||||||
@ -447,7 +533,7 @@ func TestParseMultiStringSliceFromEnvWithDefaults(t *testing.T) {
|
|||||||
|
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringSliceFlag{Name: "intervals, i", Value: NewStringSlice("1", "2", "5"), EnvVar: "APP_INTERVALS"},
|
&StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice("1", "2", "5"), EnvVars: []string{"APP_INTERVALS"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
||||||
@ -467,7 +553,7 @@ func TestParseMultiStringSliceFromEnvCascade(t *testing.T) {
|
|||||||
|
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringSliceFlag{Name: "intervals, i", Value: NewStringSlice(), EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
|
&StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice(), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
||||||
@ -487,7 +573,7 @@ func TestParseMultiStringSliceFromEnvCascadeWithDefaults(t *testing.T) {
|
|||||||
|
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
StringSliceFlag{Name: "intervals, i", Value: NewStringSlice("1", "2", "5"), EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
|
&StringSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewStringSlice("1", "2", "5"), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
if !reflect.DeepEqual(ctx.StringSlice("intervals"), []string{"20", "30", "40"}) {
|
||||||
@ -504,7 +590,7 @@ func TestParseMultiStringSliceFromEnvCascadeWithDefaults(t *testing.T) {
|
|||||||
func TestParseMultiInt(t *testing.T) {
|
func TestParseMultiInt(t *testing.T) {
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntFlag{Name: "serve, s"},
|
&IntFlag{Name: "serve", Aliases: []string{"s"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if ctx.Int("serve") != 10 {
|
if ctx.Int("serve") != 10 {
|
||||||
@ -523,7 +609,7 @@ func TestParseDestinationInt(t *testing.T) {
|
|||||||
var dest int
|
var dest int
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntFlag{
|
&IntFlag{
|
||||||
Name: "dest",
|
Name: "dest",
|
||||||
Destination: &dest,
|
Destination: &dest,
|
||||||
},
|
},
|
||||||
@ -543,7 +629,7 @@ func TestParseMultiIntFromEnv(t *testing.T) {
|
|||||||
os.Setenv("APP_TIMEOUT_SECONDS", "10")
|
os.Setenv("APP_TIMEOUT_SECONDS", "10")
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntFlag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
|
&IntFlag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"APP_TIMEOUT_SECONDS"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if ctx.Int("timeout") != 10 {
|
if ctx.Int("timeout") != 10 {
|
||||||
@ -563,7 +649,7 @@ func TestParseMultiIntFromEnvCascade(t *testing.T) {
|
|||||||
os.Setenv("APP_TIMEOUT_SECONDS", "10")
|
os.Setenv("APP_TIMEOUT_SECONDS", "10")
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntFlag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
|
&IntFlag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"COMPAT_TIMEOUT_SECONDS", "APP_TIMEOUT_SECONDS"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if ctx.Int("timeout") != 10 {
|
if ctx.Int("timeout") != 10 {
|
||||||
@ -581,7 +667,7 @@ func TestParseMultiIntFromEnvCascade(t *testing.T) {
|
|||||||
func TestParseMultiIntSlice(t *testing.T) {
|
func TestParseMultiIntSlice(t *testing.T) {
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntSliceFlag{Name: "serve, s", Value: NewIntSlice()},
|
&IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewIntSlice()},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
|
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
|
||||||
@ -598,7 +684,7 @@ func TestParseMultiIntSlice(t *testing.T) {
|
|||||||
func TestParseMultiIntSliceWithDefaults(t *testing.T) {
|
func TestParseMultiIntSliceWithDefaults(t *testing.T) {
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntSliceFlag{Name: "serve, s", Value: NewIntSlice(9, 2)},
|
&IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewIntSlice(9, 2)},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
|
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{10, 20}) {
|
||||||
@ -615,7 +701,7 @@ func TestParseMultiIntSliceWithDefaults(t *testing.T) {
|
|||||||
func TestParseMultiIntSliceWithDefaultsUnset(t *testing.T) {
|
func TestParseMultiIntSliceWithDefaultsUnset(t *testing.T) {
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntSliceFlag{Name: "serve, s", Value: NewIntSlice(9, 2)},
|
&IntSliceFlag{Name: "serve", Aliases: []string{"s"}, Value: NewIntSlice(9, 2)},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{9, 2}) {
|
if !reflect.DeepEqual(ctx.IntSlice("serve"), []int{9, 2}) {
|
||||||
@ -635,7 +721,7 @@ func TestParseMultiIntSliceFromEnv(t *testing.T) {
|
|||||||
|
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntSliceFlag{Name: "intervals, i", Value: NewIntSlice(), EnvVar: "APP_INTERVALS"},
|
&IntSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewIntSlice(), EnvVars: []string{"APP_INTERVALS"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
|
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
|
||||||
@ -655,7 +741,7 @@ func TestParseMultiIntSliceFromEnvWithDefaults(t *testing.T) {
|
|||||||
|
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntSliceFlag{Name: "intervals, i", Value: NewIntSlice(1, 2, 5), EnvVar: "APP_INTERVALS"},
|
&IntSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewIntSlice(1, 2, 5), EnvVars: []string{"APP_INTERVALS"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
|
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
|
||||||
@ -675,7 +761,7 @@ func TestParseMultiIntSliceFromEnvCascade(t *testing.T) {
|
|||||||
|
|
||||||
(&App{
|
(&App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
IntSliceFlag{Name: "intervals, i", Value: NewIntSlice(), EnvVar: "COMPAT_INTERVALS,APP_INTERVALS"},
|
&IntSliceFlag{Name: "intervals", Aliases: []string{"i"}, Value: NewIntSlice(), EnvVars: []string{"COMPAT_INTERVALS", "APP_INTERVALS"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
|
if !reflect.DeepEqual(ctx.IntSlice("intervals"), []int{20, 30, 40}) {
|
||||||
@ -692,7 +778,7 @@ func TestParseMultiIntSliceFromEnvCascade(t *testing.T) {
|
|||||||
func TestParseMultiFloat64(t *testing.T) {
|
func TestParseMultiFloat64(t *testing.T) {
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
Float64Flag{Name: "serve, s"},
|
&Float64Flag{Name: "serve", Aliases: []string{"s"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if ctx.Float64("serve") != 10.2 {
|
if ctx.Float64("serve") != 10.2 {
|
||||||
@ -711,7 +797,7 @@ func TestParseDestinationFloat64(t *testing.T) {
|
|||||||
var dest float64
|
var dest float64
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
Float64Flag{
|
&Float64Flag{
|
||||||
Name: "dest",
|
Name: "dest",
|
||||||
Destination: &dest,
|
Destination: &dest,
|
||||||
},
|
},
|
||||||
@ -731,7 +817,7 @@ func TestParseMultiFloat64FromEnv(t *testing.T) {
|
|||||||
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
|
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
Float64Flag{Name: "timeout, t", EnvVar: "APP_TIMEOUT_SECONDS"},
|
&Float64Flag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"APP_TIMEOUT_SECONDS"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if ctx.Float64("timeout") != 15.5 {
|
if ctx.Float64("timeout") != 15.5 {
|
||||||
@ -751,7 +837,7 @@ func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
|
|||||||
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
|
os.Setenv("APP_TIMEOUT_SECONDS", "15.5")
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
Float64Flag{Name: "timeout, t", EnvVar: "COMPAT_TIMEOUT_SECONDS,APP_TIMEOUT_SECONDS"},
|
&Float64Flag{Name: "timeout", Aliases: []string{"t"}, EnvVars: []string{"COMPAT_TIMEOUT_SECONDS", "APP_TIMEOUT_SECONDS"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if ctx.Float64("timeout") != 15.5 {
|
if ctx.Float64("timeout") != 15.5 {
|
||||||
@ -769,7 +855,7 @@ func TestParseMultiFloat64FromEnvCascade(t *testing.T) {
|
|||||||
func TestParseMultiBool(t *testing.T) {
|
func TestParseMultiBool(t *testing.T) {
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
BoolFlag{Name: "serve, s"},
|
&BoolFlag{Name: "serve", Aliases: []string{"s"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if ctx.Bool("serve") != true {
|
if ctx.Bool("serve") != true {
|
||||||
@ -788,7 +874,7 @@ func TestParseDestinationBool(t *testing.T) {
|
|||||||
var dest bool
|
var dest bool
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
BoolFlag{
|
&BoolFlag{
|
||||||
Name: "dest",
|
Name: "dest",
|
||||||
Destination: &dest,
|
Destination: &dest,
|
||||||
},
|
},
|
||||||
@ -808,7 +894,7 @@ func TestParseMultiBoolFromEnv(t *testing.T) {
|
|||||||
os.Setenv("APP_DEBUG", "1")
|
os.Setenv("APP_DEBUG", "1")
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
BoolFlag{Name: "debug, d", EnvVar: "APP_DEBUG"},
|
&BoolFlag{Name: "debug", Aliases: []string{"d"}, EnvVars: []string{"APP_DEBUG"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if ctx.Bool("debug") != true {
|
if ctx.Bool("debug") != true {
|
||||||
@ -828,7 +914,7 @@ func TestParseMultiBoolFromEnvCascade(t *testing.T) {
|
|||||||
os.Setenv("APP_DEBUG", "1")
|
os.Setenv("APP_DEBUG", "1")
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
BoolFlag{Name: "debug, d", EnvVar: "COMPAT_DEBUG,APP_DEBUG"},
|
&BoolFlag{Name: "debug", Aliases: []string{"d"}, EnvVars: []string{"COMPAT_DEBUG", "APP_DEBUG"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if ctx.Bool("debug") != true {
|
if ctx.Bool("debug") != true {
|
||||||
@ -846,7 +932,7 @@ func TestParseMultiBoolFromEnvCascade(t *testing.T) {
|
|||||||
func TestParseMultiBoolTrue(t *testing.T) {
|
func TestParseMultiBoolTrue(t *testing.T) {
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
BoolFlag{Name: "implode, i", Value: true},
|
&BoolFlag{Name: "implode", Aliases: []string{"i"}, Value: true},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if ctx.Bool("implode") {
|
if ctx.Bool("implode") {
|
||||||
@ -866,7 +952,7 @@ func TestParseDestinationBoolTrue(t *testing.T) {
|
|||||||
|
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
BoolFlag{
|
&BoolFlag{
|
||||||
Name: "dest",
|
Name: "dest",
|
||||||
Value: true,
|
Value: true,
|
||||||
Destination: &dest,
|
Destination: &dest,
|
||||||
@ -887,10 +973,11 @@ func TestParseMultiBoolTrueFromEnv(t *testing.T) {
|
|||||||
os.Setenv("APP_DEBUG", "0")
|
os.Setenv("APP_DEBUG", "0")
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
BoolFlag{
|
&BoolFlag{
|
||||||
Name: "debug, d",
|
Name: "debug",
|
||||||
Value: true,
|
Aliases: []string{"d"},
|
||||||
EnvVar: "APP_DEBUG",
|
Value: true,
|
||||||
|
EnvVars: []string{"APP_DEBUG"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
@ -911,10 +998,11 @@ func TestParseMultiBoolTrueFromEnvCascade(t *testing.T) {
|
|||||||
os.Setenv("APP_DEBUG", "0")
|
os.Setenv("APP_DEBUG", "0")
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
BoolFlag{
|
&BoolFlag{
|
||||||
Name: "debug, d",
|
Name: "debug",
|
||||||
Value: true,
|
Aliases: []string{"d"},
|
||||||
EnvVar: "COMPAT_DEBUG,APP_DEBUG",
|
Value: true,
|
||||||
|
EnvVars: []string{"COMPAT_DEBUG", "APP_DEBUG"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
@ -951,7 +1039,7 @@ func (p *Parser) String() string {
|
|||||||
func TestParseGeneric(t *testing.T) {
|
func TestParseGeneric(t *testing.T) {
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
GenericFlag{Name: "serve, s", Value: &Parser{}},
|
&GenericFlag{Name: "serve", Aliases: []string{"s"}, Value: &Parser{}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) {
|
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"10", "20"}) {
|
||||||
@ -971,7 +1059,12 @@ func TestParseGenericFromEnv(t *testing.T) {
|
|||||||
os.Setenv("APP_SERVE", "20,30")
|
os.Setenv("APP_SERVE", "20,30")
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
GenericFlag{Name: "serve, s", Value: &Parser{}, EnvVar: "APP_SERVE"},
|
&GenericFlag{
|
||||||
|
Name: "serve",
|
||||||
|
Aliases: []string{"s"},
|
||||||
|
Value: &Parser{},
|
||||||
|
EnvVars: []string{"APP_SERVE"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) {
|
if !reflect.DeepEqual(ctx.Generic("serve"), &Parser{"20", "30"}) {
|
||||||
@ -991,7 +1084,11 @@ func TestParseGenericFromEnvCascade(t *testing.T) {
|
|||||||
os.Setenv("APP_FOO", "99,2000")
|
os.Setenv("APP_FOO", "99,2000")
|
||||||
a := App{
|
a := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
GenericFlag{Name: "foos", Value: &Parser{}, EnvVar: "COMPAT_FOO,APP_FOO"},
|
&GenericFlag{
|
||||||
|
Name: "foos",
|
||||||
|
Value: &Parser{},
|
||||||
|
EnvVars: []string{"COMPAT_FOO", "APP_FOO"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if !reflect.DeepEqual(ctx.Generic("foos"), &Parser{"99", "2000"}) {
|
if !reflect.DeepEqual(ctx.Generic("foos"), &Parser{"99", "2000"}) {
|
||||||
|
43
help.go
43
help.go
@ -74,7 +74,7 @@ OPTIONS:
|
|||||||
{{end}}{{end}}
|
{{end}}{{end}}
|
||||||
`
|
`
|
||||||
|
|
||||||
var helpCommand = Command{
|
var helpCommand = &Command{
|
||||||
Name: "help",
|
Name: "help",
|
||||||
Aliases: []string{"h"},
|
Aliases: []string{"h"},
|
||||||
Usage: "Shows a list of commands or help for one command",
|
Usage: "Shows a list of commands or help for one command",
|
||||||
@ -90,7 +90,7 @@ var helpCommand = Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var helpSubcommand = Command{
|
var helpSubcommand = &Command{
|
||||||
Name: "help",
|
Name: "help",
|
||||||
Aliases: []string{"h"},
|
Aliases: []string{"h"},
|
||||||
Usage: "Shows a list of commands or help for one command",
|
Usage: "Shows a list of commands or help for one command",
|
||||||
@ -149,7 +149,7 @@ func ShowCommandHelp(ctx *Context, command string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ctx.App.CommandNotFound == nil {
|
if ctx.App.CommandNotFound == nil {
|
||||||
return NewExitError(fmt.Sprintf("No help topic for '%v'", command), 3)
|
return Exit(fmt.Sprintf("No help topic for '%v'", command), 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.App.CommandNotFound(ctx, command)
|
ctx.App.CommandNotFound(ctx, command)
|
||||||
@ -158,7 +158,15 @@ func ShowCommandHelp(ctx *Context, command string) error {
|
|||||||
|
|
||||||
// ShowSubcommandHelp prints help for the given subcommand
|
// ShowSubcommandHelp prints help for the given subcommand
|
||||||
func ShowSubcommandHelp(c *Context) error {
|
func ShowSubcommandHelp(c *Context) error {
|
||||||
return ShowCommandHelp(c, c.Command.Name)
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Command != nil {
|
||||||
|
return ShowCommandHelp(c, c.Command.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ShowCommandHelp(c, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ShowVersion prints the version number of the App
|
// ShowVersion prints the version number of the App
|
||||||
@ -193,26 +201,39 @@ func printHelp(out io.Writer, templ string, data interface{}) {
|
|||||||
|
|
||||||
w := tabwriter.NewWriter(out, 0, 8, 1, '\t', 0)
|
w := tabwriter.NewWriter(out, 0, 8, 1, '\t', 0)
|
||||||
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
|
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
|
||||||
|
|
||||||
|
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 the writer is closed, t.Execute will fail, and there's nothing
|
if errDebug {
|
||||||
// we can do to recover.
|
|
||||||
if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" {
|
|
||||||
fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err)
|
fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Flush()
|
w.Flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkVersion(c *Context) bool {
|
func checkVersion(c *Context) bool {
|
||||||
found := false
|
found := false
|
||||||
if VersionFlag.Name != "" {
|
if VersionFlag.Name != "" {
|
||||||
eachName(VersionFlag.Name, func(name string) {
|
for _, name := range VersionFlag.Names() {
|
||||||
if c.Bool(name) {
|
if c.Bool(name) {
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
@ -220,11 +241,11 @@ func checkVersion(c *Context) bool {
|
|||||||
func checkHelp(c *Context) bool {
|
func checkHelp(c *Context) bool {
|
||||||
found := false
|
found := false
|
||||||
if HelpFlag.Name != "" {
|
if HelpFlag.Name != "" {
|
||||||
eachName(HelpFlag.Name, func(name string) {
|
for _, name := range HelpFlag.Names() {
|
||||||
if c.Bool(name) {
|
if c.Bool(name) {
|
||||||
found = true
|
found = true
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
|
34
help_test.go
34
help_test.go
@ -59,14 +59,15 @@ func Test_Help_Custom_Flags(t *testing.T) {
|
|||||||
HelpFlag = oldFlag
|
HelpFlag = oldFlag
|
||||||
}()
|
}()
|
||||||
|
|
||||||
HelpFlag = BoolFlag{
|
HelpFlag = &BoolFlag{
|
||||||
Name: "help, x",
|
Name: "help",
|
||||||
Usage: "show help",
|
Aliases: []string{"x"},
|
||||||
|
Usage: "show help",
|
||||||
}
|
}
|
||||||
|
|
||||||
app := App{
|
app := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
BoolFlag{Name: "foo, h"},
|
&BoolFlag{Name: "foo", Aliases: []string{"h"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if ctx.Bool("h") != true {
|
if ctx.Bool("h") != true {
|
||||||
@ -89,14 +90,15 @@ func Test_Version_Custom_Flags(t *testing.T) {
|
|||||||
VersionFlag = oldFlag
|
VersionFlag = oldFlag
|
||||||
}()
|
}()
|
||||||
|
|
||||||
VersionFlag = BoolFlag{
|
VersionFlag = &BoolFlag{
|
||||||
Name: "version, V",
|
Name: "version",
|
||||||
Usage: "show version",
|
Aliases: []string{"V"},
|
||||||
|
Usage: "show version",
|
||||||
}
|
}
|
||||||
|
|
||||||
app := App{
|
app := App{
|
||||||
Flags: []Flag{
|
Flags: []Flag{
|
||||||
BoolFlag{Name: "foo, v"},
|
&BoolFlag{Name: "foo", Aliases: []string{"v"}},
|
||||||
},
|
},
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
if ctx.Bool("v") != true {
|
if ctx.Bool("v") != true {
|
||||||
@ -127,9 +129,9 @@ func Test_helpCommand_Action_ErrorIfNoTopic(t *testing.T) {
|
|||||||
t.Fatalf("expected error from helpCommand.Action(), but got nil")
|
t.Fatalf("expected error from helpCommand.Action(), but got nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
exitErr, ok := err.(*ExitError)
|
exitErr, ok := err.(*exitError)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("expected ExitError from helpCommand.Action(), but instead got: %v", err.Error())
|
t.Fatalf("expected *exitError from helpCommand.Action(), but instead got: %v", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(exitErr.Error(), "No help topic for") {
|
if !strings.HasPrefix(exitErr.Error(), "No help topic for") {
|
||||||
@ -155,9 +157,9 @@ func Test_helpSubcommand_Action_ErrorIfNoTopic(t *testing.T) {
|
|||||||
t.Fatalf("expected error from helpCommand.Action(), but got nil")
|
t.Fatalf("expected error from helpCommand.Action(), but got nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
exitErr, ok := err.(*ExitError)
|
exitErr, ok := err.(*exitError)
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("expected ExitError from helpCommand.Action(), but instead got: %v", err.Error())
|
t.Fatalf("expected *exitError from helpCommand.Action(), but instead got: %v", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if !strings.HasPrefix(exitErr.Error(), "No help topic for") {
|
if !strings.HasPrefix(exitErr.Error(), "No help topic for") {
|
||||||
@ -171,7 +173,7 @@ func Test_helpSubcommand_Action_ErrorIfNoTopic(t *testing.T) {
|
|||||||
|
|
||||||
func TestShowAppHelp_CommandAliases(t *testing.T) {
|
func TestShowAppHelp_CommandAliases(t *testing.T) {
|
||||||
app := &App{
|
app := &App{
|
||||||
Commands: []Command{
|
Commands: []*Command{
|
||||||
{
|
{
|
||||||
Name: "frobbly",
|
Name: "frobbly",
|
||||||
Aliases: []string{"fr", "frob"},
|
Aliases: []string{"fr", "frob"},
|
||||||
@ -193,7 +195,7 @@ func TestShowAppHelp_CommandAliases(t *testing.T) {
|
|||||||
|
|
||||||
func TestShowCommandHelp_CommandAliases(t *testing.T) {
|
func TestShowCommandHelp_CommandAliases(t *testing.T) {
|
||||||
app := &App{
|
app := &App{
|
||||||
Commands: []Command{
|
Commands: []*Command{
|
||||||
{
|
{
|
||||||
Name: "frobbly",
|
Name: "frobbly",
|
||||||
Aliases: []string{"fr", "frob", "bork"},
|
Aliases: []string{"fr", "frob", "bork"},
|
||||||
@ -219,7 +221,7 @@ func TestShowCommandHelp_CommandAliases(t *testing.T) {
|
|||||||
|
|
||||||
func TestShowSubcommandHelp_CommandAliases(t *testing.T) {
|
func TestShowSubcommandHelp_CommandAliases(t *testing.T) {
|
||||||
app := &App{
|
app := &App{
|
||||||
Commands: []Command{
|
Commands: []*Command{
|
||||||
{
|
{
|
||||||
Name: "frobbly",
|
Name: "frobbly",
|
||||||
Aliases: []string{"fr", "frob", "bork"},
|
Aliases: []string{"fr", "frob", "bork"},
|
||||||
@ -241,7 +243,7 @@ func TestShowSubcommandHelp_CommandAliases(t *testing.T) {
|
|||||||
|
|
||||||
func TestShowAppHelp_HiddenCommand(t *testing.T) {
|
func TestShowAppHelp_HiddenCommand(t *testing.T) {
|
||||||
app := &App{
|
app := &App{
|
||||||
Commands: []Command{
|
Commands: []*Command{
|
||||||
{
|
{
|
||||||
Name: "frobbly",
|
Name: "frobbly",
|
||||||
Action: func(ctx *Context) error {
|
Action: func(ctx *Context) error {
|
||||||
|
@ -12,6 +12,10 @@ var (
|
|||||||
wd, _ = os.Getwd()
|
wd, _ = os.Getwd()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
os.Setenv("CLI_TEMPLATE_REPANIC", "1")
|
||||||
|
}
|
||||||
|
|
||||||
func expect(t *testing.T, a interface{}, b interface{}) {
|
func expect(t *testing.T, a interface{}, b interface{}) {
|
||||||
_, fn, line, _ := runtime.Caller(1)
|
_, fn, line, _ := runtime.Caller(1)
|
||||||
fn = strings.Replace(fn, wd+"/", "", -1)
|
fn = strings.Replace(fn, wd+"/", "", -1)
|
||||||
|
16
runtests
16
runtests
@ -10,7 +10,7 @@ from subprocess import check_call, check_output
|
|||||||
|
|
||||||
|
|
||||||
PACKAGE_NAME = os.environ.get(
|
PACKAGE_NAME = os.environ.get(
|
||||||
'CLI_PACKAGE_NAME', 'github.com/codegangsta/cli'
|
'CLI_PACKAGE_NAME', 'github.com/urfave/cli'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -49,9 +49,9 @@ def _test():
|
|||||||
('{}/{}'.format(PACKAGE_NAME, subpackage)).rstrip('/')
|
('{}/{}'.format(PACKAGE_NAME, subpackage)).rstrip('/')
|
||||||
])
|
])
|
||||||
|
|
||||||
combined = _combine_coverprofiles(coverprofiles)
|
combined_name = _combine_coverprofiles(coverprofiles)
|
||||||
_run('go tool cover -func={}'.format(combined.name).split())
|
_run('go tool cover -func={}'.format(combined_name).split())
|
||||||
combined.close()
|
os.remove(combined_name)
|
||||||
|
|
||||||
|
|
||||||
def _gfmxr():
|
def _gfmxr():
|
||||||
@ -78,7 +78,9 @@ def _is_go_runnable(line):
|
|||||||
|
|
||||||
|
|
||||||
def _combine_coverprofiles(coverprofiles):
|
def _combine_coverprofiles(coverprofiles):
|
||||||
combined = tempfile.NamedTemporaryFile(suffix='.coverprofile')
|
combined = tempfile.NamedTemporaryFile(
|
||||||
|
suffix='.coverprofile', delete=False
|
||||||
|
)
|
||||||
combined.write('mode: set\n')
|
combined.write('mode: set\n')
|
||||||
|
|
||||||
for coverprofile in coverprofiles:
|
for coverprofile in coverprofiles:
|
||||||
@ -88,7 +90,9 @@ def _combine_coverprofiles(coverprofiles):
|
|||||||
combined.write(line)
|
combined.write(line)
|
||||||
|
|
||||||
combined.flush()
|
combined.flush()
|
||||||
return combined
|
name = combined.name
|
||||||
|
combined.close()
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
Loading…
Reference in New Issue
Block a user