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.

README.md 31 KiB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381
  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. or `CommandsByName` with `sort`.
  353. For example this:
  354. <!-- {
  355. "args": ["&#45;&#45;help"],
  356. "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.*"
  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. app.Commands = []cli.Command{
  379. {
  380. Name: "complete",
  381. Aliases: []string{"c"},
  382. Usage: "complete a task on the list",
  383. Action: func(c *cli.Context) error {
  384. return nil
  385. },
  386. },
  387. {
  388. Name: "add",
  389. Aliases: []string{"a"},
  390. Usage: "add a task to the list",
  391. Action: func(c *cli.Context) error {
  392. return nil
  393. },
  394. },
  395. }
  396. sort.Sort(cli.FlagsByName(app.Flags))
  397. sort.Sort(cli.CommandsByName(app.Commands))
  398. app.Run(os.Args)
  399. }
  400. ```
  401. Will result in help output like:
  402. ```
  403. --config FILE, -c FILE Load configuration from FILE
  404. --lang value, -l value Language for the greeting (default: "english")
  405. ```
  406. #### Values from the Environment
  407. You can also have the default value set from the environment via `EnvVar`. e.g.
  408. <!-- {
  409. "args": ["&#45;&#45;help"],
  410. "output": "language for the greeting.*APP_LANG"
  411. } -->
  412. ``` go
  413. package main
  414. import (
  415. "os"
  416. "github.com/urfave/cli"
  417. )
  418. func main() {
  419. app := cli.NewApp()
  420. app.Flags = []cli.Flag {
  421. cli.StringFlag{
  422. Name: "lang, l",
  423. Value: "english",
  424. Usage: "language for the greeting",
  425. EnvVar: "APP_LANG",
  426. },
  427. }
  428. app.Run(os.Args)
  429. }
  430. ```
  431. The `EnvVar` may also be given as a comma-delimited "cascade", where the first
  432. environment variable that resolves is used as the default.
  433. <!-- {
  434. "args": ["&#45;&#45;help"],
  435. "output": "language for the greeting.*LEGACY_COMPAT_LANG.*APP_LANG.*LANG"
  436. } -->
  437. ``` go
  438. package main
  439. import (
  440. "os"
  441. "github.com/urfave/cli"
  442. )
  443. func main() {
  444. app := cli.NewApp()
  445. app.Flags = []cli.Flag {
  446. cli.StringFlag{
  447. Name: "lang, l",
  448. Value: "english",
  449. Usage: "language for the greeting",
  450. EnvVar: "LEGACY_COMPAT_LANG,APP_LANG,LANG",
  451. },
  452. }
  453. app.Run(os.Args)
  454. }
  455. ```
  456. #### Values from alternate input sources (YAML, TOML, and others)
  457. There is a separate package altsrc that adds support for getting flag values
  458. from other file input sources.
  459. Currently supported input source formats:
  460. * YAML
  461. * TOML
  462. In order to get values for a flag from an alternate input source the following
  463. code would be added to wrap an existing cli.Flag like below:
  464. ``` go
  465. altsrc.NewIntFlag(cli.IntFlag{Name: "test"})
  466. ```
  467. Initialization must also occur for these flags. Below is an example initializing
  468. getting data from a yaml file below.
  469. ``` go
  470. command.Before = altsrc.InitInputSourceWithContext(command.Flags, NewYamlSourceFromFlagFunc("load"))
  471. ```
  472. The code above will use the "load" string as a flag name to get the file name of
  473. a yaml file from the cli.Context. It will then use that file name to initialize
  474. the yaml input source for any flags that are defined on that command. As a note
  475. the "load" flag used would also have to be defined on the command flags in order
  476. for this code snipped to work.
  477. Currently only the aboved specified formats are supported but developers can
  478. add support for other input sources by implementing the
  479. altsrc.InputSourceContext for their given sources.
  480. Here is a more complete sample of a command using YAML support:
  481. <!-- {
  482. "args": ["test-cmd", "&#45;&#45;help"],
  483. "output": "&#45&#45;test value.*default: 0"
  484. } -->
  485. ``` go
  486. package notmain
  487. import (
  488. "fmt"
  489. "os"
  490. "github.com/urfave/cli"
  491. "github.com/urfave/cli/altsrc"
  492. )
  493. func main() {
  494. app := cli.NewApp()
  495. flags := []cli.Flag{
  496. altsrc.NewIntFlag(cli.IntFlag{Name: "test"}),
  497. cli.StringFlag{Name: "load"},
  498. }
  499. app.Action = func(c *cli.Context) error {
  500. fmt.Println("yaml ist rad")
  501. return nil
  502. }
  503. app.Before = altsrc.InitInputSourceWithContext(flags, altsrc.NewYamlSourceFromFlagFunc("load"))
  504. app.Flags = flags
  505. app.Run(os.Args)
  506. }
  507. ```
  508. ### Subcommands
  509. Subcommands can be defined for a more git-like command line app.
  510. <!-- {
  511. "args": ["template", "add"],
  512. "output": "new task template: .+"
  513. } -->
  514. ```go
  515. package main
  516. import (
  517. "fmt"
  518. "os"
  519. "github.com/urfave/cli"
  520. )
  521. func main() {
  522. app := cli.NewApp()
  523. app.Commands = []cli.Command{
  524. {
  525. Name: "add",
  526. Aliases: []string{"a"},
  527. Usage: "add a task to the list",
  528. Action: func(c *cli.Context) error {
  529. fmt.Println("added task: ", c.Args().First())
  530. return nil
  531. },
  532. },
  533. {
  534. Name: "complete",
  535. Aliases: []string{"c"},
  536. Usage: "complete a task on the list",
  537. Action: func(c *cli.Context) error {
  538. fmt.Println("completed task: ", c.Args().First())
  539. return nil
  540. },
  541. },
  542. {
  543. Name: "template",
  544. Aliases: []string{"t"},
  545. Usage: "options for task templates",
  546. Subcommands: []cli.Command{
  547. {
  548. Name: "add",
  549. Usage: "add a new template",
  550. Action: func(c *cli.Context) error {
  551. fmt.Println("new task template: ", c.Args().First())
  552. return nil
  553. },
  554. },
  555. {
  556. Name: "remove",
  557. Usage: "remove an existing template",
  558. Action: func(c *cli.Context) error {
  559. fmt.Println("removed task template: ", c.Args().First())
  560. return nil
  561. },
  562. },
  563. },
  564. },
  565. }
  566. app.Run(os.Args)
  567. }
  568. ```
  569. ### Subcommands categories
  570. For additional organization in apps that have many subcommands, you can
  571. associate a category for each command to group them together in the help
  572. output.
  573. E.g.
  574. ```go
  575. package main
  576. import (
  577. "os"
  578. "github.com/urfave/cli"
  579. )
  580. func main() {
  581. app := cli.NewApp()
  582. app.Commands = []cli.Command{
  583. {
  584. Name: "noop",
  585. },
  586. {
  587. Name: "add",
  588. Category: "template",
  589. },
  590. {
  591. Name: "remove",
  592. Category: "template",
  593. },
  594. }
  595. app.Run(os.Args)
  596. }
  597. ```
  598. Will include:
  599. ```
  600. COMMANDS:
  601. noop
  602. Template actions:
  603. add
  604. remove
  605. ```
  606. ### Exit code
  607. Calling `App.Run` will not automatically call `os.Exit`, which means that by
  608. default the exit code will "fall through" to being `0`. An explicit exit code
  609. may be set by returning a non-nil error that fulfills `cli.ExitCoder`, *or* a
  610. `cli.MultiError` that includes an error that fulfills `cli.ExitCoder`, e.g.:
  611. ``` go
  612. package main
  613. import (
  614. "os"
  615. "github.com/urfave/cli"
  616. )
  617. func main() {
  618. app := cli.NewApp()
  619. app.Flags = []cli.Flag{
  620. cli.BoolTFlag{
  621. Name: "ginger-crouton",
  622. Usage: "is it in the soup?",
  623. },
  624. }
  625. app.Action = func(ctx *cli.Context) error {
  626. if !ctx.Bool("ginger-crouton") {
  627. return cli.NewExitError("it is not in the soup", 86)
  628. }
  629. return nil
  630. }
  631. app.Run(os.Args)
  632. }
  633. ```
  634. ### Bash Completion
  635. You can enable completion commands by setting the `EnableBashCompletion`
  636. flag on the `App` object. By default, this setting will only auto-complete to
  637. show an app's subcommands, but you can write your own completion methods for
  638. the App or its subcommands.
  639. <!-- {
  640. "args": ["complete", "&#45;&#45;generate&#45;bash&#45;completion"],
  641. "output": "laundry"
  642. } -->
  643. ``` go
  644. package main
  645. import (
  646. "fmt"
  647. "os"
  648. "github.com/urfave/cli"
  649. )
  650. func main() {
  651. tasks := []string{"cook", "clean", "laundry", "eat", "sleep", "code"}
  652. app := cli.NewApp()
  653. app.EnableBashCompletion = true
  654. app.Commands = []cli.Command{
  655. {
  656. Name: "complete",
  657. Aliases: []string{"c"},
  658. Usage: "complete a task on the list",
  659. Action: func(c *cli.Context) error {
  660. fmt.Println("completed task: ", c.Args().First())
  661. return nil
  662. },
  663. BashComplete: func(c *cli.Context) {
  664. // This will complete if no args are passed
  665. if c.NArg() > 0 {
  666. return
  667. }
  668. for _, t := range tasks {
  669. fmt.Println(t)
  670. }
  671. },
  672. },
  673. }
  674. app.Run(os.Args)
  675. }
  676. ```
  677. #### Enabling
  678. Source the `autocomplete/bash_autocomplete` file in your `.bashrc` file while
  679. setting the `PROG` variable to the name of your program:
  680. `PROG=myprogram source /.../cli/autocomplete/bash_autocomplete`
  681. #### Distribution
  682. Copy `autocomplete/bash_autocomplete` into `/etc/bash_completion.d/` and rename
  683. it to the name of the program you wish to add autocomplete support for (or
  684. automatically install it there if you are distributing a package). Don't forget
  685. to source the file to make it active in the current shell.
  686. ```
  687. sudo cp src/bash_autocomplete /etc/bash_completion.d/<myprogram>
  688. source /etc/bash_completion.d/<myprogram>
  689. ```
  690. Alternatively, you can just document that users should source the generic
  691. `autocomplete/bash_autocomplete` in their bash configuration with `$PROG` set
  692. to the name of their program (as above).
  693. #### Customization
  694. The default bash completion flag (`--generate-bash-completion`) is defined as
  695. `cli.BashCompletionFlag`, and may be redefined if desired, e.g.:
  696. <!-- {
  697. "args": ["&#45;&#45;compgen"],
  698. "output": "wat\nhelp\nh"
  699. } -->
  700. ``` go
  701. package main
  702. import (
  703. "os"
  704. "github.com/urfave/cli"
  705. )
  706. func main() {
  707. cli.BashCompletionFlag = cli.BoolFlag{
  708. Name: "compgen",
  709. Hidden: true,
  710. }
  711. app := cli.NewApp()
  712. app.EnableBashCompletion = true
  713. app.Commands = []cli.Command{
  714. {
  715. Name: "wat",
  716. },
  717. }
  718. app.Run(os.Args)
  719. }
  720. ```
  721. ### Generated Help Text
  722. The default help flag (`-h/--help`) is defined as `cli.HelpFlag` and is checked
  723. by the cli internals in order to print generated help text for the app, command,
  724. or subcommand, and break execution.
  725. #### Customization
  726. All of the help text generation may be customized, and at multiple levels. The
  727. templates are exposed as variables `AppHelpTemplate`, `CommandHelpTemplate`, and
  728. `SubcommandHelpTemplate` which may be reassigned or augmented, and full override
  729. is possible by assigning a compatible func to the `cli.HelpPrinter` variable,
  730. e.g.:
  731. <!-- {
  732. "output": "Ha HA. I pwnd the help!!1"
  733. } -->
  734. ``` go
  735. package main
  736. import (
  737. "fmt"
  738. "io"
  739. "os"
  740. "github.com/urfave/cli"
  741. )
  742. func main() {
  743. // EXAMPLE: Append to an existing template
  744. cli.AppHelpTemplate = fmt.Sprintf(`%s
  745. WEBSITE: http://awesometown.example.com
  746. SUPPORT: support@awesometown.example.com
  747. `, cli.AppHelpTemplate)
  748. // EXAMPLE: Override a template
  749. cli.AppHelpTemplate = `NAME:
  750. {{.Name}} - {{.Usage}}
  751. USAGE:
  752. {{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
  753. {{if len .Authors}}
  754. AUTHOR:
  755. {{range .Authors}}{{ . }}{{end}}
  756. {{end}}{{if .Commands}}
  757. COMMANDS:
  758. {{range .Commands}}{{if not .HideHelp}} {{join .Names ", "}}{{ "\t"}}{{.Usage}}{{ "\n" }}{{end}}{{end}}{{end}}{{if .VisibleFlags}}
  759. GLOBAL OPTIONS:
  760. {{range .VisibleFlags}}{{.}}
  761. {{end}}{{end}}{{if .Copyright }}
  762. COPYRIGHT:
  763. {{.Copyright}}
  764. {{end}}{{if .Version}}
  765. VERSION:
  766. {{.Version}}
  767. {{end}}
  768. `
  769. // EXAMPLE: Replace the `HelpPrinter` func
  770. cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {
  771. fmt.Println("Ha HA. I pwnd the help!!1")
  772. }
  773. cli.NewApp().Run(os.Args)
  774. }
  775. ```
  776. The default flag may be customized to something other than `-h/--help` by
  777. setting `cli.HelpFlag`, e.g.:
  778. <!-- {
  779. "args": ["&#45;&#45halp"],
  780. "output": "haaaaalp.*HALP"
  781. } -->
  782. ``` go
  783. package main
  784. import (
  785. "os"
  786. "github.com/urfave/cli"
  787. )
  788. func main() {
  789. cli.HelpFlag = cli.BoolFlag{
  790. Name: "halp, haaaaalp",
  791. Usage: "HALP",
  792. EnvVar: "SHOW_HALP,HALPPLZ",
  793. }
  794. cli.NewApp().Run(os.Args)
  795. }
  796. ```
  797. ### Version Flag
  798. The default version flag (`-v/--version`) is defined as `cli.VersionFlag`, which
  799. is checked by the cli internals in order to print the `App.Version` via
  800. `cli.VersionPrinter` and break execution.
  801. #### Customization
  802. The default flag may be customized to something other than `-v/--version` by
  803. setting `cli.VersionFlag`, e.g.:
  804. <!-- {
  805. "args": ["&#45;&#45print-version"],
  806. "output": "partay version 19\\.99\\.0"
  807. } -->
  808. ``` go
  809. package main
  810. import (
  811. "os"
  812. "github.com/urfave/cli"
  813. )
  814. func main() {
  815. cli.VersionFlag = cli.BoolFlag{
  816. Name: "print-version, V",
  817. Usage: "print only the version",
  818. }
  819. app := cli.NewApp()
  820. app.Name = "partay"
  821. app.Version = "19.99.0"
  822. app.Run(os.Args)
  823. }
  824. ```
  825. Alternatively, the version printer at `cli.VersionPrinter` may be overridden, e.g.:
  826. <!-- {
  827. "args": ["&#45;&#45version"],
  828. "output": "version=19\\.99\\.0 revision=fafafaf"
  829. } -->
  830. ``` go
  831. package main
  832. import (
  833. "fmt"
  834. "os"
  835. "github.com/urfave/cli"
  836. )
  837. var (
  838. Revision = "fafafaf"
  839. )
  840. func main() {
  841. cli.VersionPrinter = func(c *cli.Context) {
  842. fmt.Printf("version=%s revision=%s\n", c.App.Version, Revision)
  843. }
  844. app := cli.NewApp()
  845. app.Name = "partay"
  846. app.Version = "19.99.0"
  847. app.Run(os.Args)
  848. }
  849. ```
  850. #### Full API Example
  851. **Notice**: This is a contrived (functioning) example meant strictly for API
  852. demonstration purposes. Use of one's imagination is encouraged.
  853. <!-- {
  854. "output": "made it!\nPhew!"
  855. } -->
  856. ``` go
  857. package main
  858. import (
  859. "errors"
  860. "flag"
  861. "fmt"
  862. "io"
  863. "io/ioutil"
  864. "os"
  865. "time"
  866. "github.com/urfave/cli"
  867. )
  868. func init() {
  869. cli.AppHelpTemplate += "\nCUSTOMIZED: you bet ur muffins\n"
  870. cli.CommandHelpTemplate += "\nYMMV\n"
  871. cli.SubcommandHelpTemplate += "\nor something\n"
  872. cli.HelpFlag = cli.BoolFlag{Name: "halp"}
  873. cli.BashCompletionFlag = cli.BoolFlag{Name: "compgen", Hidden: true}
  874. cli.VersionFlag = cli.BoolFlag{Name: "print-version, V"}
  875. cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {
  876. fmt.Fprintf(w, "best of luck to you\n")
  877. }
  878. cli.VersionPrinter = func(c *cli.Context) {
  879. fmt.Fprintf(c.App.Writer, "version=%s\n", c.App.Version)
  880. }
  881. cli.OsExiter = func(c int) {
  882. fmt.Fprintf(cli.ErrWriter, "refusing to exit %d\n", c)
  883. }
  884. cli.ErrWriter = ioutil.Discard
  885. cli.FlagStringer = func(fl cli.Flag) string {
  886. return fmt.Sprintf("\t\t%s", fl.GetName())
  887. }
  888. }
  889. type hexWriter struct{}
  890. func (w *hexWriter) Write(p []byte) (int, error) {
  891. for _, b := range p {
  892. fmt.Printf("%x", b)
  893. }
  894. fmt.Printf("\n")
  895. return len(p), nil
  896. }
  897. type genericType struct{
  898. s string
  899. }
  900. func (g *genericType) Set(value string) error {
  901. g.s = value
  902. return nil
  903. }
  904. func (g *genericType) String() string {
  905. return g.s
  906. }
  907. func main() {
  908. app := cli.NewApp()
  909. app.Name = "kənˈtrīv"
  910. app.Version = "19.99.0"
  911. app.Compiled = time.Now()
  912. app.Authors = []cli.Author{
  913. cli.Author{
  914. Name: "Example Human",
  915. Email: "human@example.com",
  916. },
  917. }
  918. app.Copyright = "(c) 1999 Serious Enterprise"
  919. app.HelpName = "contrive"
  920. app.Usage = "demonstrate available API"
  921. app.UsageText = "contrive - demonstrating the available API"
  922. app.ArgsUsage = "[args and such]"
  923. app.Commands = []cli.Command{
  924. cli.Command{
  925. Name: "doo",
  926. Aliases: []string{"do"},
  927. Category: "motion",
  928. Usage: "do the doo",
  929. UsageText: "doo - does the dooing",
  930. Description: "no really, there is a lot of dooing to be done",
  931. ArgsUsage: "[arrgh]",
  932. Flags: []cli.Flag{
  933. cli.BoolFlag{Name: "forever, forevvarr"},
  934. },
  935. Subcommands: cli.Commands{
  936. cli.Command{
  937. Name: "wop",
  938. Action: wopAction,
  939. },
  940. },
  941. SkipFlagParsing: false,
  942. HideHelp: false,
  943. Hidden: false,
  944. HelpName: "doo!",
  945. BashComplete: func(c *cli.Context) {
  946. fmt.Fprintf(c.App.Writer, "--better\n")
  947. },
  948. Before: func(c *cli.Context) error {
  949. fmt.Fprintf(c.App.Writer, "brace for impact\n")
  950. return nil
  951. },
  952. After: func(c *cli.Context) error {
  953. fmt.Fprintf(c.App.Writer, "did we lose anyone?\n")
  954. return nil
  955. },
  956. Action: func(c *cli.Context) error {
  957. c.Command.FullName()
  958. c.Command.HasName("wop")
  959. c.Command.Names()
  960. c.Command.VisibleFlags()
  961. fmt.Fprintf(c.App.Writer, "dodododododoodododddooooododododooo\n")
  962. if c.Bool("forever") {
  963. c.Command.Run(c)
  964. }
  965. return nil
  966. },
  967. OnUsageError: func(c *cli.Context, err error, isSubcommand bool) error {
  968. fmt.Fprintf(c.App.Writer, "for shame\n")
  969. return err
  970. },
  971. },
  972. }
  973. app.Flags = []cli.Flag{
  974. cli.BoolFlag{Name: "fancy"},
  975. cli.BoolTFlag{Name: "fancier"},
  976. cli.DurationFlag{Name: "howlong, H", Value: time.Second * 3},
  977. cli.Float64Flag{Name: "howmuch"},
  978. cli.GenericFlag{Name: "wat", Value: &genericType{}},
  979. cli.Int64Flag{Name: "longdistance"},
  980. cli.Int64SliceFlag{Name: "intervals"},
  981. cli.IntFlag{Name: "distance"},
  982. cli.IntSliceFlag{Name: "times"},
  983. cli.StringFlag{Name: "dance-move, d"},
  984. cli.StringSliceFlag{Name: "names, N"},
  985. cli.UintFlag{Name: "age"},
  986. cli.Uint64Flag{Name: "bigage"},
  987. }
  988. app.EnableBashCompletion = true
  989. app.HideHelp = false
  990. app.HideVersion = false
  991. app.BashComplete = func(c *cli.Context) {
  992. fmt.Fprintf(c.App.Writer, "lipstick\nkiss\nme\nlipstick\nringo\n")
  993. }
  994. app.Before = func(c *cli.Context) error {
  995. fmt.Fprintf(c.App.Writer, "HEEEERE GOES\n")
  996. return nil
  997. }
  998. app.After = func(c *cli.Context) error {
  999. fmt.Fprintf(c.App.Writer, "Phew!\n")
  1000. return nil
  1001. }
  1002. app.CommandNotFound = func(c *cli.Context, command string) {
  1003. fmt.Fprintf(c.App.Writer, "Thar be no %q here.\n", command)
  1004. }
  1005. app.OnUsageError = func(c *cli.Context, err error, isSubcommand bool) error {
  1006. if isSubcommand {
  1007. return err
  1008. }
  1009. fmt.Fprintf(c.App.Writer, "WRONG: %#v\n", err)
  1010. return nil
  1011. }
  1012. app.Action = func(c *cli.Context) error {
  1013. cli.DefaultAppComplete(c)
  1014. cli.HandleExitCoder(errors.New("not an exit coder, though"))
  1015. cli.ShowAppHelp(c)
  1016. cli.ShowCommandCompletions(c, "nope")
  1017. cli.ShowCommandHelp(c, "also-nope")
  1018. cli.ShowCompletions(c)
  1019. cli.ShowSubcommandHelp(c)
  1020. cli.ShowVersion(c)
  1021. categories := c.App.Categories()
  1022. categories.AddCommand("sounds", cli.Command{
  1023. Name: "bloop",
  1024. })
  1025. for _, category := range c.App.Categories() {
  1026. fmt.Fprintf(c.App.Writer, "%s\n", category.Name)
  1027. fmt.Fprintf(c.App.Writer, "%#v\n", category.Commands)
  1028. fmt.Fprintf(c.App.Writer, "%#v\n", category.VisibleCommands())
  1029. }
  1030. fmt.Printf("%#v\n", c.App.Command("doo"))
  1031. if c.Bool("infinite") {
  1032. c.App.Run([]string{"app", "doo", "wop"})
  1033. }
  1034. if c.Bool("forevar") {
  1035. c.App.RunAsSubcommand(c)
  1036. }
  1037. c.App.Setup()
  1038. fmt.Printf("%#v\n", c.App.VisibleCategories())
  1039. fmt.Printf("%#v\n", c.App.VisibleCommands())
  1040. fmt.Printf("%#v\n", c.App.VisibleFlags())
  1041. fmt.Printf("%#v\n", c.Args().First())
  1042. if len(c.Args()) > 0 {
  1043. fmt.Printf("%#v\n", c.Args()[1])
  1044. }
  1045. fmt.Printf("%#v\n", c.Args().Present())
  1046. fmt.Printf("%#v\n", c.Args().Tail())
  1047. set := flag.NewFlagSet("contrive", 0)
  1048. nc := cli.NewContext(c.App, set, c)
  1049. fmt.Printf("%#v\n", nc.Args())
  1050. fmt.Printf("%#v\n", nc.Bool("nope"))
  1051. fmt.Printf("%#v\n", nc.BoolT("nerp"))
  1052. fmt.Printf("%#v\n", nc.Duration("howlong"))
  1053. fmt.Printf("%#v\n", nc.Float64("hay"))
  1054. fmt.Printf("%#v\n", nc.Generic("bloop"))
  1055. fmt.Printf("%#v\n", nc.Int64("bonk"))
  1056. fmt.Printf("%#v\n", nc.Int64Slice("burnks"))
  1057. fmt.Printf("%#v\n", nc.Int("bips"))
  1058. fmt.Printf("%#v\n", nc.IntSlice("blups"))
  1059. fmt.Printf("%#v\n", nc.String("snurt"))
  1060. fmt.Printf("%#v\n", nc.StringSlice("snurkles"))
  1061. fmt.Printf("%#v\n", nc.Uint("flub"))
  1062. fmt.Printf("%#v\n", nc.Uint64("florb"))
  1063. fmt.Printf("%#v\n", nc.GlobalBool("global-nope"))
  1064. fmt.Printf("%#v\n", nc.GlobalBoolT("global-nerp"))
  1065. fmt.Printf("%#v\n", nc.GlobalDuration("global-howlong"))
  1066. fmt.Printf("%#v\n", nc.GlobalFloat64("global-hay"))
  1067. fmt.Printf("%#v\n", nc.GlobalGeneric("global-bloop"))
  1068. fmt.Printf("%#v\n", nc.GlobalInt("global-bips"))
  1069. fmt.Printf("%#v\n", nc.GlobalIntSlice("global-blups"))
  1070. fmt.Printf("%#v\n", nc.GlobalString("global-snurt"))
  1071. fmt.Printf("%#v\n", nc.GlobalStringSlice("global-snurkles"))
  1072. fmt.Printf("%#v\n", nc.FlagNames())
  1073. fmt.Printf("%#v\n", nc.GlobalFlagNames())
  1074. fmt.Printf("%#v\n", nc.GlobalIsSet("wat"))
  1075. fmt.Printf("%#v\n", nc.GlobalSet("wat", "nope"))
  1076. fmt.Printf("%#v\n", nc.NArg())
  1077. fmt.Printf("%#v\n", nc.NumFlags())
  1078. fmt.Printf("%#v\n", nc.Parent())
  1079. nc.Set("wat", "also-nope")
  1080. ec := cli.NewExitError("ohwell", 86)
  1081. fmt.Fprintf(c.App.Writer, "%d", ec.ExitCode())
  1082. fmt.Printf("made it!\n")
  1083. return ec
  1084. }
  1085. if os.Getenv("HEXY") != "" {
  1086. app.Writer = &hexWriter{}
  1087. app.ErrWriter = &hexWriter{}
  1088. }
  1089. app.Metadata = map[string]interface{}{
  1090. "layers": "many",
  1091. "explicable": false,
  1092. "whatever-values": 19.99,
  1093. }
  1094. app.Run(os.Args)
  1095. }
  1096. func wopAction(c *cli.Context) error {
  1097. fmt.Fprintf(c.App.Writer, ":wave: over here, eh\n")
  1098. return nil
  1099. }
  1100. ```
  1101. ## Contribution Guidelines
  1102. Feel free to put up a pull request to fix a bug or maybe add a feature. I will
  1103. give it a code review and make sure that it does not break backwards
  1104. compatibility. If I or any other collaborators agree that it is in line with
  1105. the vision of the project, we will work with you to get the code into
  1106. a mergeable state and merge it into the master branch.
  1107. If you have contributed something significant to the project, we will most
  1108. likely add you as a collaborator. As a collaborator you are given the ability
  1109. to merge others pull requests. It is very important that new code does not
  1110. break existing code, so be careful about what code you do choose to merge.
  1111. If you feel like you have contributed to the project but have not yet been
  1112. added as a collaborator, we probably forgot to add you, please open an issue.