• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

altsrc/H11-Aug-2017-2,0871,632

autocomplete/H11-Aug-2017-2315

.flake8H A D11-Aug-201731 32

.gitignoreH A D11-Aug-201729 32

.travis.ymlH A D11-Aug-2017417 2823

CHANGELOG.mdH A D11-Aug-201715.8 KiB436360

LICENSEH A D11-Aug-20171.1 KiB2217

README.mdH A D11-Aug-201731.3 KiB1,3821,112

app.goH A D11-Aug-201712.1 KiB498358

app_test.goH A D11-Aug-201737.5 KiB1,7431,392

appveyor.ymlH A D11-Aug-2017460 2720

category.goH A D11-Aug-20171.1 KiB4533

cli.goH A D11-Aug-2017721 231

command.goH A D11-Aug-20177.4 KiB305216

command_test.goH A D11-Aug-20175.8 KiB241209

context.goH A D11-Aug-20176.3 KiB279209

context_test.goH A D11-Aug-201711.2 KiB404354

errors.goH A D11-Aug-20172.6 KiB11680

errors_test.goH A D11-Aug-20172.3 KiB12392

flag-types.jsonH A D11-Aug-20172.1 KiB9493

flag.goH A D11-Aug-201719.5 KiB800607

flag_generated.goH A D11-Aug-201713.5 KiB628442

flag_test.goH A D11-Aug-201730.5 KiB1,2161,094

funcs.goH A D11-Aug-20171.2 KiB298

generate-flag-typesH A D11-Aug-20178 KiB256204

help.goH A D11-Aug-20178.7 KiB339251

help_test.goH A D11-Aug-201710.1 KiB453375

helpers_test.goH A D11-Aug-2017594 2923

helpers_unix_test.goH A D11-Aug-2017126 105

helpers_windows_test.goH A D11-Aug-2017377 2116

runtestsH A D11-Aug-20172.9 KiB12386

README.md

1cli
2===
3
4[![Build Status](https://travis-ci.org/urfave/cli.svg?branch=master)](https://travis-ci.org/urfave/cli)
5[![Windows Build Status](https://ci.appveyor.com/api/projects/status/rtgk5xufi932pb2v?svg=true)](https://ci.appveyor.com/project/urfave/cli)
6[![GoDoc](https://godoc.org/github.com/urfave/cli?status.svg)](https://godoc.org/github.com/urfave/cli)
7[![codebeat](https://codebeat.co/badges/0a8f30aa-f975-404b-b878-5fab3ae1cc5f)](https://codebeat.co/projects/github-com-urfave-cli)
8[![Go Report Card](https://goreportcard.com/badge/urfave/cli)](https://goreportcard.com/report/urfave/cli)
9[![top level coverage](https://gocover.io/_badge/github.com/urfave/cli?0 "top level coverage")](http://gocover.io/github.com/urfave/cli) /
10[![altsrc coverage](https://gocover.io/_badge/github.com/urfave/cli/altsrc?0 "altsrc coverage")](http://gocover.io/github.com/urfave/cli/altsrc)
11
12**Notice:** This is the library formerly known as
13`github.com/codegangsta/cli` -- Github will automatically redirect requests
14to this repository, but we recommend updating your references for clarity.
15
16cli is a simple, fast, and fun package for building command line apps in Go. The
17goal is to enable developers to write fast and distributable command line
18applications in an expressive way.
19
20<!-- toc -->
21
22- [Overview](#overview)
23- [Installation](#installation)
24  * [Supported platforms](#supported-platforms)
25  * [Using the `v2` branch](#using-the-v2-branch)
26  * [Pinning to the `v1` releases](#pinning-to-the-v1-releases)
27- [Getting Started](#getting-started)
28- [Examples](#examples)
29  * [Arguments](#arguments)
30  * [Flags](#flags)
31    + [Placeholder Values](#placeholder-values)
32    + [Alternate Names](#alternate-names)
33    + [Ordering](#ordering)
34    + [Values from the Environment](#values-from-the-environment)
35    + [Values from alternate input sources (YAML, TOML, and others)](#values-from-alternate-input-sources-yaml-toml-and-others)
36  * [Subcommands](#subcommands)
37  * [Subcommands categories](#subcommands-categories)
38  * [Exit code](#exit-code)
39  * [Bash Completion](#bash-completion)
40    + [Enabling](#enabling)
41    + [Distribution](#distribution)
42    + [Customization](#customization)
43  * [Generated Help Text](#generated-help-text)
44    + [Customization](#customization-1)
45  * [Version Flag](#version-flag)
46    + [Customization](#customization-2)
47    + [Full API Example](#full-api-example)
48- [Contribution Guidelines](#contribution-guidelines)
49
50<!-- tocstop -->
51
52## Overview
53
54Command line apps are usually so tiny that there is absolutely no reason why
55your code should *not* be self-documenting. Things like generating help text and
56parsing command flags/options should not hinder productivity when writing a
57command line app.
58
59**This is where cli comes into play.** cli makes command line programming fun,
60organized, and expressive!
61
62## Installation
63
64Make sure you have a working Go environment.  Go version 1.2+ is supported.  [See
65the install instructions for Go](http://golang.org/doc/install.html).
66
67To install cli, simply run:
68```
69$ go get github.com/urfave/cli
70```
71
72Make sure your `PATH` includes the `$GOPATH/bin` directory so your commands can
73be easily used:
74```
75export PATH=$PATH:$GOPATH/bin
76```
77
78### Supported platforms
79
80cli is tested against multiple versions of Go on Linux, and against the latest
81released version of Go on OS X and Windows.  For full details, see
82[`./.travis.yml`](./.travis.yml) and [`./appveyor.yml`](./appveyor.yml).
83
84### Using the `v2` branch
85
86**Warning**: The `v2` branch is currently unreleased and considered unstable.
87
88There is currently a long-lived branch named `v2` that is intended to land as
89the new `master` branch once development there has settled down.  The current
90`master` branch (mirrored as `v1`) is being manually merged into `v2` on
91an irregular human-based schedule, but generally if one wants to "upgrade" to
92`v2` *now* and accept the volatility (read: "awesomeness") that comes along with
93that, please use whatever version pinning of your preference, such as via
94`gopkg.in`:
95
96```
97$ go get gopkg.in/urfave/cli.v2
98```
99
100``` go
101...
102import (
103  "gopkg.in/urfave/cli.v2" // imports as package "cli"
104)
105...
106```
107
108### Pinning to the `v1` releases
109
110Similarly to the section above describing use of the `v2` branch, if one wants
111to avoid any unexpected compatibility pains once `v2` becomes `master`, then
112pinning to `v1` is an acceptable option, e.g.:
113
114```
115$ go get gopkg.in/urfave/cli.v1
116```
117
118``` go
119...
120import (
121  "gopkg.in/urfave/cli.v1" // imports as package "cli"
122)
123...
124```
125
126This will pull the latest tagged `v1` release (e.g. `v1.18.1` at the time of writing).
127
128## Getting Started
129
130One of the philosophies behind cli is that an API should be playful and full of
131discovery. So a cli app can be as little as one line of code in `main()`.
132
133<!-- {
134  "args": ["&#45;&#45;help"],
135  "output": "A new cli application"
136} -->
137``` go
138package main
139
140import (
141  "os"
142
143  "github.com/urfave/cli"
144)
145
146func main() {
147  cli.NewApp().Run(os.Args)
148}
149```
150
151This app will run and show help text, but is not very useful. Let's give an
152action to execute and some help documentation:
153
154<!-- {
155  "output": "boom! I say!"
156} -->
157``` go
158package main
159
160import (
161  "fmt"
162  "os"
163
164  "github.com/urfave/cli"
165)
166
167func main() {
168  app := cli.NewApp()
169  app.Name = "boom"
170  app.Usage = "make an explosive entrance"
171  app.Action = func(c *cli.Context) error {
172    fmt.Println("boom! I say!")
173    return nil
174  }
175
176  app.Run(os.Args)
177}
178```
179
180Running this already gives you a ton of functionality, plus support for things
181like subcommands and flags, which are covered below.
182
183## Examples
184
185Being a programmer can be a lonely job. Thankfully by the power of automation
186that is not the case! Let's create a greeter app to fend off our demons of
187loneliness!
188
189Start by creating a directory named `greet`, and within it, add a file,
190`greet.go` with the following code in it:
191
192<!-- {
193  "output": "Hello friend!"
194} -->
195``` go
196package main
197
198import (
199  "fmt"
200  "os"
201
202  "github.com/urfave/cli"
203)
204
205func main() {
206  app := cli.NewApp()
207  app.Name = "greet"
208  app.Usage = "fight the loneliness!"
209  app.Action = func(c *cli.Context) error {
210    fmt.Println("Hello friend!")
211    return nil
212  }
213
214  app.Run(os.Args)
215}
216```
217
218Install our command to the `$GOPATH/bin` directory:
219
220```
221$ go install
222```
223
224Finally run our new command:
225
226```
227$ greet
228Hello friend!
229```
230
231cli also generates neat help text:
232
233```
234$ greet help
235NAME:
236    greet - fight the loneliness!
237
238USAGE:
239    greet [global options] command [command options] [arguments...]
240
241VERSION:
242    0.0.0
243
244COMMANDS:
245    help, h  Shows a list of commands or help for one command
246
247GLOBAL OPTIONS
248    --version Shows version information
249```
250
251### Arguments
252
253You can lookup arguments by calling the `Args` function on `cli.Context`, e.g.:
254
255<!-- {
256  "output": "Hello \""
257} -->
258``` go
259package main
260
261import (
262  "fmt"
263  "os"
264
265  "github.com/urfave/cli"
266)
267
268func main() {
269  app := cli.NewApp()
270
271  app.Action = func(c *cli.Context) error {
272    fmt.Printf("Hello %q", c.Args().Get(0))
273    return nil
274  }
275
276  app.Run(os.Args)
277}
278```
279
280### Flags
281
282Setting and querying flags is simple.
283
284<!-- {
285  "output": "Hello Nefertiti"
286} -->
287``` go
288package main
289
290import (
291  "fmt"
292  "os"
293
294  "github.com/urfave/cli"
295)
296
297func main() {
298  app := cli.NewApp()
299
300  app.Flags = []cli.Flag {
301    cli.StringFlag{
302      Name: "lang",
303      Value: "english",
304      Usage: "language for the greeting",
305    },
306  }
307
308  app.Action = func(c *cli.Context) error {
309    name := "Nefertiti"
310    if c.NArg() > 0 {
311      name = c.Args().Get(0)
312    }
313    if c.String("lang") == "spanish" {
314      fmt.Println("Hola", name)
315    } else {
316      fmt.Println("Hello", name)
317    }
318    return nil
319  }
320
321  app.Run(os.Args)
322}
323```
324
325You can also set a destination variable for a flag, to which the content will be
326scanned.
327
328<!-- {
329  "output": "Hello someone"
330} -->
331``` go
332package main
333
334import (
335  "os"
336  "fmt"
337
338  "github.com/urfave/cli"
339)
340
341func main() {
342  var language string
343
344  app := cli.NewApp()
345
346  app.Flags = []cli.Flag {
347    cli.StringFlag{
348      Name:        "lang",
349      Value:       "english",
350      Usage:       "language for the greeting",
351      Destination: &language,
352    },
353  }
354
355  app.Action = func(c *cli.Context) error {
356    name := "someone"
357    if c.NArg() > 0 {
358      name = c.Args()[0]
359    }
360    if language == "spanish" {
361      fmt.Println("Hola", name)
362    } else {
363      fmt.Println("Hello", name)
364    }
365    return nil
366  }
367
368  app.Run(os.Args)
369}
370```
371
372See full list of flags at http://godoc.org/github.com/urfave/cli
373
374#### Placeholder Values
375
376Sometimes it's useful to specify a flag's value within the usage string itself.
377Such placeholders are indicated with back quotes.
378
379For example this:
380
381<!-- {
382  "args": ["&#45;&#45;help"],
383  "output": "&#45;&#45;config FILE, &#45;c FILE"
384} -->
385```go
386package main
387
388import (
389  "os"
390
391  "github.com/urfave/cli"
392)
393
394func main() {
395  app := cli.NewApp()
396
397  app.Flags = []cli.Flag{
398    cli.StringFlag{
399      Name:  "config, c",
400      Usage: "Load configuration from `FILE`",
401    },
402  }
403
404  app.Run(os.Args)
405}
406```
407
408Will result in help output like:
409
410```
411--config FILE, -c FILE   Load configuration from FILE
412```
413
414Note that only the first placeholder is used. Subsequent back-quoted words will
415be left as-is.
416
417#### Alternate Names
418
419You can set alternate (or short) names for flags by providing a comma-delimited
420list for the `Name`. e.g.
421
422<!-- {
423  "args": ["&#45;&#45;help"],
424  "output": "&#45;&#45;lang value, &#45;l value.*language for the greeting.*default: \"english\""
425} -->
426``` go
427package main
428
429import (
430  "os"
431
432  "github.com/urfave/cli"
433)
434
435func main() {
436  app := cli.NewApp()
437
438  app.Flags = []cli.Flag {
439    cli.StringFlag{
440      Name: "lang, l",
441      Value: "english",
442      Usage: "language for the greeting",
443    },
444  }
445
446  app.Run(os.Args)
447}
448```
449
450That flag can then be set with `--lang spanish` or `-l spanish`. Note that
451giving two different forms of the same flag in the same command invocation is an
452error.
453
454#### Ordering
455
456Flags for the application and commands are shown in the order they are defined.
457However, it's possible to sort them from outside this library by using `FlagsByName`
458or `CommandsByName` with `sort`.
459
460For example this:
461
462<!-- {
463  "args": ["&#45;&#45;help"],
464  "output": "add a task to the list\n.*complete a task on the list\n.*\n\n.*\n.*Load configuration from FILE\n.*Language for the greeting.*"
465} -->
466``` go
467package main
468
469import (
470  "os"
471  "sort"
472
473  "github.com/urfave/cli"
474)
475
476func main() {
477  app := cli.NewApp()
478
479  app.Flags = []cli.Flag {
480    cli.StringFlag{
481      Name: "lang, l",
482      Value: "english",
483      Usage: "Language for the greeting",
484    },
485    cli.StringFlag{
486      Name: "config, c",
487      Usage: "Load configuration from `FILE`",
488    },
489  }
490
491  app.Commands = []cli.Command{
492    {
493      Name:    "complete",
494      Aliases: []string{"c"},
495      Usage:   "complete a task on the list",
496      Action:  func(c *cli.Context) error {
497        return nil
498      },
499    },
500    {
501      Name:    "add",
502      Aliases: []string{"a"},
503      Usage:   "add a task to the list",
504      Action:  func(c *cli.Context) error {
505        return nil
506      },
507    },
508  }
509
510  sort.Sort(cli.FlagsByName(app.Flags))
511  sort.Sort(cli.CommandsByName(app.Commands))
512
513  app.Run(os.Args)
514}
515```
516
517Will result in help output like:
518
519```
520--config FILE, -c FILE  Load configuration from FILE
521--lang value, -l value  Language for the greeting (default: "english")
522```
523
524#### Values from the Environment
525
526You can also have the default value set from the environment via `EnvVar`.  e.g.
527
528<!-- {
529  "args": ["&#45;&#45;help"],
530  "output": "language for the greeting.*APP_LANG"
531} -->
532``` go
533package main
534
535import (
536  "os"
537
538  "github.com/urfave/cli"
539)
540
541func main() {
542  app := cli.NewApp()
543
544  app.Flags = []cli.Flag {
545    cli.StringFlag{
546      Name: "lang, l",
547      Value: "english",
548      Usage: "language for the greeting",
549      EnvVar: "APP_LANG",
550    },
551  }
552
553  app.Run(os.Args)
554}
555```
556
557The `EnvVar` may also be given as a comma-delimited "cascade", where the first
558environment variable that resolves is used as the default.
559
560<!-- {
561  "args": ["&#45;&#45;help"],
562  "output": "language for the greeting.*LEGACY_COMPAT_LANG.*APP_LANG.*LANG"
563} -->
564``` go
565package main
566
567import (
568  "os"
569
570  "github.com/urfave/cli"
571)
572
573func main() {
574  app := cli.NewApp()
575
576  app.Flags = []cli.Flag {
577    cli.StringFlag{
578      Name: "lang, l",
579      Value: "english",
580      Usage: "language for the greeting",
581      EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG",
582    },
583  }
584
585  app.Run(os.Args)
586}
587```
588
589#### Values from alternate input sources (YAML, TOML, and others)
590
591There is a separate package altsrc that adds support for getting flag values
592from other file input sources.
593
594Currently supported input source formats:
595* YAML
596* TOML
597
598In order to get values for a flag from an alternate input source the following
599code would be added to wrap an existing cli.Flag like below:
600
601``` go
602  altsrc.NewIntFlag(cli.IntFlag{Name: "test"})
603```
604
605Initialization must also occur for these flags. Below is an example initializing
606getting data from a yaml file below.
607
608``` go
609  command.Before = altsrc.InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
610```
611
612The code above will use the "load" string as a flag name to get the file name of
613a yaml file from the cli.Context.  It will then use that file name to initialize
614the yaml input source for any flags that are defined on that command.  As a note
615the "load" flag used would also have to be defined on the command flags in order
616for this code snipped to work.
617
618Currently only the aboved specified formats are supported but developers can
619add support for other input sources by implementing the
620altsrc.InputSourceContext for their given sources.
621
622Here is a more complete sample of a command using YAML support:
623
624<!-- {
625  "args": ["test-cmd", "&#45;&#45;help"],
626  "output": "&#45&#45;test value.*default: 0"
627} -->
628``` go
629package notmain
630
631import (
632  "fmt"
633  "os"
634
635  "github.com/urfave/cli"
636  "github.com/urfave/cli/altsrc"
637)
638
639func main() {
640  app := cli.NewApp()
641
642  flags := []cli.Flag{
643    altsrc.NewIntFlag(cli.IntFlag{Name: "test"}),
644    cli.StringFlag{Name: "load"},
645  }
646
647  app.Action = func(c *cli.Context) error {
648    fmt.Println("yaml ist rad")
649    return nil
650  }
651
652  app.Before = altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc("load"))
653  app.Flags = flags
654
655  app.Run(os.Args)
656}
657```
658
659### Subcommands
660
661Subcommands can be defined for a more git-like command line app.
662
663<!-- {
664  "args": ["template", "add"],
665  "output": "new task template: .+"
666} -->
667```go
668package main
669
670import (
671  "fmt"
672  "os"
673
674  "github.com/urfave/cli"
675)
676
677func main() {
678  app := cli.NewApp()
679
680  app.Commands = []cli.Command{
681    {
682      Name:    "add",
683      Aliases: []string{"a"},
684      Usage:   "add a task to the list",
685      Action:  func(c *cli.Context) error {
686        fmt.Println("added task: ", c.Args().First())
687        return nil
688      },
689    },
690    {
691      Name:    "complete",
692      Aliases: []string{"c"},
693      Usage:   "complete a task on the list",
694      Action:  func(c *cli.Context) error {
695        fmt.Println("completed task: ", c.Args().First())
696        return nil
697      },
698    },
699    {
700      Name:        "template",
701      Aliases:     []string{"t"},
702      Usage:       "options for task templates",
703      Subcommands: []cli.Command{
704        {
705          Name:  "add",
706          Usage: "add a new template",
707          Action: func(c *cli.Context) error {
708            fmt.Println("new task template: ", c.Args().First())
709            return nil
710          },
711        },
712        {
713          Name:  "remove",
714          Usage: "remove an existing template",
715          Action: func(c *cli.Context) error {
716            fmt.Println("removed task template: ", c.Args().First())
717            return nil
718          },
719        },
720      },
721    },
722  }
723
724  app.Run(os.Args)
725}
726```
727
728### Subcommands categories
729
730For additional organization in apps that have many subcommands, you can
731associate a category for each command to group them together in the help
732output.
733
734E.g.
735
736```go
737package main
738
739import (
740  "os"
741
742  "github.com/urfave/cli"
743)
744
745func main() {
746  app := cli.NewApp()
747
748  app.Commands = []cli.Command{
749    {
750      Name: "noop",
751    },
752    {
753      Name:     "add",
754      Category: "template",
755    },
756    {
757      Name:     "remove",
758      Category: "template",
759    },
760  }
761
762  app.Run(os.Args)
763}
764```
765
766Will include:
767
768```
769COMMANDS:
770    noop
771
772  Template actions:
773    add
774    remove
775```
776
777### Exit code
778
779Calling `App.Run` will not automatically call `os.Exit`, which means that by
780default the exit code will "fall through" to being `0`.  An explicit exit code
781may be set by returning a non-nil error that fulfills `cli.ExitCoder`, *or* a
782`cli.MultiError` that includes an error that fulfills `cli.ExitCoder`, e.g.:
783
784``` go
785package main
786
787import (
788  "os"
789
790  "github.com/urfave/cli"
791)
792
793func main() {
794  app := cli.NewApp()
795  app.Flags = []cli.Flag{
796    cli.BoolTFlag{
797      Name:  "ginger-crouton",
798      Usage: "is it in the soup?",
799    },
800  }
801  app.Action = func(ctx *cli.Context) error {
802    if !ctx.Bool("ginger-crouton") {
803      return cli.NewExitError("it is not in the soup", 86)
804    }
805    return nil
806  }
807
808  app.Run(os.Args)
809}
810```
811
812### Bash Completion
813
814You can enable completion commands by setting the `EnableBashCompletion`
815flag on the `App` object.  By default, this setting will only auto-complete to
816show an app's subcommands, but you can write your own completion methods for
817the App or its subcommands.
818
819<!-- {
820  "args": ["complete", "&#45;&#45;generate&#45;bash&#45;completion"],
821  "output": "laundry"
822} -->
823``` go
824package main
825
826import (
827  "fmt"
828  "os"
829
830  "github.com/urfave/cli"
831)
832
833func main() {
834  tasks := []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
835
836  app := cli.NewApp()
837  app.EnableBashCompletion = true
838  app.Commands = []cli.Command{
839    {
840      Name:  "complete",
841      Aliases: []string{"c"},
842      Usage: "complete a task on the list",
843      Action: func(c *cli.Context) error {
844         fmt.Println("completed task: ", c.Args().First())
845         return nil
846      },
847      BashComplete: func(c *cli.Context) {
848        // This will complete if no args are passed
849        if c.NArg() > 0 {
850          return
851        }
852        for _, t := range tasks {
853          fmt.Println(t)
854        }
855      },
856    },
857  }
858
859  app.Run(os.Args)
860}
861```
862
863#### Enabling
864
865Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while
866setting the `PROG` variable to the name of your program:
867
868`PROG=myprogram source /.../cli/autocomplete/bash_autocomplete`
869
870#### Distribution
871
872Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename
873it to the name of the program you wish to add autocomplete support for (or
874automatically install it there if you are distributing a package). Don't forget
875to source the file to make it active in the current shell.
876
877```
878sudo cp src/bash_autocomplete /etc/bash_completion.d/<myprogram>
879source /etc/bash_completion.d/<myprogram>
880```
881
882Alternatively, you can just document that users should source the generic
883`autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set
884to the name of their program (as above).
885
886#### Customization
887
888The default bash completion flag (`--generate-bash-completion`) is defined as
889`cli.BashCompletionFlag`, and may be redefined if desired, e.g.:
890
891<!-- {
892  "args": ["&#45;&#45;compgen"],
893  "output": "wat\nhelp\nh"
894} -->
895``` go
896package main
897
898import (
899  "os"
900
901  "github.com/urfave/cli"
902)
903
904func main() {
905  cli.BashCompletionFlag = cli.BoolFlag{
906    Name:   "compgen",
907    Hidden: true,
908  }
909
910  app := cli.NewApp()
911  app.EnableBashCompletion = true
912  app.Commands = []cli.Command{
913    {
914      Name: "wat",
915    },
916  }
917  app.Run(os.Args)
918}
919```
920
921### Generated Help Text
922
923The default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked
924by the cli internals in order to print generated help text for the app, command,
925or subcommand, and break execution.
926
927#### Customization
928
929All of the help text generation may be customized, and at multiple levels.  The
930templates are exposed as variables `AppHelpTemplate`, `CommandHelpTemplate`, and
931`SubcommandHelpTemplate` which may be reassigned or augmented, and full override
932is possible by assigning a compatible func to the `cli.HelpPrinter` variable,
933e.g.:
934
935<!-- {
936  "output": "Ha HA.  I pwnd the help!!1"
937} -->
938``` go
939package main
940
941import (
942  "fmt"
943  "io"
944  "os"
945
946  "github.com/urfave/cli"
947)
948
949func main() {
950  // EXAMPLE: Append to an existing template
951  cli.AppHelpTemplate = fmt.Sprintf(`%s
952
953WEBSITE: http://awesometown.example.com
954
955SUPPORT: support@awesometown.example.com
956
957`, cli.AppHelpTemplate)
958
959  // EXAMPLE: Override a template
960  cli.AppHelpTemplate = `NAME:
961   {{.Name}} - {{.Usage}}
962USAGE:
963   {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
964   {{if len .Authors}}
965AUTHOR:
966   {{range .Authors}}{{ . }}{{end}}
967   {{end}}{{if .Commands}}
968COMMANDS:
969{{range .Commands}}{{if not .HideHelp}}   {{join .Names ", "}}{{ "\t"}}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
970GLOBAL OPTIONS:
971   {{range .VisibleFlags}}{{.}}
972   {{end}}{{end}}{{if .Copyright }}
973COPYRIGHT:
974   {{.Copyright}}
975   {{end}}{{if .Version}}
976VERSION:
977   {{.Version}}
978   {{end}}
979`
980
981  // EXAMPLE: Replace the `HelpPrinter` func
982  cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {
983    fmt.Println("Ha HA.  I pwnd the help!!1")
984  }
985
986  cli.NewApp().Run(os.Args)
987}
988```
989
990The default flag may be customized to something other than `-h/--help` by
991setting `cli.HelpFlag`, e.g.:
992
993<!-- {
994  "args": ["&#45;&#45halp"],
995  "output": "haaaaalp.*HALP"
996} -->
997``` go
998package main
999
1000import (
1001  "os"
1002
1003  "github.com/urfave/cli"
1004)
1005
1006func main() {
1007  cli.HelpFlag = cli.BoolFlag{
1008    Name: "halp, haaaaalp",
1009    Usage: "HALP",
1010    EnvVar: "SHOW_HALP,HALPPLZ",
1011  }
1012
1013  cli.NewApp().Run(os.Args)
1014}
1015```
1016
1017### Version Flag
1018
1019The default version flag (`-v/--version`) is defined as `cli.VersionFlag`, which
1020is checked by the cli internals in order to print the `App.Version` via
1021`cli.VersionPrinter` and break execution.
1022
1023#### Customization
1024
1025The default flag may be customized to something other than `-v/--version` by
1026setting `cli.VersionFlag`, e.g.:
1027
1028<!-- {
1029  "args": ["&#45;&#45print-version"],
1030  "output": "partay version 19\\.99\\.0"
1031} -->
1032``` go
1033package main
1034
1035import (
1036  "os"
1037
1038  "github.com/urfave/cli"
1039)
1040
1041func main() {
1042  cli.VersionFlag = cli.BoolFlag{
1043    Name: "print-version, V",
1044    Usage: "print only the version",
1045  }
1046
1047  app := cli.NewApp()
1048  app.Name = "partay"
1049  app.Version = "19.99.0"
1050  app.Run(os.Args)
1051}
1052```
1053
1054Alternatively, the version printer at `cli.VersionPrinter` may be overridden, e.g.:
1055
1056<!-- {
1057  "args": ["&#45;&#45version"],
1058  "output": "version=19\\.99\\.0 revision=fafafaf"
1059} -->
1060``` go
1061package main
1062
1063import (
1064  "fmt"
1065  "os"
1066
1067  "github.com/urfave/cli"
1068)
1069
1070var (
1071  Revision = "fafafaf"
1072)
1073
1074func main() {
1075  cli.VersionPrinter = func(c *cli.Context) {
1076    fmt.Printf("version=%s revision=%s\n", c.App.Version, Revision)
1077  }
1078
1079  app := cli.NewApp()
1080  app.Name = "partay"
1081  app.Version = "19.99.0"
1082  app.Run(os.Args)
1083}
1084```
1085
1086#### Full API Example
1087
1088**Notice**: This is a contrived (functioning) example meant strictly for API
1089demonstration purposes.  Use of one's imagination is encouraged.
1090
1091<!-- {
1092  "output": "made it!\nPhew!"
1093} -->
1094``` go
1095package main
1096
1097import (
1098  "errors"
1099  "flag"
1100  "fmt"
1101  "io"
1102  "io/ioutil"
1103  "os"
1104  "time"
1105
1106  "github.com/urfave/cli"
1107)
1108
1109func init() {
1110  cli.AppHelpTemplate += "\nCUSTOMIZED: you bet ur muffins\n"
1111  cli.CommandHelpTemplate += "\nYMMV\n"
1112  cli.SubcommandHelpTemplate += "\nor something\n"
1113
1114  cli.HelpFlag = cli.BoolFlag{Name: "halp"}
1115  cli.BashCompletionFlag = cli.BoolFlag{Name: "compgen", Hidden: true}
1116  cli.VersionFlag = cli.BoolFlag{Name: "print-version, V"}
1117
1118  cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {
1119    fmt.Fprintf(w, "best of luck to you\n")
1120  }
1121  cli.VersionPrinter = func(c *cli.Context) {
1122    fmt.Fprintf(c.App.Writer, "version=%s\n", c.App.Version)
1123  }
1124  cli.OsExiter = func(c int) {
1125    fmt.Fprintf(cli.ErrWriter, "refusing to exit %d\n", c)
1126  }
1127  cli.ErrWriter = ioutil.Discard
1128  cli.FlagStringer = func(fl cli.Flag) string {
1129    return fmt.Sprintf("\t\t%s", fl.GetName())
1130  }
1131}
1132
1133type hexWriter struct{}
1134
1135func (w *hexWriter) Write(p []byte) (int, error) {
1136  for _, b := range p {
1137    fmt.Printf("%x", b)
1138  }
1139  fmt.Printf("\n")
1140
1141  return len(p), nil
1142}
1143
1144type genericType struct{
1145  s string
1146}
1147
1148func (g *genericType) Set(value string) error {
1149  g.s = value
1150  return nil
1151}
1152
1153func (g *genericType) String() string {
1154  return g.s
1155}
1156
1157func main() {
1158  app := cli.NewApp()
1159  app.Name = "kənˈtrīv"
1160  app.Version = "19.99.0"
1161  app.Compiled = time.Now()
1162  app.Authors = []cli.Author{
1163    cli.Author{
1164      Name:  "Example Human",
1165      Email: "human@example.com",
1166    },
1167  }
1168  app.Copyright = "(c) 1999 Serious Enterprise"
1169  app.HelpName = "contrive"
1170  app.Usage = "demonstrate available API"
1171  app.UsageText = "contrive - demonstrating the available API"
1172  app.ArgsUsage = "[args and such]"
1173  app.Commands = []cli.Command{
1174    cli.Command{
1175      Name:        "doo",
1176      Aliases:     []string{"do"},
1177      Category:    "motion",
1178      Usage:       "do the doo",
1179      UsageText:   "doo - does the dooing",
1180      Description: "no really, there is a lot of dooing to be done",
1181      ArgsUsage:   "[arrgh]",
1182      Flags: []cli.Flag{
1183        cli.BoolFlag{Name: "forever, forevvarr"},
1184      },
1185      Subcommands: cli.Commands{
1186        cli.Command{
1187          Name:   "wop",
1188          Action: wopAction,
1189        },
1190      },
1191      SkipFlagParsing: false,
1192      HideHelp:        false,
1193      Hidden:          false,
1194      HelpName:        "doo!",
1195      BashComplete: func(c *cli.Context) {
1196        fmt.Fprintf(c.App.Writer, "--better\n")
1197      },
1198      Before: func(c *cli.Context) error {
1199        fmt.Fprintf(c.App.Writer, "brace for impact\n")
1200        return nil
1201      },
1202      After: func(c *cli.Context) error {
1203        fmt.Fprintf(c.App.Writer, "did we lose anyone?\n")
1204        return nil
1205      },
1206      Action: func(c *cli.Context) error {
1207        c.Command.FullName()
1208        c.Command.HasName("wop")
1209        c.Command.Names()
1210        c.Command.VisibleFlags()
1211        fmt.Fprintf(c.App.Writer, "dodododododoodododddooooododododooo\n")
1212        if c.Bool("forever") {
1213          c.Command.Run(c)
1214        }
1215        return nil
1216      },
1217      OnUsageError: func(c *cli.Context, err error, isSubcommand bool) error {
1218        fmt.Fprintf(c.App.Writer, "for shame\n")
1219        return err
1220      },
1221    },
1222  }
1223  app.Flags = []cli.Flag{
1224    cli.BoolFlag{Name: "fancy"},
1225    cli.BoolTFlag{Name: "fancier"},
1226    cli.DurationFlag{Name: "howlong, H", Value: time.Second * 3},
1227    cli.Float64Flag{Name: "howmuch"},
1228    cli.GenericFlag{Name: "wat", Value: &genericType{}},
1229    cli.Int64Flag{Name: "longdistance"},
1230    cli.Int64SliceFlag{Name: "intervals"},
1231    cli.IntFlag{Name: "distance"},
1232    cli.IntSliceFlag{Name: "times"},
1233    cli.StringFlag{Name: "dance-move, d"},
1234    cli.StringSliceFlag{Name: "names, N"},
1235    cli.UintFlag{Name: "age"},
1236    cli.Uint64Flag{Name: "bigage"},
1237  }
1238  app.EnableBashCompletion = true
1239  app.HideHelp = false
1240  app.HideVersion = false
1241  app.BashComplete = func(c *cli.Context) {
1242    fmt.Fprintf(c.App.Writer, "lipstick\nkiss\nme\nlipstick\nringo\n")
1243  }
1244  app.Before = func(c *cli.Context) error {
1245    fmt.Fprintf(c.App.Writer, "HEEEERE GOES\n")
1246    return nil
1247  }
1248  app.After = func(c *cli.Context) error {
1249    fmt.Fprintf(c.App.Writer, "Phew!\n")
1250    return nil
1251  }
1252  app.CommandNotFound = func(c *cli.Context, command string) {
1253    fmt.Fprintf(c.App.Writer, "Thar be no %q here.\n", command)
1254  }
1255  app.OnUsageError = func(c *cli.Context, err error, isSubcommand bool) error {
1256    if isSubcommand {
1257      return err
1258    }
1259
1260    fmt.Fprintf(c.App.Writer, "WRONG: %#v\n", err)
1261    return nil
1262  }
1263  app.Action = func(c *cli.Context) error {
1264    cli.DefaultAppComplete(c)
1265    cli.HandleExitCoder(errors.New("not an exit coder, though"))
1266    cli.ShowAppHelp(c)
1267    cli.ShowCommandCompletions(c, "nope")
1268    cli.ShowCommandHelp(c, "also-nope")
1269    cli.ShowCompletions(c)
1270    cli.ShowSubcommandHelp(c)
1271    cli.ShowVersion(c)
1272
1273    categories := c.App.Categories()
1274    categories.AddCommand("sounds", cli.Command{
1275      Name: "bloop",
1276    })
1277
1278    for _, category := range c.App.Categories() {
1279      fmt.Fprintf(c.App.Writer, "%s\n", category.Name)
1280      fmt.Fprintf(c.App.Writer, "%#v\n", category.Commands)
1281      fmt.Fprintf(c.App.Writer, "%#v\n", category.VisibleCommands())
1282    }
1283
1284    fmt.Printf("%#v\n", c.App.Command("doo"))
1285    if c.Bool("infinite") {
1286      c.App.Run([]string{"app", "doo", "wop"})
1287    }
1288
1289    if c.Bool("forevar") {
1290      c.App.RunAsSubcommand(c)
1291    }
1292    c.App.Setup()
1293    fmt.Printf("%#v\n", c.App.VisibleCategories())
1294    fmt.Printf("%#v\n", c.App.VisibleCommands())
1295    fmt.Printf("%#v\n", c.App.VisibleFlags())
1296
1297    fmt.Printf("%#v\n", c.Args().First())
1298    if len(c.Args()) > 0 {
1299      fmt.Printf("%#v\n", c.Args()[1])
1300    }
1301    fmt.Printf("%#v\n", c.Args().Present())
1302    fmt.Printf("%#v\n", c.Args().Tail())
1303
1304    set := flag.NewFlagSet("contrive", 0)
1305    nc := cli.NewContext(c.App, set, c)
1306
1307    fmt.Printf("%#v\n", nc.Args())
1308    fmt.Printf("%#v\n", nc.Bool("nope"))
1309    fmt.Printf("%#v\n", nc.BoolT("nerp"))
1310    fmt.Printf("%#v\n", nc.Duration("howlong"))
1311    fmt.Printf("%#v\n", nc.Float64("hay"))
1312    fmt.Printf("%#v\n", nc.Generic("bloop"))
1313    fmt.Printf("%#v\n", nc.Int64("bonk"))
1314    fmt.Printf("%#v\n", nc.Int64Slice("burnks"))
1315    fmt.Printf("%#v\n", nc.Int("bips"))
1316    fmt.Printf("%#v\n", nc.IntSlice("blups"))
1317    fmt.Printf("%#v\n", nc.String("snurt"))
1318    fmt.Printf("%#v\n", nc.StringSlice("snurkles"))
1319    fmt.Printf("%#v\n", nc.Uint("flub"))
1320    fmt.Printf("%#v\n", nc.Uint64("florb"))
1321    fmt.Printf("%#v\n", nc.GlobalBool("global-nope"))
1322    fmt.Printf("%#v\n", nc.GlobalBoolT("global-nerp"))
1323    fmt.Printf("%#v\n", nc.GlobalDuration("global-howlong"))
1324    fmt.Printf("%#v\n", nc.GlobalFloat64("global-hay"))
1325    fmt.Printf("%#v\n", nc.GlobalGeneric("global-bloop"))
1326    fmt.Printf("%#v\n", nc.GlobalInt("global-bips"))
1327    fmt.Printf("%#v\n", nc.GlobalIntSlice("global-blups"))
1328    fmt.Printf("%#v\n", nc.GlobalString("global-snurt"))
1329    fmt.Printf("%#v\n", nc.GlobalStringSlice("global-snurkles"))
1330
1331    fmt.Printf("%#v\n", nc.FlagNames())
1332    fmt.Printf("%#v\n", nc.GlobalFlagNames())
1333    fmt.Printf("%#v\n", nc.GlobalIsSet("wat"))
1334    fmt.Printf("%#v\n", nc.GlobalSet("wat", "nope"))
1335    fmt.Printf("%#v\n", nc.NArg())
1336    fmt.Printf("%#v\n", nc.NumFlags())
1337    fmt.Printf("%#v\n", nc.Parent())
1338
1339    nc.Set("wat", "also-nope")
1340
1341    ec := cli.NewExitError("ohwell", 86)
1342    fmt.Fprintf(c.App.Writer, "%d", ec.ExitCode())
1343    fmt.Printf("made it!\n")
1344    return ec
1345  }
1346
1347  if os.Getenv("HEXY") != "" {
1348    app.Writer = &hexWriter{}
1349    app.ErrWriter = &hexWriter{}
1350  }
1351
1352  app.Metadata = map[string]interface{}{
1353    "layers":     "many",
1354    "explicable": false,
1355    "whatever-values": 19.99,
1356  }
1357
1358  app.Run(os.Args)
1359}
1360
1361func wopAction(c *cli.Context) error {
1362  fmt.Fprintf(c.App.Writer, ":wave: over here, eh\n")
1363  return nil
1364}
1365```
1366
1367## Contribution Guidelines
1368
1369Feel free to put up a pull request to fix a bug or maybe add a feature. I will
1370give it a code review and make sure that it does not break backwards
1371compatibility. If I or any other collaborators agree that it is in line with
1372the vision of the project, we will work with you to get the code into
1373a mergeable state and merge it into the master branch.
1374
1375If you have contributed something significant to the project, we will most
1376likely add you as a collaborator. As a collaborator you are given the ability
1377to merge others pull requests. It is very important that new code does not
1378break existing code, so be careful about what code you do choose to merge.
1379
1380If you feel like you have contributed to the project but have not yet been
1381added as a collaborator, we probably forgot to add you, please open an issue.
1382