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