Merge pull request #465 from urfave/declarativeness

Remove `NewApp` initializer
This commit is contained in:
Jesse Szwedko 2016-06-25 11:08:53 -05:00 committed by GitHub
commit ee464a6db7
11 changed files with 820 additions and 768 deletions

View File

@ -35,10 +35,11 @@ before_script:
- if [ ! -f node_modules/.bin/markdown-toc ] ; then
npm install markdown-toc ;
fi
- go get github.com/urfave/gfmxr/...
- mkdir -p ${GOPATH%%:*}/src/gopkg.in/urfave
- rm -rvf ${GOPATH%%:*}/src/gopkg.in/urfave/cli.v2
- rm -rvf ${GOPATH%%:*}/pkg/*/gopkg.in/urfave/cli.v2.a
- ln -sv ${TRAVIS_BUILD_DIR} ${GOPATH%%:*}/src/gopkg.in/urfave/cli.v2
- go get github.com/urfave/gfmxr/...
script:
- flake8 runtests cli-v1-to-v2

206
README.md
View File

@ -146,7 +146,7 @@ import (
)
func main() {
cli.NewApp().Run(os.Args)
(&cli.App{}).Run(os.Args)
}
```
@ -167,12 +167,13 @@ import (
)
func main() {
app := cli.NewApp()
app.Name = "boom"
app.Usage = "make an explosive entrance"
app.Action = func(c *cli.Context) error {
app := &cli.App{
Name: "boom",
Usage: "make an explosive entrance",
Action: func(c *cli.Context) error {
fmt.Println("boom! I say!")
return nil
},
}
app.Run(os.Args)
@ -205,12 +206,13 @@ import (
)
func main() {
app := cli.NewApp()
app.Name = "greet"
app.Usage = "fight the loneliness!"
app.Action = func(c *cli.Context) error {
app := &cli.App{
Name: "greet",
Usage: "fight the loneliness!",
Action: func(c *cli.Context) error {
fmt.Println("Hello friend!")
return nil
},
}
app.Run(os.Args)
@ -268,11 +270,11 @@ import (
)
func main() {
app := cli.NewApp()
app.Action = func(c *cli.Context) error {
app := &cli.App{
Action: func(c *cli.Context) error {
fmt.Printf("Hello %q", c.Args().Get(0))
return nil
},
}
app.Run(os.Args)
@ -297,17 +299,15 @@ import (
)
func main() {
app := cli.NewApp()
app.Flags = []cli.Flag {
app := &cli.App{
Flags: []cli.Flag {
&cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
},
}
app.Action = func(c *cli.Context) error {
},
Action: func(c *cli.Context) error {
name := "Nefertiti"
if c.NArg() > 0 {
name = c.Args().Get(0)
@ -318,6 +318,7 @@ func main() {
fmt.Println("Hello", name)
}
return nil
},
}
app.Run(os.Args)
@ -343,18 +344,16 @@ import (
func main() {
var language string
app := cli.NewApp()
app.Flags = []cli.Flag {
app := &cli.App{
Flags: []cli.Flag {
&cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
Destination: &language,
},
}
app.Action = func(c *cli.Context) error {
},
Action: func(c *cli.Context) error {
name := "someone"
if c.NArg() > 0 {
name = c.Args().Get(0)
@ -365,6 +364,7 @@ func main() {
fmt.Println("Hello", name)
}
return nil
},
}
app.Run(os.Args)
@ -394,14 +394,14 @@ import (
)
func main() {
app := cli.NewApp()
app.Flags = []cli.Flag{
app := &cli.App{
Flags: []cli.Flag{
&cli.StringFlag{
Name: "config",
Aliases: []string{"c"},
Usage: "Load configuration from `FILE`",
},
},
}
app.Run(os.Args)
@ -436,15 +436,15 @@ import (
)
func main() {
app := cli.NewApp()
app.Flags = []cli.Flag {
app := &cli.App{
Flags: []cli.Flag {
&cli.StringFlag{
Name: "lang",
Aliases: []string{"l"},
Value: "english",
Usage: "language for the greeting",
},
},
}
app.Run(os.Args)
@ -473,9 +473,8 @@ import (
)
func main() {
app := cli.NewApp()
app.Flags = []cli.Flag {
app := &cli.App{
Flags: []cli.Flag {
&cli.StringFlag{
Name: "lang",
Aliases: []string{"l"},
@ -483,6 +482,7 @@ func main() {
Usage: "language for the greeting",
EnvVars: []string{"APP_LANG"},
},
},
}
app.Run(os.Args)
@ -506,9 +506,8 @@ import (
)
func main() {
app := cli.NewApp()
app.Flags = []cli.Flag{
app := &cli.App{
Flags: []cli.Flag{
&cli.StringFlag{
Name: "lang",
Aliases: []string{"l"},
@ -516,6 +515,7 @@ func main() {
Usage: "language for the greeting",
EnvVars: []string{"LEGACY_COMPAT_LANG", "APP_LANG", "LANG"},
},
},
}
app.Run(os.Args)
@ -569,21 +569,20 @@ import (
)
func main() {
app := cli.NewApp()
flags := []cli.Flag{
altsrc.NewIntFlag(&cli.IntFlag{Name: "test"}),
&cli.StringFlag{Name: "load"},
}
app.Action = func(c *cli.Context) error {
app := &cli.App{
Action: func(c *cli.Context) error {
fmt.Println("yaml ist rad")
return nil
},
Before: altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc("load")),
Flags: flags,
}
app.Before = altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc("load"))
app.Flags = flags
app.Run(os.Args)
}
```
@ -607,9 +606,8 @@ import (
)
func main() {
app := cli.NewApp()
app.Commands = []*cli.Command{
app := &cli.App{
Commands: []*cli.Command{
{
Name: "add",
Aliases: []string{"a"},
@ -651,6 +649,7 @@ func main() {
},
},
},
},
}
app.Run(os.Args)
@ -675,9 +674,8 @@ import (
)
func main() {
app := cli.NewApp()
app.Commands = []*cli.Command{
app := &cli.App{
Commands: []*cli.Command{
{
Name: "noop",
},
@ -689,6 +687,7 @@ func main() {
Name: "remove",
Category: "template",
},
},
}
app.Run(os.Args)
@ -723,19 +722,20 @@ import (
)
func main() {
app := cli.NewApp()
app.Flags = []cli.Flag{
app := &cli.App{
Flags: []cli.Flag{
&cli.BoolFlag{
Name: "ginger-crouton",
Value: true,
Usage: "is it in the soup?",
},
}
app.Action = func(ctx *cli.Context) error {
},
Action: func(ctx *cli.Context) error {
if !ctx.Bool("ginger-crouton") {
return cli.Exit("it is not in the soup", 86)
}
return nil
},
}
app.Run(os.Args)
@ -766,9 +766,9 @@ import (
func main() {
tasks := []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
app := cli.NewApp()
app.EnableBashCompletion = true
app.Commands = []*cli.Command{
app := &cli.App{
EnableBashCompletion: true,
Commands: []*cli.Command{
{
Name: "complete",
Aliases: []string{"c"},
@ -787,6 +787,7 @@ func main() {
}
},
},
},
}
app.Run(os.Args)
@ -840,12 +841,13 @@ func main() {
Hidden: true,
}
app := cli.NewApp()
app.EnableBashCompletion = true
app.Commands = []*cli.Command{
app := &cli.App{
EnableBashCompletion: true,
Commands: []*cli.Command{
{
Name: "wat",
},
},
}
app.Run(os.Args)
}
@ -919,7 +921,7 @@ VERSION:
fmt.Println("Ha HA. I pwnd the help!!1")
}
cli.NewApp().Run(os.Args)
(&cli.App{}).Run(os.Args)
}
```
@ -946,7 +948,7 @@ func main() {
EnvVars: []string{"SHOW_HALP", "HALPPLZ"},
}
cli.NewApp().Run(os.Args)
(&cli.App{}).Run(os.Args)
}
```
@ -980,9 +982,10 @@ func main() {
Usage: "print only the version",
}
app := cli.NewApp()
app.Name = "partay"
app.Version = "v19.99.0"
app := &cli.App{
Name: "partay",
Version: "v19.99.0",
}
app.Run(os.Args)
}
```
@ -1012,9 +1015,10 @@ func main() {
fmt.Printf("version=%s revision=%s\n", c.App.Version, Revision)
}
app := cli.NewApp()
app.Name = "partay"
app.Version = "v19.99.0"
app := &cli.App{
Name: "partay",
Version: "v19.99.0",
}
app.Run(os.Args)
}
```
@ -1091,22 +1095,22 @@ func (g *genericType) String() string {
}
func main() {
app := cli.NewApp()
app.Name = "kənˈtrīv"
app.Version = "v19.99.0"
app.Compiled = time.Now()
app.Authors = []*cli.Author{
app := cli.App{
Name: "kənˈtrīv",
Version: "v19.99.0",
Compiled: time.Now(),
Authors: []*cli.Author{
&cli.Author{
Name: "Example Human",
Email: "human@example.com",
},
}
app.Copyright = "(c) 1999 Serious Enterprise"
app.HelpName = "contrive"
app.Usage = "demonstrate available API"
app.UsageText = "contrive - demonstrating the available API"
app.ArgsUsage = "[args and such]"
app.Commands = []*cli.Command{
},
Copyright: "(c) 1999 Serious Enterprise",
HelpName: "contrive",
Usage: "demonstrate available API",
UsageText: "contrive - demonstrating the available API",
ArgsUsage: "[args and such]",
Commands: []*cli.Command{
&cli.Command{
Name: "doo",
Aliases: []string{"do"},
@ -1155,8 +1159,8 @@ func main() {
return err
},
},
}
app.Flags = []cli.Flag{
},
Flags: []cli.Flag{
&cli.BoolFlag{Name: "fancy"},
&cli.BoolFlag{Value: true, Name: "fancier"},
&cli.DurationFlag{Name: "howlong", Aliases: []string{"H"}, Value: time.Second * 3},
@ -1170,33 +1174,33 @@ func main() {
&cli.StringSliceFlag{Name: "names", Aliases: []string{"N"}},
&cli.UintFlag{Name: "age"},
&cli.Uint64Flag{Name: "bigage"},
}
app.EnableBashCompletion = true
app.HideHelp = false
app.HideVersion = false
app.BashComplete = func(c *cli.Context) {
},
EnableBashCompletion: true,
HideHelp: false,
HideVersion: false,
BashComplete: func(c *cli.Context) {
fmt.Fprintf(c.App.Writer, "lipstick\nkiss\nme\nlipstick\nringo\n")
}
app.Before = func(c *cli.Context) error {
},
Before: func(c *cli.Context) error {
fmt.Fprintf(c.App.Writer, "HEEEERE GOES\n")
return nil
}
app.After = func(c *cli.Context) error {
},
After: func(c *cli.Context) error {
fmt.Fprintf(c.App.Writer, "Phew!\n")
return nil
}
app.CommandNotFound = func(c *cli.Context, command string) {
},
CommandNotFound: func(c *cli.Context, command string) {
fmt.Fprintf(c.App.Writer, "Thar be no %q here.\n", command)
}
app.OnUsageError = func(c *cli.Context, err error, isSubcommand bool) error {
},
OnUsageError: func(c *cli.Context, err error, isSubcommand bool) error {
if isSubcommand {
return err
}
fmt.Fprintf(c.App.Writer, "WRONG: %#v\n", err)
return nil
}
app.Action = func(c *cli.Context) error {
},
Action: func(c *cli.Context) error {
cli.DefaultAppComplete(c)
cli.HandleExitCoder(errors.New("not an exit coder, though"))
cli.ShowAppHelp(c)
@ -1268,6 +1272,12 @@ func main() {
fmt.Fprintf(c.App.Writer, "%d", ec.ExitCode())
fmt.Printf("made it!\n")
return ec
},
Metadata: map[string]interface{}{
"layers": "many",
"explicable": false,
"whatever-values": 19.99,
},
}
if os.Getenv("HEXY") != "" {
@ -1275,12 +1285,6 @@ func main() {
app.ErrWriter = &hexWriter{}
}
app.Metadata = map[string]interface{}{
"layers": "many",
"explicable": false,
"whatever-values": 19.99,
}
app.Run(os.Args)
}

View File

@ -15,7 +15,7 @@ import (
)
func TestCommandYamlFileTest(t *testing.T) {
app := cli.NewApp()
app := &cli.App{}
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
defer os.Remove("current.yaml")
@ -45,7 +45,7 @@ func TestCommandYamlFileTest(t *testing.T) {
}
func TestCommandYamlFileTestGlobalEnvVarWins(t *testing.T) {
app := cli.NewApp()
app := &cli.App{}
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
defer os.Remove("current.yaml")
@ -79,7 +79,7 @@ func TestCommandYamlFileTestGlobalEnvVarWins(t *testing.T) {
}
func TestCommandYamlFileTestGlobalEnvVarWinsNested(t *testing.T) {
app := cli.NewApp()
app := &cli.App{}
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.yaml", []byte(`top:
test: 15`), 0666)
@ -114,7 +114,7 @@ func TestCommandYamlFileTestGlobalEnvVarWinsNested(t *testing.T) {
}
func TestCommandYamlFileTestSpecifiedFlagWins(t *testing.T) {
app := cli.NewApp()
app := &cli.App{}
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
defer os.Remove("current.yaml")
@ -146,7 +146,7 @@ func TestCommandYamlFileTestSpecifiedFlagWins(t *testing.T) {
}
func TestCommandYamlFileTestSpecifiedFlagWinsNested(t *testing.T) {
app := cli.NewApp()
app := &cli.App{}
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.yaml", []byte(`top:
test: 15`), 0666)
@ -179,7 +179,7 @@ func TestCommandYamlFileTestSpecifiedFlagWinsNested(t *testing.T) {
}
func TestCommandYamlFileTestDefaultValueFileWins(t *testing.T) {
app := cli.NewApp()
app := &cli.App{}
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
defer os.Remove("current.yaml")
@ -211,7 +211,7 @@ func TestCommandYamlFileTestDefaultValueFileWins(t *testing.T) {
}
func TestCommandYamlFileTestDefaultValueFileWinsNested(t *testing.T) {
app := cli.NewApp()
app := &cli.App{}
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.yaml", []byte(`top:
test: 15`), 0666)
@ -244,7 +244,7 @@ func TestCommandYamlFileTestDefaultValueFileWinsNested(t *testing.T) {
}
func TestCommandYamlFileFlagHasDefaultGlobalEnvYamlSetGlobalEnvWins(t *testing.T) {
app := cli.NewApp()
app := &cli.App{}
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.yaml", []byte("test: 15"), 0666)
defer os.Remove("current.yaml")
@ -278,7 +278,7 @@ func TestCommandYamlFileFlagHasDefaultGlobalEnvYamlSetGlobalEnvWins(t *testing.T
}
func TestCommandYamlFileFlagHasDefaultGlobalEnvYamlSetGlobalEnvWinsNested(t *testing.T) {
app := cli.NewApp()
app := &cli.App{}
set := flag.NewFlagSet("test", 0)
ioutil.WriteFile("current.yaml", []byte(`top:
test: 15`), 0666)

51
app.go
View File

@ -11,8 +11,7 @@ import (
"time"
)
// App is the main structure of a cli application. It is recommended that
// an app be created with the cli.NewApp() function
// App is the main structure of a cli application.
type App struct {
// The name of the program. Defaults to path.Base(os.Args[0])
Name string
@ -78,22 +77,6 @@ func compileTime() time.Time {
return info.ModTime()
}
// NewApp creates a new cli Application with some reasonable defaults for Name,
// Usage, Version and Action.
func NewApp() *App {
return &App{
Name: filepath.Base(os.Args[0]),
HelpName: filepath.Base(os.Args[0]),
Usage: "A new cli application",
UsageText: "",
Version: "0.0.0",
BashComplete: DefaultAppComplete,
Action: helpCommand.Action,
Compiled: compileTime(),
Writer: os.Stdout,
}
}
// Setup runs initialization code to ensure all data structures are ready for
// `Run` or inspection prior to `Run`. It is internally called by `Run`, but
// will return early if setup has already happened.
@ -104,6 +87,38 @@ func (a *App) Setup() {
a.didSetup = true
if a.Name == "" {
a.Name = filepath.Base(os.Args[0])
}
if a.HelpName == "" {
a.HelpName = filepath.Base(os.Args[0])
}
if a.Usage == "" {
a.Usage = "A new cli application"
}
if a.Version == "" {
a.Version = "0.0.0"
}
if a.BashComplete == nil {
a.BashComplete = DefaultAppComplete
}
if a.Action == nil {
a.Action = helpCommand.Action
}
if a.Compiled == (time.Time{}) {
a.Compiled = compileTime()
}
if a.Writer == nil {
a.Writer = os.Stdout
}
newCmds := []*Command{}
for _, c := range a.Commands {
if c.HelpName == "" {

View File

@ -21,17 +21,19 @@ func ExampleApp_Run() {
// set args for examples sake
os.Args = []string{"greet", "--name", "Jeremy"}
app := NewApp()
app.Name = "greet"
app.Flags = []Flag{
app := &App{
Name: "greet",
Flags: []Flag{
&StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
}
app.Action = func(c *Context) error {
},
Action: func(c *Context) error {
fmt.Printf("Hello %v\n", c.String("name"))
return nil
},
UsageText: "app [first_arg] [second_arg]",
Authors: []*Author{{Name: "Oliver Allen", Email: "oliver@toyshop.example.com"}},
}
app.UsageText = "app [first_arg] [second_arg]"
app.Authors = []*Author{{Name: "Oliver Allen", Email: "oliver@toyshop.example.com"}}
app.Run(os.Args)
// Output:
// Hello Jeremy
@ -40,9 +42,9 @@ func ExampleApp_Run() {
func ExampleApp_Run_subcommand() {
// set args for examples sake
os.Args = []string{"say", "hi", "english", "--name", "Jeremy"}
app := NewApp()
app.Name = "say"
app.Commands = []*Command{
app := &App{
Name: "say",
Commands: []*Command{
{
Name: "hello",
Aliases: []string{"hi"},
@ -68,6 +70,7 @@ func ExampleApp_Run_subcommand() {
},
},
},
},
}
app.Run(os.Args)
@ -79,12 +82,12 @@ func ExampleApp_Run_help() {
// set args for examples sake
os.Args = []string{"greet", "h", "describeit"}
app := NewApp()
app.Name = "greet"
app.Flags = []Flag{
app := &App{
Name: "greet",
Flags: []Flag{
&StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
}
app.Commands = []*Command{
},
Commands: []*Command{
{
Name: "describeit",
Aliases: []string{"d"},
@ -95,6 +98,7 @@ func ExampleApp_Run_help() {
return nil
},
},
},
}
app.Run(os.Args)
// Output:
@ -112,10 +116,10 @@ func ExampleApp_Run_bashComplete() {
// set args for examples sake
os.Args = []string{"greet", "--generate-bash-completion"}
app := NewApp()
app.Name = "greet"
app.EnableBashCompletion = true
app.Commands = []*Command{
app := &App{
Name: "greet",
EnableBashCompletion: true,
Commands: []*Command{
{
Name: "describeit",
Aliases: []string{"d"},
@ -134,6 +138,7 @@ func ExampleApp_Run_bashComplete() {
return nil
},
},
},
}
app.Run(os.Args)
@ -148,10 +153,11 @@ func ExampleApp_Run_bashComplete() {
func TestApp_Run(t *testing.T) {
s := ""
app := NewApp()
app.Action = func(c *Context) error {
app := &App{
Action: func(c *Context) error {
s = s + c.Args().First()
return nil
},
}
err := app.Run([]string{"command", "foo"})
@ -174,7 +180,7 @@ var commandAppTests = []struct {
}
func TestApp_Command(t *testing.T) {
app := NewApp()
app := &App{}
fooCommand := &Command{Name: "foobar", Aliases: []string{"f"}}
batCommand := &Command{Name: "batbaz", Aliases: []string{"b"}}
app.Commands = []*Command{
@ -190,8 +196,8 @@ func TestApp_Command(t *testing.T) {
func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
var context *Context
a := NewApp()
a.Commands = []*Command{
a := &App{
Commands: []*Command{
{
Name: "foo",
Action: func(c *Context) error {
@ -207,6 +213,7 @@ func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
},
Before: func(_ *Context) error { return nil },
},
},
}
a.Run([]string{"", "foo", "--lang", "spanish", "abcd"})
@ -218,7 +225,7 @@ func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
var parsedOption string
var args Args
app := NewApp()
app := &App{}
command := &Command{
Name: "cmd",
Flags: []Flag{
@ -243,7 +250,7 @@ func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
func TestApp_CommandWithDash(t *testing.T) {
var args Args
app := NewApp()
app := &App{}
command := &Command{
Name: "cmd",
Action: func(c *Context) error {
@ -262,7 +269,7 @@ func TestApp_CommandWithDash(t *testing.T) {
func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
var args Args
app := NewApp()
app := &App{}
command := &Command{
Name: "cmd",
Action: func(c *Context) error {
@ -280,8 +287,8 @@ func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
}
func TestApp_VisibleCommands(t *testing.T) {
app := NewApp()
app.Commands = []*Command{
app := &App{
Commands: []*Command{
{
Name: "frob",
HelpName: "foo frob",
@ -293,6 +300,7 @@ func TestApp_VisibleCommands(t *testing.T) {
Hidden: true,
Action: func(_ *Context) error { return nil },
},
},
}
app.Setup()
@ -332,13 +340,14 @@ func TestApp_VisibleCommands(t *testing.T) {
func TestApp_Float64Flag(t *testing.T) {
var meters float64
app := NewApp()
app.Flags = []Flag{
app := &App{
Flags: []Flag{
&Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"},
}
app.Action = func(c *Context) error {
},
Action: func(c *Context) error {
meters = c.Float64("height")
return nil
},
}
app.Run([]string{"", "--height", "1.93"})
@ -350,7 +359,7 @@ func TestApp_ParseSliceFlags(t *testing.T) {
var parsedIntSlice []int
var parsedStringSlice []string
app := NewApp()
app := &App{}
command := &Command{
Name: "cmd",
Flags: []Flag{
@ -408,7 +417,7 @@ func TestApp_ParseSliceFlagsWithMissingValue(t *testing.T) {
var parsedIntSlice []int
var parsedStringSlice []string
app := NewApp()
app := &App{}
command := &Command{
Name: "cmd",
Flags: []Flag{
@ -438,7 +447,8 @@ func TestApp_ParseSliceFlagsWithMissingValue(t *testing.T) {
}
func TestApp_DefaultStdout(t *testing.T) {
app := NewApp()
app := &App{}
app.Setup()
if app.Writer != os.Stdout {
t.Error("Default output writer not set.")
@ -466,9 +476,10 @@ func (fw *mockWriter) GetWritten() (b []byte) {
func TestApp_SetStdout(t *testing.T) {
w := &mockWriter{}
app := NewApp()
app.Name = "test"
app.Writer = w
app := &App{
Name: "test",
Writer: w,
}
err := app.Run([]string{"help"})
@ -486,9 +497,8 @@ func TestApp_BeforeFunc(t *testing.T) {
beforeError := fmt.Errorf("fail")
var err error
app := NewApp()
app.Before = func(c *Context) error {
app := &App{
Before: func(c *Context) error {
counts.Total++
counts.Before = counts.Total
s := c.String("opt")
@ -497,9 +507,8 @@ func TestApp_BeforeFunc(t *testing.T) {
}
return nil
}
app.Commands = []*Command{
},
Commands: []*Command{
{
Name: "sub",
Action: func(c *Context) error {
@ -508,10 +517,10 @@ func TestApp_BeforeFunc(t *testing.T) {
return nil
},
},
}
app.Flags = []Flag{
},
Flags: []Flag{
&StringFlag{Name: "opt"},
},
}
// run with the Before() func succeeding
@ -578,9 +587,8 @@ func TestApp_AfterFunc(t *testing.T) {
afterError := fmt.Errorf("fail")
var err error
app := NewApp()
app.After = func(c *Context) error {
app := &App{
After: func(c *Context) error {
counts.Total++
counts.After = counts.Total
s := c.String("opt")
@ -589,9 +597,8 @@ func TestApp_AfterFunc(t *testing.T) {
}
return nil
}
app.Commands = []*Command{
},
Commands: []*Command{
{
Name: "sub",
Action: func(c *Context) error {
@ -600,10 +607,10 @@ func TestApp_AfterFunc(t *testing.T) {
return nil
},
},
}
app.Flags = []Flag{
},
Flags: []Flag{
&StringFlag{Name: "opt"},
},
}
// run with the After() func succeeding
@ -649,8 +656,7 @@ func TestAppNoHelpFlag(t *testing.T) {
HelpFlag = nil
app := NewApp()
app.Writer = ioutil.Discard
app := &App{Writer: ioutil.Discard}
err := app.Run([]string{"test", "-h"})
if err != flag.ErrHelp {
@ -669,7 +675,7 @@ func TestAppHelpPrinter(t *testing.T) {
wasCalled = true
}
app := NewApp()
app := &App{}
app.Run([]string{"-h"})
if wasCalled == false {
@ -688,7 +694,7 @@ func TestApp_VersionPrinter(t *testing.T) {
wasCalled = true
}
app := NewApp()
app := &App{}
ctx := NewContext(app, nil, nil)
ShowVersion(ctx)
@ -699,14 +705,12 @@ func TestApp_VersionPrinter(t *testing.T) {
func TestApp_CommandNotFound(t *testing.T) {
counts := &opCounts{}
app := NewApp()
app.CommandNotFound = func(c *Context, command string) {
app := &App{
CommandNotFound: func(c *Context, command string) {
counts.Total++
counts.CommandNotFound = counts.Total
}
app.Commands = []*Command{
},
Commands: []*Command{
{
Name: "bar",
Action: func(c *Context) error {
@ -715,6 +719,7 @@ func TestApp_CommandNotFound(t *testing.T) {
return nil
},
},
},
}
app.Run([]string{"command", "foo"})
@ -729,17 +734,17 @@ func TestApp_OrderOfOperations(t *testing.T) {
resetCounts := func() { counts = &opCounts{} }
app := NewApp()
app.EnableBashCompletion = true
app.BashComplete = func(c *Context) {
app := &App{
EnableBashCompletion: true,
BashComplete: func(c *Context) {
counts.Total++
counts.BashComplete = counts.Total
}
app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
},
OnUsageError: func(c *Context, err error, isSubcommand bool) error {
counts.Total++
counts.OnUsageError = counts.Total
return errors.New("hay OnUsageError")
},
}
beforeNoError := func(c *Context) error {
@ -875,7 +880,7 @@ func TestApp_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) {
for _, flagSet := range subcommandHelpTopics {
t.Logf("==> checking with flags %v", flagSet)
app := NewApp()
app := &App{}
buf := new(bytes.Buffer)
app.Writer = buf
@ -920,7 +925,7 @@ func TestApp_Run_CommandWithSubcommandHasHelpTopic(t *testing.T) {
}
func TestApp_Run_SubcommandFullPath(t *testing.T) {
app := NewApp()
app := &App{}
buf := new(bytes.Buffer)
app.Writer = buf
app.Name = "command"
@ -953,7 +958,7 @@ func TestApp_Run_SubcommandFullPath(t *testing.T) {
}
func TestApp_Run_SubcommandHelpName(t *testing.T) {
app := NewApp()
app := &App{}
buf := new(bytes.Buffer)
app.Writer = buf
app.Name = "command"
@ -988,7 +993,7 @@ func TestApp_Run_SubcommandHelpName(t *testing.T) {
}
func TestApp_Run_CommandHelpName(t *testing.T) {
app := NewApp()
app := &App{}
buf := new(bytes.Buffer)
app.Writer = buf
app.Name = "command"
@ -1023,7 +1028,7 @@ func TestApp_Run_CommandHelpName(t *testing.T) {
}
func TestApp_Run_CommandSubcommandHelpName(t *testing.T) {
app := NewApp()
app := &App{}
buf := new(bytes.Buffer)
app.Writer = buf
app.Name = "base"
@ -1065,13 +1070,14 @@ func TestApp_Run_Help(t *testing.T) {
t.Logf("==> checking with arguments %v", args)
app := NewApp()
app.Name = "boom"
app.Usage = "make an explosive entrance"
app.Writer = buf
app.Action = func(c *Context) error {
app := &App{
Name: "boom",
Usage: "make an explosive entrance",
Writer: buf,
Action: func(c *Context) error {
buf.WriteString("boom I say!")
return nil
},
}
err := app.Run(args)
@ -1096,14 +1102,15 @@ func TestApp_Run_Version(t *testing.T) {
t.Logf("==> checking with arguments %v", args)
app := NewApp()
app.Name = "boom"
app.Usage = "make an explosive entrance"
app.Version = "0.1.0"
app.Writer = buf
app.Action = func(c *Context) error {
app := &App{
Name: "boom",
Usage: "make an explosive entrance",
Version: "0.1.0",
Writer: buf,
Action: func(c *Context) error {
buf.WriteString("boom I say!")
return nil
},
}
err := app.Run(args)
@ -1121,10 +1128,12 @@ func TestApp_Run_Version(t *testing.T) {
}
func TestApp_Run_Categories(t *testing.T) {
app := NewApp()
app.Name = "categories"
app.HideHelp = true
app.Commands = []*Command{
buf := new(bytes.Buffer)
app := &App{
Name: "categories",
HideHelp: true,
Commands: []*Command{
{
Name: "command1",
Category: "1",
@ -1137,9 +1146,9 @@ func TestApp_Run_Categories(t *testing.T) {
Name: "command3",
Category: "2",
},
},
Writer: buf,
}
buf := new(bytes.Buffer)
app.Writer = buf
app.Run([]string{"categories"})
@ -1172,10 +1181,10 @@ func TestApp_Run_Categories(t *testing.T) {
}
func TestApp_VisibleCategories(t *testing.T) {
app := NewApp()
app.Name = "visible-categories"
app.HideHelp = true
app.Commands = []*Command{
app := &App{
Name: "visible-categories",
HideHelp: true,
Commands: []*Command{
{
Name: "command1",
Category: "1",
@ -1192,6 +1201,7 @@ func TestApp_VisibleCategories(t *testing.T) {
Category: "3",
HelpName: "foo command3",
},
},
}
expected := []CommandCategory{
@ -1212,10 +1222,10 @@ func TestApp_VisibleCategories(t *testing.T) {
app.Setup()
expect(t, expected, app.VisibleCategories())
app = NewApp()
app.Name = "visible-categories"
app.HideHelp = true
app.Commands = []*Command{
app = &App{
Name: "visible-categories",
HideHelp: true,
Commands: []*Command{
{
Name: "command1",
Category: "1",
@ -1233,6 +1243,7 @@ func TestApp_VisibleCategories(t *testing.T) {
Category: "3",
HelpName: "foo command3",
},
},
}
expected = []CommandCategory{
@ -1247,10 +1258,10 @@ func TestApp_VisibleCategories(t *testing.T) {
app.Setup()
expect(t, expected, app.VisibleCategories())
app = NewApp()
app.Name = "visible-categories"
app.HideHelp = true
app.Commands = []*Command{
app = &App{
Name: "visible-categories",
HideHelp: true,
Commands: []*Command{
{
Name: "command1",
Category: "1",
@ -1269,6 +1280,7 @@ func TestApp_VisibleCategories(t *testing.T) {
HelpName: "foo command3",
Hidden: true,
},
},
}
app.Setup()
@ -1276,10 +1288,11 @@ func TestApp_VisibleCategories(t *testing.T) {
}
func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
app := NewApp()
app.Action = func(c *Context) error { return nil }
app.Before = func(c *Context) error { return fmt.Errorf("before error") }
app.After = func(c *Context) error { return fmt.Errorf("after error") }
app := &App{
Action: func(c *Context) error { return nil },
Before: func(c *Context) error { return fmt.Errorf("before error") },
After: func(c *Context) error { return fmt.Errorf("after error") },
}
err := app.Run([]string{"foo"})
if err == nil {
@ -1295,8 +1308,8 @@ func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
}
func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
app := NewApp()
app.Commands = []*Command{
app := &App{
Commands: []*Command{
{
Subcommands: []*Command{
{
@ -1307,6 +1320,7 @@ func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
Before: func(c *Context) error { return fmt.Errorf("before error") },
After: func(c *Context) error { return fmt.Errorf("after error") },
},
},
}
err := app.Run([]string{"foo", "bar"})
@ -1323,11 +1337,11 @@ func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
}
func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) {
app := NewApp()
app.Flags = []Flag{
app := &App{
Flags: []Flag{
&IntFlag{Name: "flag"},
}
app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
},
OnUsageError: func(c *Context, err error, isSubcommand bool) error {
if isSubcommand {
t.Errorf("Expect no subcommand")
}
@ -1335,11 +1349,12 @@ func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) {
t.Errorf("Expect an invalid value error, but got \"%v\"", err)
}
return errors.New("intercepted: " + err.Error())
}
app.Commands = []*Command{
},
Commands: []*Command{
{
Name: "bar",
},
},
}
err := app.Run([]string{"foo", "--flag=wrong"})
@ -1353,11 +1368,11 @@ func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) {
}
func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) {
app := NewApp()
app.Flags = []Flag{
app := &App{
Flags: []Flag{
&IntFlag{Name: "flag"},
}
app.OnUsageError = func(c *Context, err error, isSubcommand bool) error {
},
OnUsageError: func(c *Context, err error, isSubcommand bool) error {
if isSubcommand {
t.Errorf("Expect subcommand")
}
@ -1365,11 +1380,12 @@ func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) {
t.Errorf("Expect an invalid value error, but got \"%v\"", err)
}
return errors.New("intercepted: " + err.Error())
}
app.Commands = []*Command{
},
Commands: []*Command{
{
Name: "bar",
},
},
}
err := app.Run([]string{"foo", "--flag=wrong", "bar"})

View File

@ -18,8 +18,10 @@ install:
- set PATH=%GOPATH%\bin;C:\go\bin;%PATH%
- go version
- go env
- git clone . c:\gopath\src\gopkg.in\urfave\cli.v2
- go get github.com/urfave/gfmxr/...
- rmdir c:\gopath\src\gopkg.in\urfave\cli.v2 /s /q
- rmdir c:\gopath\pkg /s /q
- git clone . c:\gopath\src\gopkg.in\urfave\cli.v2
- go get -v -t ./...
- if not exist node_modules\.bin\markdown-toc npm install markdown-toc

View File

@ -292,6 +292,13 @@ def _context_parent(source):
return re.sub('\\.Parent\\(\\)', '.Lineage()[1]', source, flags=re.UNICODE)
@_migrator
def _app_init(source):
return re.sub(
'cli\\.NewApp\\(\\)', '(&cli.App{})', source, flags=re.UNICODE
)
def test_migrators():
import difflib
@ -432,6 +439,13 @@ _MIGRATOR_TESTS = (
\t\t\t\tName: "tootles", Aliases: []string{"toots", "t"},
\t\t\t},
\t\t}
"""),
("""
\t\tapp := cli.NewApp()
\t\tapp.HideHelp = true
""", """
\t\tapp := (&cli.App{})
\t\tapp.HideHelp = true
""")
)

11
cli.go
View File

@ -2,16 +2,17 @@
// Go applications. cli is designed to be easy to understand and write, the most simple
// cli application can be written as follows:
// func main() {
// cli.NewApp().Run(os.Args)
// (&cli.App{}).Run(os.Args)
// }
//
// Of course this application does not do much, so let's make this an actual application:
// func main() {
// app := cli.NewApp()
// app.Name = "greet"
// app.Usage = "say a greeting"
// app.Action = func(c *cli.Context) error {
// app := &cli.App{
// Name: "greet",
// Usage: "say a greeting",
// Action: func(c *cli.Context) error {
// println("Greetings")
// },
// }
//
// app.Run(os.Args)

View File

@ -164,10 +164,11 @@ func (c *Command) HasName(name string) bool {
}
func (c *Command) startApp(ctx *Context) error {
app := NewApp()
app.Metadata = ctx.App.Metadata
// set the name and usage
app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
app := &App{
Metadata: ctx.App.Metadata,
Name: fmt.Sprintf("%s %s", ctx.App.Name, c.Name),
}
if c.HelpName == "" {
app.HelpName = c.HelpName
} else {

View File

@ -22,8 +22,7 @@ func TestCommandFlagParsing(t *testing.T) {
}
for _, c := range cases {
app := NewApp()
app.Writer = ioutil.Discard
app := &App{Writer: ioutil.Discard}
set := flag.NewFlagSet("test", 0)
set.Parse(c.testArgs)
@ -47,8 +46,8 @@ func TestCommandFlagParsing(t *testing.T) {
}
func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
app := NewApp()
app.Commands = []*Command{
app := &App{
Commands: []*Command{
{
Name: "bar",
Before: func(c *Context) error {
@ -58,6 +57,7 @@ func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
return fmt.Errorf("after error")
},
},
},
}
err := app.Run([]string{"foo", "bar"})
@ -74,8 +74,8 @@ func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
}
func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) {
app := NewApp()
app.Commands = []*Command{
app := &App{
Commands: []*Command{
{
Name: "bar",
Flags: []Flag{
@ -88,6 +88,7 @@ func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) {
return errors.New("intercepted: " + err.Error())
},
},
},
}
err := app.Run([]string{"foo", "bar", "--flag=wrong"})

View File

@ -9,8 +9,7 @@ import (
func Test_ShowAppHelp_NoAuthor(t *testing.T) {
output := new(bytes.Buffer)
app := NewApp()
app.Writer = output
app := &App{Writer: output}
c := NewContext(app, nil, nil)
@ -23,8 +22,7 @@ func Test_ShowAppHelp_NoAuthor(t *testing.T) {
func Test_ShowAppHelp_NoVersion(t *testing.T) {
output := new(bytes.Buffer)
app := NewApp()
app.Writer = output
app := &App{Writer: output}
app.Version = ""
@ -39,8 +37,7 @@ func Test_ShowAppHelp_NoVersion(t *testing.T) {
func Test_ShowAppHelp_HideVersion(t *testing.T) {
output := new(bytes.Buffer)
app := NewApp()
app.Writer = output
app := &App{Writer: output}
app.HideVersion = true
@ -116,7 +113,7 @@ func Test_Version_Custom_Flags(t *testing.T) {
}
func Test_helpCommand_Action_ErrorIfNoTopic(t *testing.T) {
app := NewApp()
app := &App{}
set := flag.NewFlagSet("test", 0)
set.Parse([]string{"foo"})
@ -144,7 +141,7 @@ func Test_helpCommand_Action_ErrorIfNoTopic(t *testing.T) {
}
func Test_helpCommand_InHelpOutput(t *testing.T) {
app := NewApp()
app := &App{}
output := &bytes.Buffer{}
app.Writer = output
app.Run([]string{"test", "--help"})
@ -161,7 +158,7 @@ func Test_helpCommand_InHelpOutput(t *testing.T) {
}
func Test_helpSubcommand_Action_ErrorIfNoTopic(t *testing.T) {
app := NewApp()
app := &App{}
set := flag.NewFlagSet("test", 0)
set.Parse([]string{"foo"})