You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1364 lines
31 KiB

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