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": ["--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": ["--help"],
383 "output": "--config FILE, -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": ["--help"],
424 "output": "--lang value, -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": ["--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": ["--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": ["--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", "--help"],
626 "output": "--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", "--generate-bash-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": ["--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": ["--halp"],
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": ["--print-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": ["--version"],
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