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