Merge pull request #358 from harshavardhana/pr_out_move_from_codegangsta_cli_to_minio_io_cli_fork

This commit is contained in:
Harshavardhana 2015-03-24 20:41:04 -07:00
commit a311a9c4b8
19 changed files with 560 additions and 167 deletions

10
Godeps/Godeps.json generated
View File

@ -5,11 +5,6 @@
"./..." "./..."
], ],
"Deps": [ "Deps": [
{
"ImportPath": "github.com/codegangsta/cli",
"Comment": "1.2.0-42-gfbda1ce",
"Rev": "fbda1ce02d5dabcee952040e5f4025753b6c9ce0"
},
{ {
"ImportPath": "github.com/gorilla/context", "ImportPath": "github.com/gorilla/context",
"Rev": "50c25fb3b2b3b3cc724e9b6ac75fb44b3bccd0da" "Rev": "50c25fb3b2b3b3cc724e9b6ac75fb44b3bccd0da"
@ -18,6 +13,11 @@
"ImportPath": "github.com/gorilla/mux", "ImportPath": "github.com/gorilla/mux",
"Rev": "e444e69cbd2e2e3e0749a2f3c717cec491552bbf" "Rev": "e444e69cbd2e2e3e0749a2f3c717cec491552bbf"
}, },
{
"ImportPath": "github.com/minio-io/cli",
"Comment": "1.2.0-96-gfcc23e2",
"Rev": "fcc23e23a705c0d95fce2a446c364ac31a1c73a5"
},
{ {
"ImportPath": "gopkg.in/check.v1", "ImportPath": "gopkg.in/check.v1",
"Rev": "64131543e7896d5bcc6bd5a76287eb75ea96c673" "Rev": "64131543e7896d5bcc6bd5a76287eb75ea96c673"

View File

@ -210,7 +210,7 @@ Subcommands can be defined for a more git-like command line app.
app.Commands = []cli.Command{ app.Commands = []cli.Command{
{ {
Name: "add", Name: "add",
ShortName: "a", Aliases: []string{"a"},
Usage: "add a task to the list", Usage: "add a task to the list",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
println("added task: ", c.Args().First()) println("added task: ", c.Args().First())
@ -218,7 +218,7 @@ app.Commands = []cli.Command{
}, },
{ {
Name: "complete", Name: "complete",
ShortName: "c", Aliases: []string{"c"},
Usage: "complete a task on the list", Usage: "complete a task on the list",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
println("completed task: ", c.Args().First()) println("completed task: ", c.Args().First())
@ -226,7 +226,7 @@ app.Commands = []cli.Command{
}, },
{ {
Name: "template", Name: "template",
ShortName: "r", Aliases: []string{"r"},
Usage: "options for task templates", Usage: "options for task templates",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
{ {
@ -263,7 +263,7 @@ app.EnableBashCompletion = true
app.Commands = []cli.Command{ app.Commands = []cli.Command{
{ {
Name: "complete", Name: "complete",
ShortName: "c", Aliases: []string{"c"},
Usage: "complete a task on the list", Usage: "complete a task on the list",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
println("completed task: ", c.Args().First()) println("completed task: ", c.Args().First())
@ -293,6 +293,6 @@ setting the `PROG` variable to the name of your program:
## 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 are 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, 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 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, I probably forgot to add you. Hit @codegangsta up over email and we will get it figured out.

View File

@ -2,8 +2,12 @@ package cli
import ( import (
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"os" "os"
"strings"
"text/tabwriter"
"text/template"
"time" "time"
) )
@ -31,16 +35,23 @@ type App struct {
// 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
// If a non-nil error is returned, no subcommands are run // If a non-nil error is returned, no subcommands are run
Before func(context *Context) error Before func(context *Context) error
// An action to execute after any subcommands are run, but after the subcommand has finished
// It is run even if Action() panics
After func(context *Context) error
// The action to execute when no subcommands are specified // The action to execute when no subcommands are specified
Action func(context *Context) Action func(context *Context)
// Execute this function if the proper command cannot be found // Execute this function if the proper command cannot be found
CommandNotFound func(context *Context, command string) CommandNotFound func(context *Context, command string)
// Compilation date // Compilation date
Compiled time.Time Compiled time.Time
// Author // List of all authors who contributed
Authors []Author
// Name of Author (Note: Use App.Authors, this is deprecated)
Author string Author string
// Author e-mail // Email of Author (Note: Use App.Authors, this is deprecated)
Email string Email string
// Writer writer to write output to
Writer io.Writer
} }
// Tries to find out when this binary was compiled. // Tries to find out when this binary was compiled.
@ -62,16 +73,43 @@ func NewApp() *App {
BashComplete: DefaultAppComplete, BashComplete: DefaultAppComplete,
Action: helpCommand.Action, Action: helpCommand.Action,
Compiled: compileTime(), Compiled: compileTime(),
Writer: os.Stdout,
} }
} }
// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination // Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination
func (a *App) Run(arguments []string) error { func (a *App) Run(arguments []string) (err error) {
if a.Author != "" || a.Email != "" {
a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
}
if HelpPrinter == nil {
defer func() {
HelpPrinter = nil
}()
HelpPrinter = func(templ string, data interface{}) {
funcMap := template.FuncMap{
"join": strings.Join,
}
w := tabwriter.NewWriter(a.Writer, 0, 8, 1, '\t', 0)
t := template.Must(template.New("help").Funcs(funcMap).Parse(templ))
err := t.Execute(w, data)
if err != nil {
panic(err)
}
w.Flush()
}
}
// 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.Commands = append(a.Commands, helpCommand)
if (HelpFlag != BoolFlag{}) {
a.appendFlag(HelpFlag) a.appendFlag(HelpFlag)
} }
}
//append version/help flags //append version/help flags
if a.EnableBashCompletion { if a.EnableBashCompletion {
@ -85,21 +123,21 @@ func (a *App) Run(arguments []string) error {
// parse flags // parse flags
set := flagSet(a.Name, a.Flags) set := flagSet(a.Name, a.Flags)
set.SetOutput(ioutil.Discard) set.SetOutput(ioutil.Discard)
err := set.Parse(arguments[1:]) err = set.Parse(arguments[1:])
nerr := normalizeFlags(a.Flags, set) nerr := normalizeFlags(a.Flags, set)
if nerr != nil { if nerr != nil {
fmt.Println(nerr) fmt.Fprintln(a.Writer, nerr)
context := NewContext(a, set, set) context := NewContext(a, set, set)
ShowAppHelp(context) ShowAppHelp(context)
fmt.Println("") fmt.Fprintln(a.Writer)
return nerr return nerr
} }
context := NewContext(a, set, set) context := NewContext(a, set, set)
if err != nil { if err != nil {
fmt.Printf("Incorrect Usage.\n\n") fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n")
ShowAppHelp(context) ShowAppHelp(context)
fmt.Println("") fmt.Fprintln(a.Writer)
return err return err
} }
@ -115,6 +153,15 @@ func (a *App) Run(arguments []string) error {
return nil return nil
} }
if a.After != nil {
defer func() {
// err is always nil here.
// There is a check to see if it is non-nil
// just few lines before.
err = a.After(context)
}()
}
if a.Before != nil { if a.Before != nil {
err := a.Before(context) err := a.Before(context)
if err != nil { if err != nil {
@ -139,20 +186,22 @@ func (a *App) Run(arguments []string) error {
// Another entry point to the cli app, takes care of passing arguments and error handling // Another entry point to the cli app, takes care of passing arguments and error handling
func (a *App) RunAndExitOnError() { func (a *App) RunAndExitOnError() {
if err := a.Run(os.Args); err != nil { if err := a.Run(os.Args); err != nil {
os.Stderr.WriteString(fmt.Sprintln(err)) fmt.Fprintln(os.Stderr, err)
os.Exit(1) os.Exit(1)
} }
} }
// Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags // Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags
func (a *App) RunAsSubcommand(ctx *Context) error { 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.Commands = append(a.Commands, helpCommand)
if (HelpFlag != BoolFlag{}) {
a.appendFlag(HelpFlag) a.appendFlag(HelpFlag)
} }
} }
}
// append flags // append flags
if a.EnableBashCompletion { if a.EnableBashCompletion {
@ -162,23 +211,23 @@ func (a *App) RunAsSubcommand(ctx *Context) error {
// parse flags // parse flags
set := flagSet(a.Name, a.Flags) set := flagSet(a.Name, a.Flags)
set.SetOutput(ioutil.Discard) set.SetOutput(ioutil.Discard)
err := set.Parse(ctx.Args().Tail()) err = set.Parse(ctx.Args().Tail())
nerr := normalizeFlags(a.Flags, set) nerr := normalizeFlags(a.Flags, set)
context := NewContext(a, set, ctx.globalSet) context := NewContext(a, set, ctx.globalSet)
if nerr != nil { if nerr != nil {
fmt.Println(nerr) fmt.Fprintln(a.Writer, nerr)
if len(a.Commands) > 0 { if len(a.Commands) > 0 {
ShowSubcommandHelp(context) ShowSubcommandHelp(context)
} else { } else {
ShowCommandHelp(ctx, context.Args().First()) ShowCommandHelp(ctx, context.Args().First())
} }
fmt.Println("") fmt.Fprintln(a.Writer)
return nerr return nerr
} }
if err != nil { if err != nil {
fmt.Printf("Incorrect Usage.\n\n") fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n")
ShowSubcommandHelp(context) ShowSubcommandHelp(context)
return err return err
} }
@ -197,6 +246,15 @@ func (a *App) RunAsSubcommand(ctx *Context) error {
} }
} }
if a.After != nil {
defer func() {
// err is always nil here.
// There is a check to see if it is non-nil
// just few lines before.
err = a.After(context)
}()
}
if a.Before != nil { if a.Before != nil {
err := a.Before(context) err := a.Before(context)
if err != nil { if err != nil {
@ -214,11 +272,7 @@ func (a *App) RunAsSubcommand(ctx *Context) error {
} }
// Run default Action // Run default Action
if len(a.Commands) > 0 {
a.Action(context) a.Action(context)
} else {
a.Action(ctx)
}
return nil return nil
} }
@ -249,3 +303,19 @@ func (a *App) appendFlag(flag Flag) {
a.Flags = append(a.Flags, flag) a.Flags = append(a.Flags, flag)
} }
} }
// Author represents someone who has contributed to a cli project.
type Author struct {
Name string // The Authors name
Email string // The Authors email
}
// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
func (a Author) String() string {
e := ""
if a.Email != "" {
e = "<" + a.Email + "> "
}
return fmt.Sprintf("%v %v", a.Name, e)
}

View File

@ -1,6 +1,7 @@
package cli_test package cli_test
import ( import (
"flag"
"fmt" "fmt"
"os" "os"
"testing" "testing"
@ -20,6 +21,9 @@ func ExampleApp() {
app.Action = func(c *cli.Context) { app.Action = func(c *cli.Context) {
fmt.Printf("Hello %v\n", c.String("name")) fmt.Printf("Hello %v\n", c.String("name"))
} }
app.Author = "Harrison"
app.Email = "harrison@lolwut.com"
app.Authors = []cli.Author{cli.Author{Name: "Oliver Allen", Email: "oliver@toyshop.com"}}
app.Run(os.Args) app.Run(os.Args)
// Output: // Output:
// Hello Jeremy // Hello Jeremy
@ -33,13 +37,13 @@ func ExampleAppSubcommand() {
app.Commands = []cli.Command{ app.Commands = []cli.Command{
{ {
Name: "hello", Name: "hello",
ShortName: "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: []cli.Command{ Subcommands: []cli.Command{
{ {
Name: "english", Name: "english",
ShortName: "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: []cli.Flag{ Flags: []cli.Flag{
@ -74,7 +78,7 @@ func ExampleAppHelp() {
app.Commands = []cli.Command{ app.Commands = []cli.Command{
{ {
Name: "describeit", Name: "describeit",
ShortName: "d", Aliases: []string{"d"},
Usage: "use it to see a description", Usage: "use it to see a description",
Description: "This is how we describe describeit the function", Description: "This is how we describe describeit the function",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
@ -104,7 +108,7 @@ func ExampleAppBashComplete() {
app.Commands = []cli.Command{ app.Commands = []cli.Command{
{ {
Name: "describeit", Name: "describeit",
ShortName: "d", Aliases: []string{"d"},
Usage: "use it to see a description", Usage: "use it to see a description",
Description: "This is how we describe describeit the function", Description: "This is how we describe describeit the function",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
@ -158,8 +162,8 @@ var commandAppTests = []struct {
func TestApp_Command(t *testing.T) { func TestApp_Command(t *testing.T) {
app := cli.NewApp() app := cli.NewApp()
fooCommand := cli.Command{Name: "foobar", ShortName: "f"} fooCommand := cli.Command{Name: "foobar", Aliases: []string{"f"}}
batCommand := cli.Command{Name: "batbaz", ShortName: "b"} batCommand := cli.Command{Name: "batbaz", Aliases: []string{"b"}}
app.Commands = []cli.Command{ app.Commands = []cli.Command{
fooCommand, fooCommand,
batCommand, batCommand,
@ -192,6 +196,76 @@ func TestApp_CommandWithArgBeforeFlags(t *testing.T) {
expect(t, firstArg, "my-arg") expect(t, firstArg, "my-arg")
} }
func TestApp_RunAsSubcommandParseFlags(t *testing.T) {
var context *cli.Context
a := cli.NewApp()
a.Commands = []cli.Command{
{
Name: "foo",
Action: func(c *cli.Context) {
context = c
},
Flags: []cli.Flag{
cli.StringFlag{
Name: "lang",
Value: "english",
Usage: "language for the greeting",
},
},
Before: func(_ *cli.Context) error { return nil },
},
}
a.Run([]string{"", "foo", "--lang", "spanish", "abcd"})
expect(t, context.Args().Get(0), "abcd")
expect(t, context.String("lang"), "spanish")
}
func TestApp_CommandWithFlagBeforeTerminator(t *testing.T) {
var parsedOption string
var args []string
app := cli.NewApp()
command := cli.Command{
Name: "cmd",
Flags: []cli.Flag{
cli.StringFlag{Name: "option", Value: "", Usage: "some option"},
},
Action: func(c *cli.Context) {
parsedOption = c.String("option")
args = c.Args()
},
}
app.Commands = []cli.Command{command}
app.Run([]string{"", "cmd", "my-arg", "--option", "my-option", "--", "--notARealFlag"})
expect(t, parsedOption, "my-option")
expect(t, args[0], "my-arg")
expect(t, args[1], "--")
expect(t, args[2], "--notARealFlag")
}
func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
var args []string
app := cli.NewApp()
command := cli.Command{
Name: "cmd",
Action: func(c *cli.Context) {
args = c.Args()
},
}
app.Commands = []cli.Command{command}
app.Run([]string{"", "cmd", "my-arg", "--", "notAFlagAtAll"})
expect(t, args[0], "my-arg")
expect(t, args[1], "--")
expect(t, args[2], "notAFlagAtAll")
}
func TestApp_Float64Flag(t *testing.T) { func TestApp_Float64Flag(t *testing.T) {
var meters float64 var meters float64
@ -265,6 +339,50 @@ func TestApp_ParseSliceFlags(t *testing.T) {
} }
} }
func TestApp_DefaultStdout(t *testing.T) {
app := cli.NewApp()
if app.Writer != os.Stdout {
t.Error("Default output writer not set.")
}
}
type mockWriter struct {
written []byte
}
func (fw *mockWriter) Write(p []byte) (n int, err error) {
if fw.written == nil {
fw.written = p
} else {
fw.written = append(fw.written, p...)
}
return len(p), nil
}
func (fw *mockWriter) GetWritten() (b []byte) {
return fw.written
}
func TestApp_SetStdout(t *testing.T) {
w := &mockWriter{}
app := cli.NewApp()
app.Name = "test"
app.Writer = w
err := app.Run([]string{"help"})
if err != nil {
t.Fatalf("Run error: %s", err)
}
if len(w.written) == 0 {
t.Error("App did not write output to desired writer.")
}
}
func TestApp_BeforeFunc(t *testing.T) { func TestApp_BeforeFunc(t *testing.T) {
beforeRun, subcommandRun := false, false beforeRun, subcommandRun := false, false
beforeError := fmt.Errorf("fail") beforeError := fmt.Errorf("fail")
@ -331,6 +449,87 @@ func TestApp_BeforeFunc(t *testing.T) {
} }
func TestApp_AfterFunc(t *testing.T) {
afterRun, subcommandRun := false, false
afterError := fmt.Errorf("fail")
var err error
app := cli.NewApp()
app.After = func(c *cli.Context) error {
afterRun = true
s := c.String("opt")
if s == "fail" {
return afterError
}
return nil
}
app.Commands = []cli.Command{
cli.Command{
Name: "sub",
Action: func(c *cli.Context) {
subcommandRun = true
},
},
}
app.Flags = []cli.Flag{
cli.StringFlag{Name: "opt"},
}
// run with the After() func succeeding
err = app.Run([]string{"command", "--opt", "succeed", "sub"})
if err != nil {
t.Fatalf("Run error: %s", err)
}
if afterRun == false {
t.Errorf("After() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
// reset
afterRun, subcommandRun = false, false
// run with the Before() func failing
err = app.Run([]string{"command", "--opt", "fail", "sub"})
// should be the same error produced by the Before func
if err != afterError {
t.Errorf("Run error expected, but not received")
}
if afterRun == false {
t.Errorf("After() not executed when expected")
}
if subcommandRun == false {
t.Errorf("Subcommand not executed when expected")
}
}
func TestAppNoHelpFlag(t *testing.T) {
oldFlag := cli.HelpFlag
defer func() {
cli.HelpFlag = oldFlag
}()
cli.HelpFlag = cli.BoolFlag{}
app := cli.NewApp()
err := app.Run([]string{"test", "-h"})
if err != flag.ErrHelp {
t.Errorf("expected error about missing help flag, but got: %s (%T)", err, err)
}
}
func TestAppHelpPrinter(t *testing.T) { func TestAppHelpPrinter(t *testing.T) {
oldPrinter := cli.HelpPrinter oldPrinter := cli.HelpPrinter
defer func() { defer func() {

View File

@ -13,7 +13,7 @@ func Example() {
app.Commands = []cli.Command{ app.Commands = []cli.Command{
{ {
Name: "add", Name: "add",
ShortName: "a", Aliases: []string{"a"},
Usage: "add a task to the list", Usage: "add a task to the list",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
println("added task: ", c.Args().First()) println("added task: ", c.Args().First())
@ -21,7 +21,7 @@ func Example() {
}, },
{ {
Name: "complete", Name: "complete",
ShortName: "c", Aliases: []string{"c"},
Usage: "complete a task on the list", Usage: "complete a task on the list",
Action: func(c *cli.Context) { Action: func(c *cli.Context) {
println("completed task: ", c.Args().First()) println("completed task: ", c.Args().First())
@ -38,13 +38,13 @@ func ExampleSubcommand() {
app.Commands = []cli.Command{ app.Commands = []cli.Command{
{ {
Name: "hello", Name: "hello",
ShortName: "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: []cli.Command{ Subcommands: []cli.Command{
{ {
Name: "english", Name: "english",
ShortName: "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: []cli.Flag{ Flags: []cli.Flag{
@ -59,7 +59,7 @@ func ExampleSubcommand() {
}, },
}, { }, {
Name: "spanish", Name: "spanish",
ShortName: "sp", Aliases: []string{"sp"},
Usage: "sends a greeting in spanish", Usage: "sends a greeting in spanish",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ cli.StringFlag{
@ -73,7 +73,7 @@ func ExampleSubcommand() {
}, },
}, { }, {
Name: "french", Name: "french",
ShortName: "fr", Aliases: []string{"fr"},
Usage: "sends a greeting in french", Usage: "sends a greeting in french",
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ cli.StringFlag{

View File

@ -10,8 +10,10 @@ import (
type Command struct { type Command struct {
// The name of the command // The name of the command
Name string Name string
// short name of the command. Typically one character // short name of the command. Typically one character (deprecated, use `Aliases`)
ShortName string ShortName string
// A list of aliases for the command
Aliases []string
// A short description of the usage of this command // A short description of the usage of this command
Usage string Usage string
// A longer explanation of how the command works // A longer explanation of how the command works
@ -21,6 +23,9 @@ type Command struct {
// An action to execute before any sub-subcommands are run, but after the context is ready // An action to execute before any sub-subcommands are run, but after the context is ready
// If a non-nil error is returned, no sub-subcommands are run // If a non-nil error is returned, no sub-subcommands are run
Before func(context *Context) error Before func(context *Context) error
// An action to execute after any subcommands are run, but after the subcommand has finished
// It is run even if Action() panics
After func(context *Context) error
// The function to call when this command is invoked // The function to call when this command is invoked
Action func(context *Context) Action func(context *Context)
// List of child commands // List of child commands
@ -36,11 +41,11 @@ type Command struct {
// Invokes the command given the context, parses ctx.Args() to generate command-specific flags // Invokes the command given the context, parses ctx.Args() to generate command-specific flags
func (c Command) Run(ctx *Context) error { func (c Command) Run(ctx *Context) error {
if len(c.Subcommands) > 0 || c.Before != nil { if len(c.Subcommands) > 0 || c.Before != nil || c.After != nil {
return c.startApp(ctx) return c.startApp(ctx)
} }
if !c.HideHelp { if !c.HideHelp && (HelpFlag != BoolFlag{}) {
// append help to flags // append help to flags
c.Flags = append( c.Flags = append(
c.Flags, c.Flags,
@ -56,36 +61,48 @@ func (c Command) Run(ctx *Context) error {
set.SetOutput(ioutil.Discard) set.SetOutput(ioutil.Discard)
firstFlagIndex := -1 firstFlagIndex := -1
terminatorIndex := -1
for index, arg := range ctx.Args() { for index, arg := range ctx.Args() {
if strings.HasPrefix(arg, "-") { if arg == "--" {
firstFlagIndex = index terminatorIndex = index
break break
} else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 {
firstFlagIndex = index
} }
} }
var err error var err error
if firstFlagIndex > -1 && !c.SkipFlagParsing { if firstFlagIndex > -1 && !c.SkipFlagParsing {
args := ctx.Args() args := ctx.Args()
regularArgs := args[1:firstFlagIndex] regularArgs := make([]string, len(args[1:firstFlagIndex]))
flagArgs := args[firstFlagIndex:] copy(regularArgs, args[1:firstFlagIndex])
var flagArgs []string
if terminatorIndex > -1 {
flagArgs = args[firstFlagIndex:terminatorIndex]
regularArgs = append(regularArgs, args[terminatorIndex:]...)
} else {
flagArgs = args[firstFlagIndex:]
}
err = set.Parse(append(flagArgs, regularArgs...)) err = set.Parse(append(flagArgs, regularArgs...))
} else { } else {
err = set.Parse(ctx.Args().Tail()) err = set.Parse(ctx.Args().Tail())
} }
if err != nil { if err != nil {
fmt.Printf("Incorrect Usage.\n\n") fmt.Fprint(ctx.App.Writer, "Incorrect Usage.\n\n")
ShowCommandHelp(ctx, c.Name) ShowCommandHelp(ctx, c.Name)
fmt.Println("") fmt.Fprintln(ctx.App.Writer)
return err return err
} }
nerr := normalizeFlags(c.Flags, set) nerr := normalizeFlags(c.Flags, set)
if nerr != nil { if nerr != nil {
fmt.Println(nerr) fmt.Fprintln(ctx.App.Writer, nerr)
fmt.Println("") fmt.Fprintln(ctx.App.Writer)
ShowCommandHelp(ctx, c.Name) ShowCommandHelp(ctx, c.Name)
fmt.Println("") fmt.Fprintln(ctx.App.Writer)
return nerr return nerr
} }
context := NewContext(ctx.App, set, ctx.globalSet) context := NewContext(ctx.App, set, ctx.globalSet)
@ -102,9 +119,24 @@ func (c Command) Run(ctx *Context) error {
return nil return nil
} }
func (c Command) Names() []string {
names := []string{c.Name}
if c.ShortName != "" {
names = append(names, c.ShortName)
}
return append(names, c.Aliases...)
}
// Returns true if Command.Name or Command.ShortName matches given name // Returns true if Command.Name or Command.ShortName matches given name
func (c Command) HasName(name string) bool { func (c Command) HasName(name string) bool {
return c.Name == name || c.ShortName == name for _, n := range c.Names() {
if n == name {
return true
}
}
return false
} }
func (c Command) startApp(ctx *Context) error { func (c Command) startApp(ctx *Context) error {
@ -134,6 +166,7 @@ func (c Command) startApp(ctx *Context) error {
// set the actions // set the actions
app.Before = c.Before app.Before = c.Before
app.After = c.After
if c.Action != nil { if c.Action != nil {
app.Action = c.Action app.Action = c.Action
} else { } else {

View File

@ -17,7 +17,7 @@ func TestCommandDoNotIgnoreFlags(t *testing.T) {
command := cli.Command{ command := cli.Command{
Name: "test-cmd", Name: "test-cmd",
ShortName: "tc", Aliases: []string{"tc"},
Usage: "this is for testing", Usage: "this is for testing",
Description: "testing", Description: "testing",
Action: func(_ *cli.Context) {}, Action: func(_ *cli.Context) {},
@ -37,7 +37,7 @@ func TestCommandIgnoreFlags(t *testing.T) {
command := cli.Command{ command := cli.Command{
Name: "test-cmd", Name: "test-cmd",
ShortName: "tc", Aliases: []string{"tc"},
Usage: "this is for testing", Usage: "this is for testing",
Description: "testing", Description: "testing",
Action: func(_ *cli.Context) {}, Action: func(_ *cli.Context) {},

View File

@ -106,6 +106,11 @@ func (c *Context) GlobalGeneric(name string) interface{} {
return lookupGeneric(name, c.globalSet) return lookupGeneric(name, c.globalSet)
} }
// Returns the number of flags set
func (c *Context) NumFlags() int {
return c.flagSet.NFlag()
}
// Determines if the flag was actually set // Determines if the flag was actually set
func (c *Context) IsSet(name string) bool { func (c *Context) IsSet(name string) bool {
if c.setFlags == nil { if c.setFlags == nil {

View File

@ -97,3 +97,15 @@ func TestContext_GlobalIsSet(t *testing.T) {
expect(t, c.GlobalIsSet("myflagGlobalUnset"), false) expect(t, c.GlobalIsSet("myflagGlobalUnset"), false)
expect(t, c.GlobalIsSet("bogusGlobal"), false) expect(t, c.GlobalIsSet("bogusGlobal"), false)
} }
func TestContext_NumFlags(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.Bool("myflag", false, "doc")
set.String("otherflag", "hello world", "doc")
globalSet := flag.NewFlagSet("test", 0)
globalSet.Bool("myflagGlobal", true, "doc")
c := cli.NewContext(nil, set, globalSet)
set.Parse([]string{"--myflag", "--otherflag=foo"})
globalSet.Parse([]string{"--myflagGlobal"})
expect(t, c.NumFlags(), 2)
}

View File

@ -12,6 +12,7 @@ import (
// This flag enables bash-completion for all commands and subcommands // This flag enables bash-completion for all commands and subcommands
var BashCompletionFlag = BoolFlag{ var BashCompletionFlag = BoolFlag{
Name: "generate-bash-completion", Name: "generate-bash-completion",
Hide: true,
} }
// This flag prints the version for the application // This flag prints the version for the application
@ -21,6 +22,8 @@ var VersionFlag = BoolFlag{
} }
// This flag prints the help for all commands and subcommands // This flag prints the help for all commands and subcommands
// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand
// unless HideHelp is set to true)
var HelpFlag = BoolFlag{ var HelpFlag = BoolFlag{
Name: "help, h", Name: "help, h",
Usage: "show help", Usage: "show help",
@ -34,6 +37,7 @@ type Flag interface {
// Apply Flag settings to the given flag set // Apply Flag settings to the given flag set
Apply(*flag.FlagSet) Apply(*flag.FlagSet)
getName() string getName() string
isNotHidden() bool
} }
func flagSet(name string, flags []Flag) *flag.FlagSet { func flagSet(name string, flags []Flag) *flag.FlagSet {
@ -65,12 +69,18 @@ type GenericFlag struct {
Value Generic Value Generic
Usage string Usage string
EnvVar string EnvVar string
Hide bool
} }
// 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
// the value)
func (f GenericFlag) String() string { func (f GenericFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s %v\t`%v` %s", prefixFor(f.Name), f.Name, f.Value, "-"+f.Name+" option -"+f.Name+" option", f.Usage)) return withEnvHint(f.EnvVar, fmt.Sprintf("%s%s \"%v\"\t%v", prefixFor(f.Name), f.Name, f.Value, f.Usage))
} }
// Apply takes the flagset and calls Set on the generic flag with the value
// provided by the user for parsing by the flag
func (f GenericFlag) Apply(set *flag.FlagSet) { func (f GenericFlag) Apply(set *flag.FlagSet) {
val := f.Value val := f.Value
if f.EnvVar != "" { if f.EnvVar != "" {
@ -92,6 +102,10 @@ func (f GenericFlag) getName() string {
return f.Name return f.Name
} }
func (f GenericFlag) isNotHidden() bool {
return !f.Hide
}
type StringSlice []string type StringSlice []string
func (f *StringSlice) Set(value string) error { func (f *StringSlice) Set(value string) error {
@ -112,12 +126,13 @@ type StringSliceFlag struct {
Value *StringSlice Value *StringSlice
Usage string Usage string
EnvVar string EnvVar string
Hide bool
} }
func (f StringSliceFlag) String() string { func (f StringSliceFlag) String() string {
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
pref := prefixFor(firstName) pref := prefixFor(firstName)
return withEnvHint(f.EnvVar, fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)) return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
} }
func (f StringSliceFlag) Apply(set *flag.FlagSet) { func (f StringSliceFlag) Apply(set *flag.FlagSet) {
@ -145,6 +160,10 @@ func (f StringSliceFlag) getName() string {
return f.Name return f.Name
} }
func (f StringSliceFlag) isNotHidden() bool {
return !f.Hide
}
type IntSlice []int type IntSlice []int
func (f *IntSlice) Set(value string) error { func (f *IntSlice) Set(value string) error {
@ -171,12 +190,13 @@ type IntSliceFlag struct {
Value *IntSlice Value *IntSlice
Usage string Usage string
EnvVar string EnvVar string
Hide bool
} }
func (f IntSliceFlag) String() string { func (f IntSliceFlag) String() string {
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ") firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
pref := prefixFor(firstName) pref := prefixFor(firstName)
return withEnvHint(f.EnvVar, fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)) return withEnvHint(f.EnvVar, fmt.Sprintf("%s [%v]\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage))
} }
func (f IntSliceFlag) Apply(set *flag.FlagSet) { func (f IntSliceFlag) Apply(set *flag.FlagSet) {
@ -207,10 +227,15 @@ func (f IntSliceFlag) getName() string {
return f.Name return f.Name
} }
func (f IntSliceFlag) isNotHidden() bool {
return !f.Hide
}
type BoolFlag struct { type BoolFlag struct {
Name string Name string
Usage string Usage string
EnvVar string EnvVar string
Hide bool
} }
func (f BoolFlag) String() string { func (f BoolFlag) String() string {
@ -241,10 +266,15 @@ func (f BoolFlag) getName() string {
return f.Name return f.Name
} }
func (f BoolFlag) isNotHidden() bool {
return !f.Hide
}
type BoolTFlag struct { type BoolTFlag struct {
Name string Name string
Usage string Usage string
EnvVar string EnvVar string
Hide bool
} }
func (f BoolTFlag) String() string { func (f BoolTFlag) String() string {
@ -275,11 +305,16 @@ func (f BoolTFlag) getName() string {
return f.Name return f.Name
} }
func (f BoolTFlag) isNotHidden() bool {
return !f.Hide
}
type StringFlag struct { type StringFlag struct {
Name string Name string
Value string Value string
Usage string Usage string
EnvVar string EnvVar string
Hide bool
} }
func (f StringFlag) String() string { func (f StringFlag) String() string {
@ -287,11 +322,10 @@ func (f StringFlag) String() string {
fmtString = "%s %v\t%v" fmtString = "%s %v\t%v"
if len(f.Value) > 0 { if len(f.Value) > 0 {
fmtString = "%s '%v'\t%v" fmtString = "%s \"%v\"\t%v"
} else { } else {
fmtString = "%s %v\t%v" fmtString = "%s %v\t%v"
} }
return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage)) return withEnvHint(f.EnvVar, fmt.Sprintf(fmtString, prefixedNames(f.Name), f.Value, f.Usage))
} }
@ -315,15 +349,20 @@ func (f StringFlag) getName() string {
return f.Name return f.Name
} }
func (f StringFlag) isNotHidden() bool {
return !f.Hide
}
type IntFlag struct { type IntFlag struct {
Name string Name string
Value int Value int
Usage string Usage string
EnvVar string EnvVar string
Hide bool
} }
func (f IntFlag) String() string { func (f IntFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage)) return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
} }
func (f IntFlag) Apply(set *flag.FlagSet) { func (f IntFlag) Apply(set *flag.FlagSet) {
@ -331,7 +370,7 @@ func (f IntFlag) Apply(set *flag.FlagSet) {
for _, envVar := range strings.Split(f.EnvVar, ",") { for _, envVar := range strings.Split(f.EnvVar, ",") {
envVar = strings.TrimSpace(envVar) envVar = strings.TrimSpace(envVar)
if envVal := os.Getenv(envVar); envVal != "" { if envVal := os.Getenv(envVar); envVal != "" {
envValInt, err := strconv.ParseUint(envVal, 10, 64) envValInt, err := strconv.ParseInt(envVal, 0, 64)
if err == nil { if err == nil {
f.Value = int(envValInt) f.Value = int(envValInt)
break break
@ -349,15 +388,20 @@ func (f IntFlag) getName() string {
return f.Name return f.Name
} }
func (f IntFlag) isNotHidden() bool {
return !f.Hide
}
type DurationFlag struct { type DurationFlag struct {
Name string Name string
Value time.Duration Value time.Duration
Usage string Usage string
EnvVar string EnvVar string
Hide bool
} }
func (f DurationFlag) String() string { func (f DurationFlag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage)) return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
} }
func (f DurationFlag) Apply(set *flag.FlagSet) { func (f DurationFlag) Apply(set *flag.FlagSet) {
@ -383,15 +427,20 @@ func (f DurationFlag) getName() string {
return f.Name return f.Name
} }
func (f DurationFlag) isNotHidden() bool {
return !f.Hide
}
type Float64Flag struct { type Float64Flag struct {
Name string Name string
Value float64 Value float64
Usage string Usage string
EnvVar string EnvVar string
Hide bool
} }
func (f Float64Flag) String() string { func (f Float64Flag) String() string {
return withEnvHint(f.EnvVar, fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage)) return withEnvHint(f.EnvVar, fmt.Sprintf("%s \"%v\"\t%v", prefixedNames(f.Name), f.Value, f.Usage))
} }
func (f Float64Flag) Apply(set *flag.FlagSet) { func (f Float64Flag) Apply(set *flag.FlagSet) {
@ -416,6 +465,10 @@ func (f Float64Flag) getName() string {
return f.Name return f.Name
} }
func (f Float64Flag) isNotHidden() bool {
return !f.Hide
}
func prefixFor(name string) (prefix string) { func prefixFor(name string) (prefix string) {
if len(name) == 1 { if len(name) == 1 {
prefix = "-" prefix = "-"

View File

@ -38,7 +38,7 @@ var stringFlagTests = []struct {
{"help", "", "--help \t"}, {"help", "", "--help \t"},
{"h", "", "-h \t"}, {"h", "", "-h \t"},
{"h", "", "-h \t"}, {"h", "", "-h \t"},
{"test", "Something", "--test 'Something'\t"}, {"test", "Something", "--test \"Something\"\t"},
} }
func TestStringFlagHelpOutput(t *testing.T) { func TestStringFlagHelpOutput(t *testing.T) {
@ -75,22 +75,22 @@ var stringSliceFlagTests = []struct {
s := &cli.StringSlice{} s := &cli.StringSlice{}
s.Set("") s.Set("")
return s return s
}(), "--help '--help option --help option'\t"}, }(), "--help [--help option --help option]\t"},
{"h", func() *cli.StringSlice { {"h", func() *cli.StringSlice {
s := &cli.StringSlice{} s := &cli.StringSlice{}
s.Set("") s.Set("")
return s return s
}(), "-h '-h option -h option'\t"}, }(), "-h [-h option -h option]\t"},
{"h", func() *cli.StringSlice { {"h", func() *cli.StringSlice {
s := &cli.StringSlice{} s := &cli.StringSlice{}
s.Set("") s.Set("")
return s return s
}(), "-h '-h option -h option'\t"}, }(), "-h [-h option -h option]\t"},
{"test", func() *cli.StringSlice { {"test", func() *cli.StringSlice {
s := &cli.StringSlice{} s := &cli.StringSlice{}
s.Set("Something") s.Set("Something")
return s return s
}(), "--test '--test option --test option'\t"}, }(), "--test [--test option --test option]\t"},
} }
func TestStringSliceFlagHelpOutput(t *testing.T) { func TestStringSliceFlagHelpOutput(t *testing.T) {
@ -122,8 +122,8 @@ var intFlagTests = []struct {
name string name string
expected string expected string
}{ }{
{"help", "--help '0'\t"}, {"help", "--help \"0\"\t"},
{"h", "-h '0'\t"}, {"h", "-h \"0\"\t"},
} }
func TestIntFlagHelpOutput(t *testing.T) { func TestIntFlagHelpOutput(t *testing.T) {
@ -155,8 +155,8 @@ var durationFlagTests = []struct {
name string name string
expected string expected string
}{ }{
{"help", "--help '0'\t"}, {"help", "--help \"0\"\t"},
{"h", "-h '0'\t"}, {"h", "-h \"0\"\t"},
} }
func TestDurationFlagHelpOutput(t *testing.T) { func TestDurationFlagHelpOutput(t *testing.T) {
@ -189,14 +189,14 @@ var intSliceFlagTests = []struct {
value *cli.IntSlice value *cli.IntSlice
expected string expected string
}{ }{
{"help", &cli.IntSlice{}, "--help '--help option --help option'\t"}, {"help", &cli.IntSlice{}, "--help [--help option --help option]\t"},
{"h", &cli.IntSlice{}, "-h '-h option -h option'\t"}, {"h", &cli.IntSlice{}, "-h [-h option -h option]\t"},
{"h", &cli.IntSlice{}, "-h '-h option -h option'\t"}, {"h", &cli.IntSlice{}, "-h [-h option -h option]\t"},
{"test", func() *cli.IntSlice { {"test", func() *cli.IntSlice {
i := &cli.IntSlice{} i := &cli.IntSlice{}
i.Set("9") i.Set("9")
return i return i
}(), "--test '--test option --test option'\t"}, }(), "--test [--test option --test option]\t"},
} }
func TestIntSliceFlagHelpOutput(t *testing.T) { func TestIntSliceFlagHelpOutput(t *testing.T) {
@ -228,8 +228,8 @@ var float64FlagTests = []struct {
name string name string
expected string expected string
}{ }{
{"help", "--help '0'\t"}, {"help", "--help \"0\"\t"},
{"h", "-h '0'\t"}, {"h", "-h \"0\"\t"},
} }
func TestFloat64FlagHelpOutput(t *testing.T) { func TestFloat64FlagHelpOutput(t *testing.T) {
@ -262,15 +262,14 @@ var genericFlagTests = []struct {
value cli.Generic value cli.Generic
expected string expected string
}{ }{
{"help", &Parser{}, "--help <nil>\t`-help option -help option` "}, {"test", &Parser{"abc", "def"}, "--test \"abc,def\"\ttest flag"},
{"h", &Parser{}, "-h <nil>\t`-h option -h option` "}, {"t", &Parser{"abc", "def"}, "-t \"abc,def\"\ttest flag"},
{"test", &Parser{}, "--test <nil>\t`-test option -test option` "},
} }
func TestGenericFlagHelpOutput(t *testing.T) { func TestGenericFlagHelpOutput(t *testing.T) {
for _, test := range genericFlagTests { for _, test := range genericFlagTests {
flag := cli.GenericFlag{Name: test.name} flag := cli.GenericFlag{Name: test.name, Value: test.value, Usage: "test flag"}
output := flag.String() output := flag.String()
if output != test.expected { if output != test.expected {

View File

@ -1,11 +1,6 @@
package cli package cli
import ( import "fmt"
"fmt"
"os"
"text/tabwriter"
"text/template"
)
// The text template for the Default help topic. // The text template for the Default help topic.
// cli.go uses text/template to render templates. You can // cli.go uses text/template to render templates. You can
@ -17,14 +12,13 @@ USAGE:
{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...] {{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]
VERSION: VERSION:
{{.Version}}{{if or .Author .Email}} {{.Version}}
AUTHOR:{{if .Author}} AUTHOR(S):
{{.Author}}{{if .Email}} - <{{.Email}}>{{end}}{{else}} {{range .Authors}}{{ . }} {{end}}
{{.Email}}{{end}}{{end}}
COMMANDS: COMMANDS:
{{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
{{end}}{{if .Flags}} {{end}}{{if .Flags}}
GLOBAL OPTIONS: GLOBAL OPTIONS:
{{range .Flags}}{{.}} {{range .Flags}}{{.}}
@ -58,7 +52,7 @@ USAGE:
{{.Name}} command{{if .Flags}} [command options]{{end}} [arguments...] {{.Name}} command{{if .Flags}} [command options]{{end}} [arguments...]
COMMANDS: COMMANDS:
{{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
{{end}}{{if .Flags}} {{end}}{{if .Flags}}
OPTIONS: OPTIONS:
{{range .Flags}}{{.}} {{range .Flags}}{{.}}
@ -67,7 +61,7 @@ OPTIONS:
var helpCommand = Command{ var helpCommand = Command{
Name: "help", Name: "help",
ShortName: "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",
Action: func(c *Context) { Action: func(c *Context) {
args := c.Args() args := c.Args()
@ -81,7 +75,7 @@ var helpCommand = Command{
var helpSubcommand = Command{ var helpSubcommand = Command{
Name: "help", Name: "help",
ShortName: "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",
Action: func(c *Context) { Action: func(c *Context) {
args := c.Args() args := c.Args()
@ -94,30 +88,61 @@ var helpSubcommand = Command{
} }
// Prints help for the App // Prints help for the App
var HelpPrinter = printHelp type helpPrinter func(templ string, data interface{})
var HelpPrinter helpPrinter = nil
// Prints version for the App // Prints version for the App
var VersionPrinter = printVersion var VersionPrinter = printVersion
func ShowAppHelp(c *Context) { func ShowAppHelp(c *Context) {
HelpPrinter(AppHelpTemplate, c.App) // Make a copy of c.App context
app := *c.App
app.Flags = make([]Flag, 0)
for _, flag := range c.App.Flags {
if flag.isNotHidden() {
app.Flags = append(app.Flags, flag)
}
}
HelpPrinter(AppHelpTemplate, app)
} }
// Prints the list of subcommands as the default app completion method // Prints the list of subcommands as the default app completion method
func DefaultAppComplete(c *Context) { func DefaultAppComplete(c *Context) {
for _, command := range c.App.Commands { for _, command := range c.App.Commands {
fmt.Println(command.Name) for _, name := range command.Names() {
if command.ShortName != "" { fmt.Fprintln(c.App.Writer, name)
fmt.Println(command.ShortName)
} }
} }
} }
// Prints help for the given command // Prints help for the given command
func ShowCommandHelp(c *Context, command string) { func ShowCommandHelp(c *Context, command string) {
// show the subcommand help for a command with subcommands
if command == "" {
// Make a copy of c.App context
app := *c.App
app.Flags = make([]Flag, 0)
for _, flag := range c.App.Flags {
if flag.isNotHidden() {
app.Flags = append(app.Flags, flag)
}
}
HelpPrinter(SubcommandHelpTemplate, app)
return
}
for _, c := range c.App.Commands { for _, c := range c.App.Commands {
if c.HasName(command) { if c.HasName(command) {
HelpPrinter(CommandHelpTemplate, c) // Make a copy of command context
c0 := c
c0.Flags = make([]Flag, 0)
for _, flag := range c.Flags {
if flag.isNotHidden() {
c0.Flags = append(c0.Flags, flag)
}
}
HelpPrinter(CommandHelpTemplate, c0)
return return
} }
} }
@ -125,13 +150,13 @@ func ShowCommandHelp(c *Context, command string) {
if c.App.CommandNotFound != nil { if c.App.CommandNotFound != nil {
c.App.CommandNotFound(c, command) c.App.CommandNotFound(c, command)
} else { } else {
fmt.Printf("No help topic for '%v'\n", command) fmt.Fprintf(c.App.Writer, "No help topic for '%v'\n", command)
} }
} }
// Prints help for the given subcommand // Prints help for the given subcommand
func ShowSubcommandHelp(c *Context) { func ShowSubcommandHelp(c *Context) {
HelpPrinter(SubcommandHelpTemplate, c.App) ShowCommandHelp(c, c.Command.Name)
} }
// Prints the version number of the App // Prints the version number of the App
@ -140,7 +165,7 @@ func ShowVersion(c *Context) {
} }
func printVersion(c *Context) { func printVersion(c *Context) {
fmt.Printf("%v version %v\n", c.App.Name, c.App.Version) fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version)
} }
// Prints the lists of commands within a given context // Prints the lists of commands within a given context
@ -159,16 +184,6 @@ func ShowCommandCompletions(ctx *Context, command string) {
} }
} }
func printHelp(templ string, data interface{}) {
w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0)
t := template.Must(template.New("help").Parse(templ))
err := t.Execute(w, data)
if err != nil {
panic(err)
}
w.Flush()
}
func checkVersion(c *Context) bool { func checkVersion(c *Context) bool {
if c.GlobalBool("version") { if c.GlobalBool("version") {
ShowVersion(c) ShowVersion(c)

75
main.go
View File

@ -19,11 +19,46 @@ package main
import ( import (
"os" "os"
"github.com/codegangsta/cli" "github.com/minio-io/cli"
"github.com/minio-io/minio/pkg/server" "github.com/minio-io/minio/pkg/server"
"github.com/minio-io/minio/pkg/utils/log" "github.com/minio-io/minio/pkg/utils/log"
) )
var flags = []cli.Flag{
cli.StringFlag{
Name: "domain,d",
Value: "",
Usage: "domain used for routing incoming API requests",
},
cli.StringFlag{
Name: "api-address,a",
Value: ":9000",
Usage: "address for incoming API requests",
},
cli.StringFlag{
Name: "web-address,w",
Value: ":9001",
Usage: "address for incoming Management UI requests",
},
cli.StringFlag{
Name: "cert,c",
Hide: true,
Value: "",
Usage: "cert.pem",
},
cli.StringFlag{
Name: "key,k",
Hide: true,
Value: "",
Usage: "key.pem",
},
cli.StringFlag{
Name: "driver-type,t",
Value: "donut",
Usage: "valid entries: file,inmemory,donut",
},
}
func getDriverType(input string) server.DriverType { func getDriverType(input string) server.DriverType {
switch { switch {
case input == "file": case input == "file":
@ -82,39 +117,11 @@ func runCmd(c *cli.Context) {
func main() { func main() {
app := cli.NewApp() app := cli.NewApp()
app.Name = "minio" app.Name = "minio"
app.Usage = "" app.Version = "0.1.0"
app.Flags = []cli.Flag{ app.Author = "Minio.io"
cli.StringFlag{ app.Usage = "Minimalist Object Storage"
Name: "domain,d", app.EnableBashCompletion = true
Value: "", app.Flags = flags
Usage: "domain used for routing incoming API requests",
},
cli.StringFlag{
Name: "api-address,a",
Value: ":9000",
Usage: "address for incoming API requests",
},
cli.StringFlag{
Name: "web-address,w",
Value: ":9001",
Usage: "address for incoming Management UI requests",
},
cli.StringFlag{
Name: "cert,c",
Value: "",
Usage: "cert.pem",
},
cli.StringFlag{
Name: "key,k",
Value: "",
Usage: "key.pem",
},
cli.StringFlag{
Name: "driver-type,t",
Value: "donut",
Usage: "valid entries: file,inmemory,donut",
},
}
app.Action = runCmd app.Action = runCmd
app.Run(os.Args) app.Run(os.Args)
} }