From df685fbacce5932609474568d4ae352b9e996355 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Wed, 22 Jun 2016 12:47:57 -0400 Subject: [PATCH] Remove `NewApp` initializer and move defaulting to `App.Setup` --- README.md | 748 ++++++++++++++++++------------------ altsrc/yaml_command_test.go | 18 +- app.go | 51 ++- app_test.go | 670 ++++++++++++++++---------------- cli-v1-to-v2 | 12 + cli.go | 15 +- command.go | 9 +- command_test.go | 47 +-- help_test.go | 13 +- 9 files changed, 815 insertions(+), 768 deletions(-) diff --git a/README.md b/README.md index 52a050a..812268d 100644 --- a/README.md +++ b/README.md @@ -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 { - fmt.Println("boom! I say!") - return nil + 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 { - fmt.Println("Hello friend!") - return nil + 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 { - fmt.Printf("Hello %q", c.Args().Get(0)) - return nil + app := &cli.App{ + Action: func(c *cli.Context) error { + fmt.Printf("Hello %q", c.Args().Get(0)) + return nil + }, } app.Run(os.Args) @@ -297,27 +299,26 @@ import ( ) func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag { - &cli.StringFlag{ - Name: "lang", - Value: "english", - Usage: "language for the greeting", + app := &cli.App{ + Flags: []cli.Flag { + &cli.StringFlag{ + Name: "lang", + Value: "english", + Usage: "language for the greeting", + }, + }, + Action: func(c *cli.Context) error { + name := "Nefertiti" + if c.NArg() > 0 { + name = c.Args().Get(0) + } + if c.String("lang") == "spanish" { + fmt.Println("Hola", name) + } else { + fmt.Println("Hello", name) + } + return nil }, - } - - app.Action = func(c *cli.Context) error { - name := "Nefertiti" - if c.NArg() > 0 { - name = c.Args().Get(0) - } - if c.String("lang") == "spanish" { - fmt.Println("Hola", name) - } else { - fmt.Println("Hello", name) - } - return nil } app.Run(os.Args) @@ -343,28 +344,27 @@ import ( func main() { var language string - app := cli.NewApp() - - app.Flags = []cli.Flag { - &cli.StringFlag{ - Name: "lang", - Value: "english", - Usage: "language for the greeting", - Destination: &language, + app := &cli.App{ + Flags: []cli.Flag { + &cli.StringFlag{ + Name: "lang", + Value: "english", + Usage: "language for the greeting", + Destination: &language, + }, + }, + Action: func(c *cli.Context) error { + name := "someone" + if c.NArg() > 0 { + name = c.Args().Get(0) + } + if language == "spanish" { + fmt.Println("Hola", name) + } else { + fmt.Println("Hello", name) + } + return nil }, - } - - app.Action = func(c *cli.Context) error { - name := "someone" - if c.NArg() > 0 { - name = c.Args().Get(0) - } - if language == "spanish" { - fmt.Println("Hola", name) - } else { - fmt.Println("Hello", name) - } - return nil } app.Run(os.Args) @@ -394,13 +394,13 @@ import ( ) func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag{ - &cli.StringFlag{ - Name: "config", - Aliases: []string{"c"}, - Usage: "Load configuration from `FILE`", + app := &cli.App{ + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "config", + Aliases: []string{"c"}, + Usage: "Load configuration from `FILE`", + }, }, } @@ -436,14 +436,14 @@ import ( ) func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag { - &cli.StringFlag{ - Name: "lang", - Aliases: []string{"l"}, - Value: "english", - Usage: "language for the greeting", + app := &cli.App{ + Flags: []cli.Flag { + &cli.StringFlag{ + Name: "lang", + Aliases: []string{"l"}, + Value: "english", + Usage: "language for the greeting", + }, }, } @@ -473,15 +473,15 @@ import ( ) func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag { - &cli.StringFlag{ - Name: "lang", - Aliases: []string{"l"}, - Value: "english", - Usage: "language for the greeting", - EnvVars: []string{"APP_LANG"}, + app := &cli.App{ + Flags: []cli.Flag { + &cli.StringFlag{ + Name: "lang", + Aliases: []string{"l"}, + Value: "english", + Usage: "language for the greeting", + EnvVars: []string{"APP_LANG"}, + }, }, } @@ -506,15 +506,15 @@ import ( ) func main() { - app := cli.NewApp() - - app.Flags = []cli.Flag{ - &cli.StringFlag{ - Name: "lang", - Aliases: []string{"l"}, - Value: "english", - Usage: "language for the greeting", - EnvVars: []string{"LEGACY_COMPAT_LANG", "APP_LANG", "LANG"}, + app := &cli.App{ + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "lang", + Aliases: []string{"l"}, + Value: "english", + Usage: "language for the greeting", + EnvVars: []string{"LEGACY_COMPAT_LANG", "APP_LANG", "LANG"}, + }, }, } @@ -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 { - fmt.Println("yaml ist rad") - return nil + 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,46 +606,46 @@ import ( ) func main() { - app := cli.NewApp() - - app.Commands = []*cli.Command{ - { - Name: "add", - Aliases: []string{"a"}, - Usage: "add a task to the list", - Action: func(c *cli.Context) error { - fmt.Println("added task: ", c.Args().First()) - return nil + app := &cli.App{ + Commands: []*cli.Command{ + { + Name: "add", + Aliases: []string{"a"}, + Usage: "add a task to the list", + Action: func(c *cli.Context) error { + fmt.Println("added task: ", c.Args().First()) + return nil + }, }, - }, - { - Name: "complete", - Aliases: []string{"c"}, - Usage: "complete a task on the list", - Action: func(c *cli.Context) error { - fmt.Println("completed task: ", c.Args().First()) - return nil + { + Name: "complete", + Aliases: []string{"c"}, + Usage: "complete a task on the list", + Action: func(c *cli.Context) error { + fmt.Println("completed task: ", c.Args().First()) + return nil + }, }, - }, - { - Name: "template", - Aliases: []string{"t"}, - Usage: "options for task templates", - Subcommands: []*cli.Command{ - { - Name: "add", - Usage: "add a new template", - Action: func(c *cli.Context) error { - fmt.Println("new task template: ", c.Args().First()) - return nil + { + Name: "template", + Aliases: []string{"t"}, + Usage: "options for task templates", + Subcommands: []*cli.Command{ + { + Name: "add", + Usage: "add a new template", + Action: func(c *cli.Context) error { + fmt.Println("new task template: ", c.Args().First()) + return nil + }, }, - }, - { - Name: "remove", - Usage: "remove an existing template", - Action: func(c *cli.Context) error { - fmt.Println("removed task template: ", c.Args().First()) - return nil + { + Name: "remove", + Usage: "remove an existing template", + Action: func(c *cli.Context) error { + fmt.Println("removed task template: ", c.Args().First()) + return nil + }, }, }, }, @@ -675,19 +674,19 @@ import ( ) func main() { - app := cli.NewApp() - - app.Commands = []*cli.Command{ - { - Name: "noop", - }, - { - Name: "add", - Category: "template", - }, - { - Name: "remove", - Category: "template", + app := &cli.App{ + Commands: []*cli.Command{ + { + Name: "noop", + }, + { + Name: "add", + Category: "template", + }, + { + Name: "remove", + Category: "template", + }, }, } @@ -723,19 +722,20 @@ import ( ) func main() { - app := cli.NewApp() - app.Flags = []cli.Flag{ - &cli.BoolFlag{ - Name: "ginger-crouton", - Value: true, - Usage: "is it in the soup?", + app := &cli.App{ + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "ginger-crouton", + Value: true, + Usage: "is it in the soup?", + }, + }, + Action: func(ctx *cli.Context) error { + if !ctx.Bool("ginger-crouton") { + return cli.Exit("it is not in the soup", 86) + } + return nil }, - } - app.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,25 +766,26 @@ import ( func main() { tasks := []string{"cook", "clean", "laundry", "eat", "sleep", "code"} - app := cli.NewApp() - app.EnableBashCompletion = true - app.Commands = []*cli.Command{ - { - Name: "complete", - Aliases: []string{"c"}, - Usage: "complete a task on the list", - Action: func(c *cli.Context) error { - fmt.Println("completed task: ", c.Args().First()) - return nil - }, - BashComplete: func(c *cli.Context) { - // This will complete if no args are passed - if c.NArg() > 0 { - return - } - for _, t := range tasks { - fmt.Println(t) - } + app := &cli.App{ + EnableBashCompletion: true, + Commands: []*cli.Command{ + { + Name: "complete", + Aliases: []string{"c"}, + Usage: "complete a task on the list", + Action: func(c *cli.Context) error { + fmt.Println("completed task: ", c.Args().First()) + return nil + }, + BashComplete: func(c *cli.Context) { + // This will complete if no args are passed + if c.NArg() > 0 { + return + } + for _, t := range tasks { + fmt.Println(t) + } + }, }, }, } @@ -840,11 +841,12 @@ func main() { Hidden: true, } - app := cli.NewApp() - app.EnableBashCompletion = true - app.Commands = []*cli.Command{ - { - Name: "wat", + 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,183 +1095,189 @@ 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{ - &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{ - &cli.Command{ - Name: "doo", - Aliases: []string{"do"}, - Category: "motion", - Usage: "do the doo", - UsageText: "doo - does the dooing", - Description: "no really, there is a lot of dooing to be done", - ArgsUsage: "[arrgh]", - Flags: []cli.Flag{ - &cli.BoolFlag{Name: "forever", Aliases: []string{"forevvarr"}}, + 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", }, - Subcommands: []*cli.Command{ - &cli.Command{ - Name: "wop", - Action: wopAction, + }, + 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"}, + Category: "motion", + Usage: "do the doo", + UsageText: "doo - does the dooing", + Description: "no really, there is a lot of dooing to be done", + ArgsUsage: "[arrgh]", + Flags: []cli.Flag{ + &cli.BoolFlag{Name: "forever", Aliases: []string{"forevvarr"}}, + }, + Subcommands: []*cli.Command{ + &cli.Command{ + Name: "wop", + Action: wopAction, + }, + }, + SkipFlagParsing: false, + HideHelp: false, + Hidden: false, + HelpName: "doo!", + BashComplete: func(c *cli.Context) { + fmt.Fprintf(c.App.Writer, "--better\n") + }, + Before: func(c *cli.Context) error { + fmt.Fprintf(c.App.Writer, "brace for impact\n") + return nil + }, + After: func(c *cli.Context) error { + fmt.Fprintf(c.App.Writer, "did we lose anyone?\n") + return nil + }, + Action: func(c *cli.Context) error { + c.Command.FullName() + c.Command.HasName("wop") + c.Command.Names() + c.Command.VisibleFlags() + fmt.Fprintf(c.App.Writer, "dodododododoodododddooooododododooo\n") + if c.Bool("forever") { + c.Command.Run(c) + } + return nil + }, + OnUsageError: func(c *cli.Context, err error, isSubcommand bool) error { + fmt.Fprintf(c.App.Writer, "for shame\n") + return err }, - }, - SkipFlagParsing: false, - HideHelp: false, - Hidden: false, - HelpName: "doo!", - BashComplete: func(c *cli.Context) { - fmt.Fprintf(c.App.Writer, "--better\n") - }, - Before: func(c *cli.Context) error { - fmt.Fprintf(c.App.Writer, "brace for impact\n") - return nil - }, - After: func(c *cli.Context) error { - fmt.Fprintf(c.App.Writer, "did we lose anyone?\n") - return nil - }, - Action: func(c *cli.Context) error { - c.Command.FullName() - c.Command.HasName("wop") - c.Command.Names() - c.Command.VisibleFlags() - fmt.Fprintf(c.App.Writer, "dodododododoodododddooooododododooo\n") - if c.Bool("forever") { - c.Command.Run(c) - } - return nil - }, - OnUsageError: func(c *cli.Context, err error, isSubcommand bool) error { - fmt.Fprintf(c.App.Writer, "for shame\n") - return err }, }, - } - app.Flags = []cli.Flag{ - &cli.BoolFlag{Name: "fancy"}, - &cli.BoolFlag{Value: true, Name: "fancier"}, - &cli.DurationFlag{Name: "howlong", Aliases: []string{"H"}, Value: time.Second * 3}, - &cli.Float64Flag{Name: "howmuch"}, - &cli.GenericFlag{Name: "wat", Value: &genericType{}}, - &cli.Int64Flag{Name: "longdistance"}, - &cli.Int64SliceFlag{Name: "intervals"}, - &cli.IntFlag{Name: "distance"}, - &cli.IntSliceFlag{Name: "times"}, - &cli.StringFlag{Name: "dance-move", Aliases: []string{"d"}}, - &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) { - fmt.Fprintf(c.App.Writer, "lipstick\nkiss\nme\nlipstick\nringo\n") - } - app.Before = func(c *cli.Context) error { - fmt.Fprintf(c.App.Writer, "HEEEERE GOES\n") - return nil - } - app.After = func(c *cli.Context) error { - fmt.Fprintf(c.App.Writer, "Phew!\n") - return nil - } - app.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 { - if isSubcommand { - return err - } + Flags: []cli.Flag{ + &cli.BoolFlag{Name: "fancy"}, + &cli.BoolFlag{Value: true, Name: "fancier"}, + &cli.DurationFlag{Name: "howlong", Aliases: []string{"H"}, Value: time.Second * 3}, + &cli.Float64Flag{Name: "howmuch"}, + &cli.GenericFlag{Name: "wat", Value: &genericType{}}, + &cli.Int64Flag{Name: "longdistance"}, + &cli.Int64SliceFlag{Name: "intervals"}, + &cli.IntFlag{Name: "distance"}, + &cli.IntSliceFlag{Name: "times"}, + &cli.StringFlag{Name: "dance-move", Aliases: []string{"d"}}, + &cli.StringSliceFlag{Name: "names", Aliases: []string{"N"}}, + &cli.UintFlag{Name: "age"}, + &cli.Uint64Flag{Name: "bigage"}, + }, + EnableBashCompletion: true, + HideHelp: false, + HideVersion: false, + BashComplete: func(c *cli.Context) { + fmt.Fprintf(c.App.Writer, "lipstick\nkiss\nme\nlipstick\nringo\n") + }, + Before: func(c *cli.Context) error { + fmt.Fprintf(c.App.Writer, "HEEEERE GOES\n") + return nil + }, + After: func(c *cli.Context) error { + fmt.Fprintf(c.App.Writer, "Phew!\n") + return nil + }, + CommandNotFound: func(c *cli.Context, command string) { + fmt.Fprintf(c.App.Writer, "Thar be no %q here.\n", command) + }, + 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 { - cli.DefaultAppComplete(c) - cli.HandleExitCoder(errors.New("not an exit coder, though")) - cli.ShowAppHelp(c) - cli.ShowCommandCompletions(c, "nope") - cli.ShowCommandHelp(c, "also-nope") - cli.ShowCompletions(c) - cli.ShowSubcommandHelp(c) - cli.ShowVersion(c) - - categories := c.App.Categories - categories.AddCommand("sounds", &cli.Command{ - Name: "bloop", - }) - - for _, category := range c.App.Categories.Categories() { - fmt.Fprintf(c.App.Writer, "%s\n", category.Name) - fmt.Fprintf(c.App.Writer, "%#v\n", category.VisibleCommands()) - fmt.Fprintf(c.App.Writer, "%#v\n", category.VisibleCommands()) - } - - fmt.Printf("%#v\n", c.App.Command("doo")) - if c.Bool("infinite") { - c.App.Run([]string{"app", "doo", "wop"}) - } - - if c.Bool("forevar") { - c.App.RunAsSubcommand(c) - } - c.App.Setup() - fmt.Printf("%#v\n", c.App.VisibleCategories()) - fmt.Printf("%#v\n", c.App.VisibleCommands()) - fmt.Printf("%#v\n", c.App.VisibleFlags()) - - fmt.Printf("%#v\n", c.Args().First()) - if c.Args().Len() > 0 { - fmt.Printf("%#v\n", c.Args().Get(1)) - } - fmt.Printf("%#v\n", c.Args().Present()) - fmt.Printf("%#v\n", c.Args().Tail()) - - set := flag.NewFlagSet("contrive", 0) - nc := cli.NewContext(c.App, set, c) - - fmt.Printf("%#v\n", nc.Args()) - fmt.Printf("%#v\n", nc.Bool("nope")) - fmt.Printf("%#v\n", !nc.Bool("nerp")) - fmt.Printf("%#v\n", nc.Duration("howlong")) - fmt.Printf("%#v\n", nc.Float64("hay")) - fmt.Printf("%#v\n", nc.Generic("bloop")) - fmt.Printf("%#v\n", nc.Int64("bonk")) - fmt.Printf("%#v\n", nc.Int64Slice("burnks")) - fmt.Printf("%#v\n", nc.Int("bips")) - fmt.Printf("%#v\n", nc.IntSlice("blups")) - fmt.Printf("%#v\n", nc.String("snurt")) - fmt.Printf("%#v\n", nc.StringSlice("snurkles")) - fmt.Printf("%#v\n", nc.Uint("flub")) - fmt.Printf("%#v\n", nc.Uint64("florb")) - - fmt.Printf("%#v\n", nc.FlagNames()) - fmt.Printf("%#v\n", nc.IsSet("wat")) - fmt.Printf("%#v\n", nc.Set("wat", "nope")) - fmt.Printf("%#v\n", nc.NArg()) - fmt.Printf("%#v\n", nc.NumFlags()) - fmt.Printf("%#v\n", nc.Lineage()[1]) - - nc.Set("wat", "also-nope") - - ec := cli.Exit("ohwell", 86) - fmt.Fprintf(c.App.Writer, "%d", ec.ExitCode()) - fmt.Printf("made it!\n") - return ec + fmt.Fprintf(c.App.Writer, "WRONG: %#v\n", err) + return nil + }, + Action: func(c *cli.Context) error { + cli.DefaultAppComplete(c) + cli.HandleExitCoder(errors.New("not an exit coder, though")) + cli.ShowAppHelp(c) + cli.ShowCommandCompletions(c, "nope") + cli.ShowCommandHelp(c, "also-nope") + cli.ShowCompletions(c) + cli.ShowSubcommandHelp(c) + cli.ShowVersion(c) + + categories := c.App.Categories + categories.AddCommand("sounds", &cli.Command{ + Name: "bloop", + }) + + for _, category := range c.App.Categories.Categories() { + fmt.Fprintf(c.App.Writer, "%s\n", category.Name) + fmt.Fprintf(c.App.Writer, "%#v\n", category.VisibleCommands()) + fmt.Fprintf(c.App.Writer, "%#v\n", category.VisibleCommands()) + } + + fmt.Printf("%#v\n", c.App.Command("doo")) + if c.Bool("infinite") { + c.App.Run([]string{"app", "doo", "wop"}) + } + + if c.Bool("forevar") { + c.App.RunAsSubcommand(c) + } + c.App.Setup() + fmt.Printf("%#v\n", c.App.VisibleCategories()) + fmt.Printf("%#v\n", c.App.VisibleCommands()) + fmt.Printf("%#v\n", c.App.VisibleFlags()) + + fmt.Printf("%#v\n", c.Args().First()) + if c.Args().Len() > 0 { + fmt.Printf("%#v\n", c.Args().Get(1)) + } + fmt.Printf("%#v\n", c.Args().Present()) + fmt.Printf("%#v\n", c.Args().Tail()) + + set := flag.NewFlagSet("contrive", 0) + nc := cli.NewContext(c.App, set, c) + + fmt.Printf("%#v\n", nc.Args()) + fmt.Printf("%#v\n", nc.Bool("nope")) + fmt.Printf("%#v\n", !nc.Bool("nerp")) + fmt.Printf("%#v\n", nc.Duration("howlong")) + fmt.Printf("%#v\n", nc.Float64("hay")) + fmt.Printf("%#v\n", nc.Generic("bloop")) + fmt.Printf("%#v\n", nc.Int64("bonk")) + fmt.Printf("%#v\n", nc.Int64Slice("burnks")) + fmt.Printf("%#v\n", nc.Int("bips")) + fmt.Printf("%#v\n", nc.IntSlice("blups")) + fmt.Printf("%#v\n", nc.String("snurt")) + fmt.Printf("%#v\n", nc.StringSlice("snurkles")) + fmt.Printf("%#v\n", nc.Uint("flub")) + fmt.Printf("%#v\n", nc.Uint64("florb")) + + fmt.Printf("%#v\n", nc.FlagNames()) + fmt.Printf("%#v\n", nc.IsSet("wat")) + fmt.Printf("%#v\n", nc.Set("wat", "nope")) + fmt.Printf("%#v\n", nc.NArg()) + fmt.Printf("%#v\n", nc.NumFlags()) + fmt.Printf("%#v\n", nc.Lineage()[1]) + + nc.Set("wat", "also-nope") + + ec := cli.Exit("ohwell", 86) + 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) } diff --git a/altsrc/yaml_command_test.go b/altsrc/yaml_command_test.go index d5082af..2bcea40 100644 --- a/altsrc/yaml_command_test.go +++ b/altsrc/yaml_command_test.go @@ -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) diff --git a/app.go b/app.go index b16f991..d2825d5 100644 --- a/app.go +++ b/app.go @@ -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 == "" { diff --git a/app_test.go b/app_test.go index 99bd6a3..0efb2e6 100644 --- a/app_test.go +++ b/app_test.go @@ -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{ - &StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, - } - app.Action = func(c *Context) error { - fmt.Printf("Hello %v\n", c.String("name")) - return nil + app := &App{ + Name: "greet", + Flags: []Flag{ + &StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, + }, + 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,30 +42,31 @@ 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{ - { - Name: "hello", - Aliases: []string{"hi"}, - Usage: "use it to see a description", - Description: "This is how we describe hello the function", - Subcommands: []*Command{ - { - Name: "english", - Aliases: []string{"en"}, - Usage: "sends a greeting in english", - Description: "greets someone in english", - Flags: []Flag{ - &StringFlag{ - Name: "name", - Value: "Bob", - Usage: "Name of the person to greet", + app := &App{ + Name: "say", + Commands: []*Command{ + { + Name: "hello", + Aliases: []string{"hi"}, + Usage: "use it to see a description", + Description: "This is how we describe hello the function", + Subcommands: []*Command{ + { + Name: "english", + Aliases: []string{"en"}, + Usage: "sends a greeting in english", + Description: "greets someone in english", + Flags: []Flag{ + &StringFlag{ + Name: "name", + Value: "Bob", + Usage: "Name of the person to greet", + }, + }, + Action: func(c *Context) error { + fmt.Println("Hello,", c.String("name")) + return nil }, - }, - Action: func(c *Context) error { - fmt.Println("Hello,", c.String("name")) - return nil }, }, }, @@ -79,20 +82,21 @@ func ExampleApp_Run_help() { // set args for examples sake os.Args = []string{"greet", "h", "describeit"} - app := NewApp() - app.Name = "greet" - app.Flags = []Flag{ - &StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, - } - app.Commands = []*Command{ - { - Name: "describeit", - Aliases: []string{"d"}, - Usage: "use it to see a description", - Description: "This is how we describe describeit the function", - Action: func(c *Context) error { - fmt.Printf("i like to describe things") - return nil + app := &App{ + Name: "greet", + Flags: []Flag{ + &StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, + }, + Commands: []*Command{ + { + Name: "describeit", + Aliases: []string{"d"}, + Usage: "use it to see a description", + Description: "This is how we describe describeit the function", + Action: func(c *Context) error { + fmt.Printf("i like to describe things") + return nil + }, }, }, } @@ -112,26 +116,27 @@ 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{ - { - Name: "describeit", - Aliases: []string{"d"}, - Usage: "use it to see a description", - Description: "This is how we describe describeit the function", - Action: func(c *Context) error { - fmt.Printf("i like to describe things") - return nil - }, - }, { - Name: "next", - Usage: "next example", - Description: "more stuff to see when generating bash completion", - Action: func(c *Context) error { - fmt.Printf("the next example") - return nil + app := &App{ + Name: "greet", + EnableBashCompletion: true, + Commands: []*Command{ + { + Name: "describeit", + Aliases: []string{"d"}, + Usage: "use it to see a description", + Description: "This is how we describe describeit the function", + Action: func(c *Context) error { + fmt.Printf("i like to describe things") + return nil + }, + }, { + Name: "next", + Usage: "next example", + Description: "more stuff to see when generating bash completion", + Action: func(c *Context) error { + fmt.Printf("the next example") + return nil + }, }, }, } @@ -148,10 +153,11 @@ func ExampleApp_Run_bashComplete() { func TestApp_Run(t *testing.T) { s := "" - app := NewApp() - app.Action = func(c *Context) error { - s = s + c.Args().First() - return nil + 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,22 +196,23 @@ func TestApp_Command(t *testing.T) { func TestApp_RunAsSubcommandParseFlags(t *testing.T) { var context *Context - a := NewApp() - a.Commands = []*Command{ - { - Name: "foo", - Action: func(c *Context) error { - context = c - return nil - }, - Flags: []Flag{ - &StringFlag{ - Name: "lang", - Value: "english", - Usage: "language for the greeting", + a := &App{ + Commands: []*Command{ + { + Name: "foo", + Action: func(c *Context) error { + context = c + return nil + }, + Flags: []Flag{ + &StringFlag{ + Name: "lang", + Value: "english", + Usage: "language for the greeting", + }, }, + Before: func(_ *Context) error { return nil }, }, - 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,18 +287,19 @@ func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) { } func TestApp_VisibleCommands(t *testing.T) { - app := NewApp() - app.Commands = []*Command{ - { - Name: "frob", - HelpName: "foo frob", - Action: func(_ *Context) error { return nil }, - }, - { - Name: "frib", - HelpName: "foo frib", - Hidden: true, - Action: func(_ *Context) error { return nil }, + app := &App{ + Commands: []*Command{ + { + Name: "frob", + HelpName: "foo frob", + Action: func(_ *Context) error { return nil }, + }, + { + Name: "frib", + HelpName: "foo frib", + Hidden: true, + Action: func(_ *Context) error { return nil }, + }, }, } @@ -332,13 +340,14 @@ func TestApp_VisibleCommands(t *testing.T) { func TestApp_Float64Flag(t *testing.T) { var meters float64 - app := NewApp() - app.Flags = []Flag{ - &Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"}, - } - app.Action = func(c *Context) error { - meters = c.Float64("height") - return nil + app := &App{ + Flags: []Flag{ + &Float64Flag{Name: "height", Value: 1.5, Usage: "Set the height, in meters"}, + }, + 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,32 +497,30 @@ func TestApp_BeforeFunc(t *testing.T) { beforeError := fmt.Errorf("fail") var err error - app := NewApp() - - app.Before = func(c *Context) error { - counts.Total++ - counts.Before = counts.Total - s := c.String("opt") - if s == "fail" { - return beforeError - } - - return nil - } + app := &App{ + Before: func(c *Context) error { + counts.Total++ + counts.Before = counts.Total + s := c.String("opt") + if s == "fail" { + return beforeError + } - app.Commands = []*Command{ - { - Name: "sub", - Action: func(c *Context) error { - counts.Total++ - counts.SubCommand = counts.Total - return nil + return nil + }, + Commands: []*Command{ + { + Name: "sub", + Action: func(c *Context) error { + counts.Total++ + counts.SubCommand = counts.Total + return nil + }, }, }, - } - - app.Flags = []Flag{ - &StringFlag{Name: "opt"}, + Flags: []Flag{ + &StringFlag{Name: "opt"}, + }, } // run with the Before() func succeeding @@ -578,32 +587,30 @@ func TestApp_AfterFunc(t *testing.T) { afterError := fmt.Errorf("fail") var err error - app := NewApp() - - app.After = func(c *Context) error { - counts.Total++ - counts.After = counts.Total - s := c.String("opt") - if s == "fail" { - return afterError - } - - return nil - } + app := &App{ + After: func(c *Context) error { + counts.Total++ + counts.After = counts.Total + s := c.String("opt") + if s == "fail" { + return afterError + } - app.Commands = []*Command{ - { - Name: "sub", - Action: func(c *Context) error { - counts.Total++ - counts.SubCommand = counts.Total - return nil + return nil + }, + Commands: []*Command{ + { + Name: "sub", + Action: func(c *Context) error { + counts.Total++ + counts.SubCommand = counts.Total + return nil + }, }, }, - } - - app.Flags = []Flag{ - &StringFlag{Name: "opt"}, + 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,20 +705,19 @@ func TestApp_VersionPrinter(t *testing.T) { func TestApp_CommandNotFound(t *testing.T) { counts := &opCounts{} - app := NewApp() - - app.CommandNotFound = func(c *Context, command string) { - counts.Total++ - counts.CommandNotFound = counts.Total - } - - app.Commands = []*Command{ - { - Name: "bar", - Action: func(c *Context) error { - counts.Total++ - counts.SubCommand = counts.Total - return nil + app := &App{ + CommandNotFound: func(c *Context, command string) { + counts.Total++ + counts.CommandNotFound = counts.Total + }, + Commands: []*Command{ + { + Name: "bar", + Action: func(c *Context) error { + counts.Total++ + counts.SubCommand = counts.Total + return nil + }, }, }, } @@ -729,17 +734,17 @@ func TestApp_OrderOfOperations(t *testing.T) { resetCounts := func() { counts = &opCounts{} } - app := NewApp() - app.EnableBashCompletion = true - app.BashComplete = func(c *Context) { - counts.Total++ - counts.BashComplete = counts.Total - } - - app.OnUsageError = func(c *Context, err error, isSubcommand bool) error { - counts.Total++ - counts.OnUsageError = counts.Total - return errors.New("hay OnUsageError") + app := &App{ + EnableBashCompletion: true, + BashComplete: func(c *Context) { + counts.Total++ + counts.BashComplete = counts.Total + }, + 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 { - buf.WriteString("boom I say!") - return nil + 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 { - buf.WriteString("boom I say!") - return nil + 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,24 +1128,26 @@ func TestApp_Run_Version(t *testing.T) { } func TestApp_Run_Categories(t *testing.T) { - app := NewApp() - app.Name = "categories" - app.Commands = []*Command{ - { - Name: "command1", - Category: "1", - }, - { - Name: "command2", - Category: "1", - }, - { - Name: "command3", - Category: "2", + buf := new(bytes.Buffer) + + app := &App{ + Name: "categories", + Commands: []*Command{ + { + Name: "command1", + Category: "1", + }, + { + Name: "command2", + Category: "1", + }, + { + Name: "command3", + Category: "2", + }, }, + Writer: buf, } - buf := new(bytes.Buffer) - app.Writer = buf app.Run([]string{"categories"}) @@ -1171,24 +1180,25 @@ func TestApp_Run_Categories(t *testing.T) { } func TestApp_VisibleCategories(t *testing.T) { - app := NewApp() - app.Name = "visible-categories" - app.Commands = []*Command{ - { - Name: "command1", - Category: "1", - HelpName: "foo command1", - Hidden: true, - }, - { - Name: "command2", - Category: "2", - HelpName: "foo command2", - }, - { - Name: "command3", - Category: "3", - HelpName: "foo command3", + app := &App{ + Name: "visible-categories", + Commands: []*Command{ + { + Name: "command1", + Category: "1", + HelpName: "foo command1", + Hidden: true, + }, + { + Name: "command2", + Category: "2", + HelpName: "foo command2", + }, + { + Name: "command3", + Category: "3", + HelpName: "foo command3", + }, }, } @@ -1210,25 +1220,26 @@ func TestApp_VisibleCategories(t *testing.T) { app.Setup() expect(t, expected, app.VisibleCategories()) - app = NewApp() - app.Name = "visible-categories" - app.Commands = []*Command{ - { - Name: "command1", - Category: "1", - HelpName: "foo command1", - Hidden: true, - }, - { - Name: "command2", - Category: "2", - HelpName: "foo command2", - Hidden: true, - }, - { - Name: "command3", - Category: "3", - HelpName: "foo command3", + app = &App{ + Name: "visible-categories", + Commands: []*Command{ + { + Name: "command1", + Category: "1", + HelpName: "foo command1", + Hidden: true, + }, + { + Name: "command2", + Category: "2", + HelpName: "foo command2", + Hidden: true, + }, + { + Name: "command3", + Category: "3", + HelpName: "foo command3", + }, }, } @@ -1244,26 +1255,27 @@ func TestApp_VisibleCategories(t *testing.T) { app.Setup() expect(t, expected, app.VisibleCategories()) - app = NewApp() - app.Name = "visible-categories" - app.Commands = []*Command{ - { - Name: "command1", - Category: "1", - HelpName: "foo command1", - Hidden: true, - }, - { - Name: "command2", - Category: "2", - HelpName: "foo command2", - Hidden: true, - }, - { - Name: "command3", - Category: "3", - HelpName: "foo command3", - Hidden: true, + app = &App{ + Name: "visible-categories", + Commands: []*Command{ + { + Name: "command1", + Category: "1", + HelpName: "foo command1", + Hidden: true, + }, + { + Name: "command2", + Category: "2", + HelpName: "foo command2", + Hidden: true, + }, + { + Name: "command3", + Category: "3", + HelpName: "foo command3", + Hidden: true, + }, }, } @@ -1272,10 +1284,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 { @@ -1291,17 +1304,18 @@ func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) { } func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) { - app := NewApp() - app.Commands = []*Command{ - { - Subcommands: []*Command{ - { - Name: "sub", + app := &App{ + Commands: []*Command{ + { + Subcommands: []*Command{ + { + Name: "sub", + }, }, + Name: "bar", + Before: func(c *Context) error { return fmt.Errorf("before error") }, + After: func(c *Context) error { return fmt.Errorf("after error") }, }, - Name: "bar", - Before: func(c *Context) error { return fmt.Errorf("before error") }, - After: func(c *Context) error { return fmt.Errorf("after error") }, }, } @@ -1319,22 +1333,23 @@ func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) { } func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) { - app := NewApp() - app.Flags = []Flag{ - &IntFlag{Name: "flag"}, - } - app.OnUsageError = func(c *Context, err error, isSubcommand bool) error { - if isSubcommand { - t.Errorf("Expect no subcommand") - } - if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { - t.Errorf("Expect an invalid value error, but got \"%v\"", err) - } - return errors.New("intercepted: " + err.Error()) - } - app.Commands = []*Command{ - { - Name: "bar", + app := &App{ + Flags: []Flag{ + &IntFlag{Name: "flag"}, + }, + OnUsageError: func(c *Context, err error, isSubcommand bool) error { + if isSubcommand { + t.Errorf("Expect no subcommand") + } + if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { + t.Errorf("Expect an invalid value error, but got \"%v\"", err) + } + return errors.New("intercepted: " + err.Error()) + }, + Commands: []*Command{ + { + Name: "bar", + }, }, } @@ -1349,22 +1364,23 @@ func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) { } func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) { - app := NewApp() - app.Flags = []Flag{ - &IntFlag{Name: "flag"}, - } - app.OnUsageError = func(c *Context, err error, isSubcommand bool) error { - if isSubcommand { - t.Errorf("Expect subcommand") - } - if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { - t.Errorf("Expect an invalid value error, but got \"%v\"", err) - } - return errors.New("intercepted: " + err.Error()) - } - app.Commands = []*Command{ - { - Name: "bar", + app := &App{ + Flags: []Flag{ + &IntFlag{Name: "flag"}, + }, + OnUsageError: func(c *Context, err error, isSubcommand bool) error { + if isSubcommand { + t.Errorf("Expect subcommand") + } + if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { + t.Errorf("Expect an invalid value error, but got \"%v\"", err) + } + return errors.New("intercepted: " + err.Error()) + }, + Commands: []*Command{ + { + Name: "bar", + }, }, } diff --git a/cli-v1-to-v2 b/cli-v1-to-v2 index 904d50e..48085e9 100755 --- a/cli-v1-to-v2 +++ b/cli-v1-to-v2 @@ -292,6 +292,11 @@ 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 +437,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 """) ) diff --git a/cli.go b/cli.go index f0440c5..b2b612f 100644 --- a/cli.go +++ b/cli.go @@ -2,17 +2,18 @@ // 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 { -// println("Greetings") -// } +// app := &cli.App{ +// Name: "greet", +// Usage: "say a greeting", +// Action: func(c *cli.Context) error { +// println("Greetings") +// }, +// } // // app.Run(os.Args) // } diff --git a/command.go b/command.go index f05f1e2..121deca 100644 --- a/command.go +++ b/command.go @@ -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 { diff --git a/command_test.go b/command_test.go index 033149f..7c5bdfd 100644 --- a/command_test.go +++ b/command_test.go @@ -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,15 +46,16 @@ func TestCommandFlagParsing(t *testing.T) { } func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) { - app := NewApp() - app.Commands = []*Command{ - { - Name: "bar", - Before: func(c *Context) error { - return fmt.Errorf("before error") - }, - After: func(c *Context) error { - return fmt.Errorf("after error") + app := &App{ + Commands: []*Command{ + { + Name: "bar", + Before: func(c *Context) error { + return fmt.Errorf("before error") + }, + After: func(c *Context) error { + return fmt.Errorf("after error") + }, }, }, } @@ -74,18 +74,19 @@ func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) { } func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) { - app := NewApp() - app.Commands = []*Command{ - { - Name: "bar", - Flags: []Flag{ - &IntFlag{Name: "flag"}, - }, - OnUsageError: func(c *Context, err error, _ bool) error { - if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { - t.Errorf("Expect an invalid value error, but got \"%v\"", err) - } - return errors.New("intercepted: " + err.Error()) + app := &App{ + Commands: []*Command{ + { + Name: "bar", + Flags: []Flag{ + &IntFlag{Name: "flag"}, + }, + OnUsageError: func(c *Context, err error, _ bool) error { + if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { + t.Errorf("Expect an invalid value error, but got \"%v\"", err) + } + return errors.New("intercepted: " + err.Error()) + }, }, }, } diff --git a/help_test.go b/help_test.go index b81701c..b8aa132 100644 --- a/help_test.go +++ b/help_test.go @@ -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_helpSubcommand_Action_ErrorIfNoTopic(t *testing.T) { - app := NewApp() + app := &App{} set := flag.NewFlagSet("test", 0) set.Parse([]string{"foo"})