README.md

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