Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / urfave / cli / app.go
1 package cli
2
3 import (
4         "fmt"
5         "io"
6         "io/ioutil"
7         "os"
8         "path/filepath"
9         "sort"
10         "time"
11 )
12
13 var (
14         changeLogURL                    = "https://github.com/urfave/cli/blob/master/CHANGELOG.md"
15         appActionDeprecationURL         = fmt.Sprintf("%s#deprecated-cli-app-action-signature", changeLogURL)
16         runAndExitOnErrorDeprecationURL = fmt.Sprintf("%s#deprecated-cli-app-runandexitonerror", changeLogURL)
17
18         contactSysadmin = "This is an error in the application.  Please contact the distributor of this application if this is not you."
19
20         errInvalidActionType = NewExitError("ERROR invalid Action type. "+
21                 fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error).  %s", contactSysadmin)+
22                 fmt.Sprintf("See %s", appActionDeprecationURL), 2)
23 )
24
25 // App is the main structure of a cli application. It is recommended that
26 // an app be created with the cli.NewApp() function
27 type App struct {
28         // The name of the program. Defaults to path.Base(os.Args[0])
29         Name string
30         // Full name of command for help, defaults to Name
31         HelpName string
32         // Description of the program.
33         Usage string
34         // Text to override the USAGE section of help
35         UsageText string
36         // Description of the program argument format.
37         ArgsUsage string
38         // Version of the program
39         Version string
40         // Description of the program
41         Description string
42         // List of commands to execute
43         Commands []Command
44         // List of flags to parse
45         Flags []Flag
46         // Boolean to enable bash completion commands
47         EnableBashCompletion bool
48         // Boolean to hide built-in help command
49         HideHelp bool
50         // Boolean to hide built-in version flag and the VERSION section of help
51         HideVersion bool
52         // Populate on app startup, only gettable through method Categories()
53         categories CommandCategories
54         // An action to execute when the bash-completion flag is set
55         BashComplete BashCompleteFunc
56         // An action to execute before any subcommands are run, but after the context is ready
57         // If a non-nil error is returned, no subcommands are run
58         Before BeforeFunc
59         // An action to execute after any subcommands are run, but after the subcommand has finished
60         // It is run even if Action() panics
61         After AfterFunc
62
63         // The action to execute when no subcommands are specified
64         // Expects a `cli.ActionFunc` but will accept the *deprecated* signature of `func(*cli.Context) {}`
65         // *Note*: support for the deprecated `Action` signature will be removed in a future version
66         Action interface{}
67
68         // Execute this function if the proper command cannot be found
69         CommandNotFound CommandNotFoundFunc
70         // Execute this function if an usage error occurs
71         OnUsageError OnUsageErrorFunc
72         // Compilation date
73         Compiled time.Time
74         // List of all authors who contributed
75         Authors []Author
76         // Copyright of the binary if any
77         Copyright string
78         // Name of Author (Note: Use App.Authors, this is deprecated)
79         Author string
80         // Email of Author (Note: Use App.Authors, this is deprecated)
81         Email string
82         // Writer writer to write output to
83         Writer io.Writer
84         // ErrWriter writes error output
85         ErrWriter io.Writer
86         // Other custom info
87         Metadata map[string]interface{}
88
89         didSetup bool
90 }
91
92 // Tries to find out when this binary was compiled.
93 // Returns the current time if it fails to find it.
94 func compileTime() time.Time {
95         info, err := os.Stat(os.Args[0])
96         if err != nil {
97                 return time.Now()
98         }
99         return info.ModTime()
100 }
101
102 // NewApp creates a new cli Application with some reasonable defaults for Name,
103 // Usage, Version and Action.
104 func NewApp() *App {
105         return &App{
106                 Name:         filepath.Base(os.Args[0]),
107                 HelpName:     filepath.Base(os.Args[0]),
108                 Usage:        "A new cli application",
109                 UsageText:    "",
110                 Version:      "0.0.0",
111                 BashComplete: DefaultAppComplete,
112                 Action:       helpCommand.Action,
113                 Compiled:     compileTime(),
114                 Writer:       os.Stdout,
115         }
116 }
117
118 // Setup runs initialization code to ensure all data structures are ready for
119 // `Run` or inspection prior to `Run`.  It is internally called by `Run`, but
120 // will return early if setup has already happened.
121 func (a *App) Setup() {
122         if a.didSetup {
123                 return
124         }
125
126         a.didSetup = true
127
128         if a.Author != "" || a.Email != "" {
129                 a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
130         }
131
132         newCmds := []Command{}
133         for _, c := range a.Commands {
134                 if c.HelpName == "" {
135                         c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
136                 }
137                 newCmds = append(newCmds, c)
138         }
139         a.Commands = newCmds
140
141         if a.Command(helpCommand.Name) == nil && !a.HideHelp {
142                 a.Commands = append(a.Commands, helpCommand)
143                 if (HelpFlag != BoolFlag{}) {
144                         a.appendFlag(HelpFlag)
145                 }
146         }
147
148         if !a.HideVersion {
149                 a.appendFlag(VersionFlag)
150         }
151
152         a.categories = CommandCategories{}
153         for _, command := range a.Commands {
154                 a.categories = a.categories.AddCommand(command.Category, command)
155         }
156         sort.Sort(a.categories)
157
158         if a.Metadata == nil {
159                 a.Metadata = make(map[string]interface{})
160         }
161
162         if a.Writer == nil {
163                 a.Writer = os.Stdout
164         }
165 }
166
167 // Run is the entry point to the cli app. Parses the arguments slice and routes
168 // to the proper flag/args combination
169 func (a *App) Run(arguments []string) (err error) {
170         a.Setup()
171
172         // handle the completion flag separately from the flagset since
173         // completion could be attempted after a flag, but before its value was put
174         // on the command line. this causes the flagset to interpret the completion
175         // flag name as the value of the flag before it which is undesirable
176         // note that we can only do this because the shell autocomplete function
177         // always appends the completion flag at the end of the command
178         shellComplete, arguments := checkShellCompleteFlag(a, arguments)
179
180         // parse flags
181         set, err := flagSet(a.Name, a.Flags)
182         if err != nil {
183                 return err
184         }
185
186         set.SetOutput(ioutil.Discard)
187         err = set.Parse(arguments[1:])
188         nerr := normalizeFlags(a.Flags, set)
189         context := NewContext(a, set, nil)
190         if nerr != nil {
191                 fmt.Fprintln(a.Writer, nerr)
192                 ShowAppHelp(context)
193                 return nerr
194         }
195         context.shellComplete = shellComplete
196
197         if checkCompletions(context) {
198                 return nil
199         }
200
201         if err != nil {
202                 if a.OnUsageError != nil {
203                         err := a.OnUsageError(context, err, false)
204                         HandleExitCoder(err)
205                         return err
206                 }
207                 fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
208                 ShowAppHelp(context)
209                 return err
210         }
211
212         if !a.HideHelp && checkHelp(context) {
213                 ShowAppHelp(context)
214                 return nil
215         }
216
217         if !a.HideVersion && checkVersion(context) {
218                 ShowVersion(context)
219                 return nil
220         }
221
222         if a.After != nil {
223                 defer func() {
224                         if afterErr := a.After(context); afterErr != nil {
225                                 if err != nil {
226                                         err = NewMultiError(err, afterErr)
227                                 } else {
228                                         err = afterErr
229                                 }
230                         }
231                 }()
232         }
233
234         if a.Before != nil {
235                 beforeErr := a.Before(context)
236                 if beforeErr != nil {
237                         fmt.Fprintf(a.Writer, "%v\n\n", beforeErr)
238                         ShowAppHelp(context)
239                         HandleExitCoder(beforeErr)
240                         err = beforeErr
241                         return err
242                 }
243         }
244
245         args := context.Args()
246         if args.Present() {
247                 name := args.First()
248                 c := a.Command(name)
249                 if c != nil {
250                         return c.Run(context)
251                 }
252         }
253
254         if a.Action == nil {
255                 a.Action = helpCommand.Action
256         }
257
258         // Run default Action
259         err = HandleAction(a.Action, context)
260
261         HandleExitCoder(err)
262         return err
263 }
264
265 // RunAndExitOnError calls .Run() and exits non-zero if an error was returned
266 //
267 // Deprecated: instead you should return an error that fulfills cli.ExitCoder
268 // to cli.App.Run. This will cause the application to exit with the given eror
269 // code in the cli.ExitCoder
270 func (a *App) RunAndExitOnError() {
271         if err := a.Run(os.Args); err != nil {
272                 fmt.Fprintln(a.errWriter(), err)
273                 OsExiter(1)
274         }
275 }
276
277 // RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to
278 // generate command-specific flags
279 func (a *App) RunAsSubcommand(ctx *Context) (err error) {
280         // append help to commands
281         if len(a.Commands) > 0 {
282                 if a.Command(helpCommand.Name) == nil && !a.HideHelp {
283                         a.Commands = append(a.Commands, helpCommand)
284                         if (HelpFlag != BoolFlag{}) {
285                                 a.appendFlag(HelpFlag)
286                         }
287                 }
288         }
289
290         newCmds := []Command{}
291         for _, c := range a.Commands {
292                 if c.HelpName == "" {
293                         c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
294                 }
295                 newCmds = append(newCmds, c)
296         }
297         a.Commands = newCmds
298
299         // parse flags
300         set, err := flagSet(a.Name, a.Flags)
301         if err != nil {
302                 return err
303         }
304
305         set.SetOutput(ioutil.Discard)
306         err = set.Parse(ctx.Args().Tail())
307         nerr := normalizeFlags(a.Flags, set)
308         context := NewContext(a, set, ctx)
309
310         if nerr != nil {
311                 fmt.Fprintln(a.Writer, nerr)
312                 fmt.Fprintln(a.Writer)
313                 if len(a.Commands) > 0 {
314                         ShowSubcommandHelp(context)
315                 } else {
316                         ShowCommandHelp(ctx, context.Args().First())
317                 }
318                 return nerr
319         }
320
321         if checkCompletions(context) {
322                 return nil
323         }
324
325         if err != nil {
326                 if a.OnUsageError != nil {
327                         err = a.OnUsageError(context, err, true)
328                         HandleExitCoder(err)
329                         return err
330                 }
331                 fmt.Fprintf(a.Writer, "%s %s\n\n", "Incorrect Usage.", err.Error())
332                 ShowSubcommandHelp(context)
333                 return err
334         }
335
336         if len(a.Commands) > 0 {
337                 if checkSubcommandHelp(context) {
338                         return nil
339                 }
340         } else {
341                 if checkCommandHelp(ctx, context.Args().First()) {
342                         return nil
343                 }
344         }
345
346         if a.After != nil {
347                 defer func() {
348                         afterErr := a.After(context)
349                         if afterErr != nil {
350                                 HandleExitCoder(err)
351                                 if err != nil {
352                                         err = NewMultiError(err, afterErr)
353                                 } else {
354                                         err = afterErr
355                                 }
356                         }
357                 }()
358         }
359
360         if a.Before != nil {
361                 beforeErr := a.Before(context)
362                 if beforeErr != nil {
363                         HandleExitCoder(beforeErr)
364                         err = beforeErr
365                         return err
366                 }
367         }
368
369         args := context.Args()
370         if args.Present() {
371                 name := args.First()
372                 c := a.Command(name)
373                 if c != nil {
374                         return c.Run(context)
375                 }
376         }
377
378         // Run default Action
379         err = HandleAction(a.Action, context)
380
381         HandleExitCoder(err)
382         return err
383 }
384
385 // Command returns the named command on App. Returns nil if the command does not exist
386 func (a *App) Command(name string) *Command {
387         for _, c := range a.Commands {
388                 if c.HasName(name) {
389                         return &c
390                 }
391         }
392
393         return nil
394 }
395
396 // Categories returns a slice containing all the categories with the commands they contain
397 func (a *App) Categories() CommandCategories {
398         return a.categories
399 }
400
401 // VisibleCategories returns a slice of categories and commands that are
402 // Hidden=false
403 func (a *App) VisibleCategories() []*CommandCategory {
404         ret := []*CommandCategory{}
405         for _, category := range a.categories {
406                 if visible := func() *CommandCategory {
407                         for _, command := range category.Commands {
408                                 if !command.Hidden {
409                                         return category
410                                 }
411                         }
412                         return nil
413                 }(); visible != nil {
414                         ret = append(ret, visible)
415                 }
416         }
417         return ret
418 }
419
420 // VisibleCommands returns a slice of the Commands with Hidden=false
421 func (a *App) VisibleCommands() []Command {
422         ret := []Command{}
423         for _, command := range a.Commands {
424                 if !command.Hidden {
425                         ret = append(ret, command)
426                 }
427         }
428         return ret
429 }
430
431 // VisibleFlags returns a slice of the Flags with Hidden=false
432 func (a *App) VisibleFlags() []Flag {
433         return visibleFlags(a.Flags)
434 }
435
436 func (a *App) hasFlag(flag Flag) bool {
437         for _, f := range a.Flags {
438                 if flag == f {
439                         return true
440                 }
441         }
442
443         return false
444 }
445
446 func (a *App) errWriter() io.Writer {
447
448         // When the app ErrWriter is nil use the package level one.
449         if a.ErrWriter == nil {
450                 return ErrWriter
451         }
452
453         return a.ErrWriter
454 }
455
456 func (a *App) appendFlag(flag Flag) {
457         if !a.hasFlag(flag) {
458                 a.Flags = append(a.Flags, flag)
459         }
460 }
461
462 // Author represents someone who has contributed to a cli project.
463 type Author struct {
464         Name  string // The Authors name
465         Email string // The Authors email
466 }
467
468 // String makes Author comply to the Stringer interface, to allow an easy print in the templating process
469 func (a Author) String() string {
470         e := ""
471         if a.Email != "" {
472                 e = " <" + a.Email + ">"
473         }
474
475         return fmt.Sprintf("%v%v", a.Name, e)
476 }
477
478 // HandleAction attempts to figure out which Action signature was used.  If
479 // it's an ActionFunc or a func with the legacy signature for Action, the func
480 // is run!
481 func HandleAction(action interface{}, context *Context) (err error) {
482         if a, ok := action.(ActionFunc); ok {
483                 return a(context)
484         } else if a, ok := action.(func(*Context) error); ok {
485                 return a(context)
486         } else if a, ok := action.(func(*Context)); ok { // deprecated function signature
487                 a(context)
488                 return nil
489         } else {
490                 return errInvalidActionType
491         }
492 }