flag.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882
  1. package cli
  2. import (
  3. "flag"
  4. "fmt"
  5. "os"
  6. "reflect"
  7. "runtime"
  8. "strconv"
  9. "strings"
  10. "time"
  11. )
  12. const defaultPlaceholder = "value"
  13. // BashCompletionFlag enables bash-completion for all commands and subcommands
  14. var BashCompletionFlag = BoolFlag{
  15. Name: "generate-bash-completion",
  16. Hidden: true,
  17. }
  18. // VersionFlag prints the version for the application
  19. var VersionFlag = BoolFlag{
  20. Name: "version, v",
  21. Usage: "print the version",
  22. }
  23. // HelpFlag prints the help for all commands and subcommands
  24. // Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand
  25. // unless HideHelp is set to true)
  26. var HelpFlag = BoolFlag{
  27. Name: "help, h",
  28. Usage: "show help",
  29. }
  30. // FlagStringer converts a flag definition to a string. This is used by help
  31. // to display a flag.
  32. var FlagStringer FlagStringFunc = stringifyFlag
  33. // Flag is a common interface related to parsing flags in cli.
  34. // For more advanced flag parsing techniques, it is recommended that
  35. // this interface be implemented.
  36. type Flag interface {
  37. fmt.Stringer
  38. // Apply Flag settings to the given flag set
  39. Apply(*flag.FlagSet)
  40. GetName() string
  41. }
  42. func flagSet(name string, flags []Flag) *flag.FlagSet {
  43. set := flag.NewFlagSet(name, flag.ContinueOnError)
  44. for _, f := range flags {
  45. f.Apply(set)
  46. }
  47. return set
  48. }
  49. func eachName(longName string, fn func(string)) {
  50. parts := strings.Split(longName, ",")
  51. for _, name := range parts {
  52. name = strings.Trim(name, " ")
  53. fn(name)
  54. }
  55. }
  56. // Generic is a generic parseable type identified by a specific flag
  57. type Generic interface {
  58. Set(value string) error
  59. String() string
  60. }
  61. // GenericFlag is the flag type for types implementing Generic
  62. type GenericFlag struct {
  63. Name string
  64. Value Generic
  65. Usage string
  66. EnvVar string
  67. Hidden bool
  68. }
  69. // String returns the string representation of the generic flag to display the
  70. // help text to the user (uses the String() method of the generic flag to show
  71. // the value)
  72. func (f GenericFlag) String() string {
  73. return FlagStringer(f)
  74. }
  75. // Apply takes the flagset and calls Set on the generic flag with the value
  76. // provided by the user for parsing by the flag
  77. func (f GenericFlag) Apply(set *flag.FlagSet) {
  78. val := f.Value
  79. if f.EnvVar != "" {
  80. for _, envVar := range strings.Split(f.EnvVar, ",") {
  81. envVar = strings.TrimSpace(envVar)
  82. if envVal := os.Getenv(envVar); envVal != "" {
  83. val.Set(envVal)
  84. break
  85. }
  86. }
  87. }
  88. eachName(f.Name, func(name string) {
  89. set.Var(f.Value, name, f.Usage)
  90. })
  91. }
  92. // GetName returns the name of a flag.
  93. func (f GenericFlag) GetName() string {
  94. return f.Name
  95. }
  96. // StringSlice is an opaque type for []string to satisfy flag.Value
  97. type StringSlice []string
  98. // Set appends the string value to the list of values
  99. func (f *StringSlice) Set(value string) error {
  100. *f = append(*f, value)
  101. return nil
  102. }
  103. // String returns a readable representation of this value (for usage defaults)
  104. func (f *StringSlice) String() string {
  105. return fmt.Sprintf("%s", *f)
  106. }
  107. // Value returns the slice of strings set by this flag
  108. func (f *StringSlice) Value() []string {
  109. return *f
  110. }
  111. // StringSliceFlag is a string flag that can be specified multiple times on the
  112. // command-line
  113. type StringSliceFlag struct {
  114. Name string
  115. Value *StringSlice
  116. Usage string
  117. EnvVar string
  118. Hidden bool
  119. }
  120. // String returns the usage
  121. func (f StringSliceFlag) String() string {
  122. return FlagStringer(f)
  123. }
  124. // Apply populates the flag given the flag set and environment
  125. func (f StringSliceFlag) Apply(set *flag.FlagSet) {
  126. if f.EnvVar != "" {
  127. for _, envVar := range strings.Split(f.EnvVar, ",") {
  128. envVar = strings.TrimSpace(envVar)
  129. if envVal := os.Getenv(envVar); envVal != "" {
  130. newVal := &StringSlice{}
  131. for _, s := range strings.Split(envVal, ",") {
  132. s = strings.TrimSpace(s)
  133. newVal.Set(s)
  134. }
  135. f.Value = newVal
  136. break
  137. }
  138. }
  139. }
  140. eachName(f.Name, func(name string) {
  141. if f.Value == nil {
  142. f.Value = &StringSlice{}
  143. }
  144. set.Var(f.Value, name, f.Usage)
  145. })
  146. }
  147. // GetName returns the name of a flag.
  148. func (f StringSliceFlag) GetName() string {
  149. return f.Name
  150. }
  151. // IntSlice is an opaque type for []int to satisfy flag.Value
  152. type IntSlice []int
  153. // Set parses the value into an integer and appends it to the list of values
  154. func (f *IntSlice) Set(value string) error {
  155. tmp, err := strconv.Atoi(value)
  156. if err != nil {
  157. return err
  158. }
  159. *f = append(*f, tmp)
  160. return nil
  161. }
  162. // String returns a readable representation of this value (for usage defaults)
  163. func (f *IntSlice) String() string {
  164. return fmt.Sprintf("%#v", *f)
  165. }
  166. // Value returns the slice of ints set by this flag
  167. func (f *IntSlice) Value() []int {
  168. return *f
  169. }
  170. // IntSliceFlag is an int flag that can be specified multiple times on the
  171. // command-line
  172. type IntSliceFlag struct {
  173. Name string
  174. Value *IntSlice
  175. Usage string
  176. EnvVar string
  177. Hidden bool
  178. }
  179. // String returns the usage
  180. func (f IntSliceFlag) String() string {
  181. return FlagStringer(f)
  182. }
  183. // Apply populates the flag given the flag set and environment
  184. func (f IntSliceFlag) Apply(set *flag.FlagSet) {
  185. if f.EnvVar != "" {
  186. for _, envVar := range strings.Split(f.EnvVar, ",") {
  187. envVar = strings.TrimSpace(envVar)
  188. if envVal := os.Getenv(envVar); envVal != "" {
  189. newVal := &IntSlice{}
  190. for _, s := range strings.Split(envVal, ",") {
  191. s = strings.TrimSpace(s)
  192. err := newVal.Set(s)
  193. if err != nil {
  194. fmt.Fprintf(ErrWriter, err.Error())
  195. }
  196. }
  197. f.Value = newVal
  198. break
  199. }
  200. }
  201. }
  202. eachName(f.Name, func(name string) {
  203. if f.Value == nil {
  204. f.Value = &IntSlice{}
  205. }
  206. set.Var(f.Value, name, f.Usage)
  207. })
  208. }
  209. // GetName returns the name of the flag.
  210. func (f IntSliceFlag) GetName() string {
  211. return f.Name
  212. }
  213. // Int64Slice is an opaque type for []int to satisfy flag.Value
  214. type Int64Slice []int64
  215. // Set parses the value into an integer and appends it to the list of values
  216. func (f *Int64Slice) Set(value string) error {
  217. tmp, err := strconv.ParseInt(value, 10, 64)
  218. if err != nil {
  219. return err
  220. }
  221. *f = append(*f, tmp)
  222. return nil
  223. }
  224. // String returns a readable representation of this value (for usage defaults)
  225. func (f *Int64Slice) String() string {
  226. return fmt.Sprintf("%#v", *f)
  227. }
  228. // Value returns the slice of ints set by this flag
  229. func (f *Int64Slice) Value() []int64 {
  230. return *f
  231. }
  232. // Int64SliceFlag is an int flag that can be specified multiple times on the
  233. // command-line
  234. type Int64SliceFlag struct {
  235. Name string
  236. Value *Int64Slice
  237. Usage string
  238. EnvVar string
  239. Hidden bool
  240. }
  241. // String returns the usage
  242. func (f Int64SliceFlag) String() string {
  243. return FlagStringer(f)
  244. }
  245. // Apply populates the flag given the flag set and environment
  246. func (f Int64SliceFlag) Apply(set *flag.FlagSet) {
  247. if f.EnvVar != "" {
  248. for _, envVar := range strings.Split(f.EnvVar, ",") {
  249. envVar = strings.TrimSpace(envVar)
  250. if envVal := os.Getenv(envVar); envVal != "" {
  251. newVal := &Int64Slice{}
  252. for _, s := range strings.Split(envVal, ",") {
  253. s = strings.TrimSpace(s)
  254. err := newVal.Set(s)
  255. if err != nil {
  256. fmt.Fprintf(ErrWriter, err.Error())
  257. }
  258. }
  259. f.Value = newVal
  260. break
  261. }
  262. }
  263. }
  264. eachName(f.Name, func(name string) {
  265. if f.Value == nil {
  266. f.Value = &Int64Slice{}
  267. }
  268. set.Var(f.Value, name, f.Usage)
  269. })
  270. }
  271. // GetName returns the name of the flag.
  272. func (f Int64SliceFlag) GetName() string {
  273. return f.Name
  274. }
  275. // BoolFlag is a switch that defaults to false
  276. type BoolFlag struct {
  277. Name string
  278. Usage string
  279. EnvVar string
  280. Destination *bool
  281. Hidden bool
  282. }
  283. // String returns a readable representation of this value (for usage defaults)
  284. func (f BoolFlag) String() string {
  285. return FlagStringer(f)
  286. }
  287. // Apply populates the flag given the flag set and environment
  288. func (f BoolFlag) Apply(set *flag.FlagSet) {
  289. val := false
  290. if f.EnvVar != "" {
  291. for _, envVar := range strings.Split(f.EnvVar, ",") {
  292. envVar = strings.TrimSpace(envVar)
  293. if envVal := os.Getenv(envVar); envVal != "" {
  294. envValBool, err := strconv.ParseBool(envVal)
  295. if err == nil {
  296. val = envValBool
  297. }
  298. break
  299. }
  300. }
  301. }
  302. eachName(f.Name, func(name string) {
  303. if f.Destination != nil {
  304. set.BoolVar(f.Destination, name, val, f.Usage)
  305. return
  306. }
  307. set.Bool(name, val, f.Usage)
  308. })
  309. }
  310. // GetName returns the name of the flag.
  311. func (f BoolFlag) GetName() string {
  312. return f.Name
  313. }
  314. // BoolTFlag this represents a boolean flag that is true by default, but can
  315. // still be set to false by --some-flag=false
  316. type BoolTFlag struct {
  317. Name string
  318. Usage string
  319. EnvVar string
  320. Destination *bool
  321. Hidden bool
  322. }
  323. // String returns a readable representation of this value (for usage defaults)
  324. func (f BoolTFlag) String() string {
  325. return FlagStringer(f)
  326. }
  327. // Apply populates the flag given the flag set and environment
  328. func (f BoolTFlag) Apply(set *flag.FlagSet) {
  329. val := true
  330. if f.EnvVar != "" {
  331. for _, envVar := range strings.Split(f.EnvVar, ",") {
  332. envVar = strings.TrimSpace(envVar)
  333. if envVal := os.Getenv(envVar); envVal != "" {
  334. envValBool, err := strconv.ParseBool(envVal)
  335. if err == nil {
  336. val = envValBool
  337. break
  338. }
  339. }
  340. }
  341. }
  342. eachName(f.Name, func(name string) {
  343. if f.Destination != nil {
  344. set.BoolVar(f.Destination, name, val, f.Usage)
  345. return
  346. }
  347. set.Bool(name, val, f.Usage)
  348. })
  349. }
  350. // GetName returns the name of the flag.
  351. func (f BoolTFlag) GetName() string {
  352. return f.Name
  353. }
  354. // StringFlag represents a flag that takes as string value
  355. type StringFlag struct {
  356. Name string
  357. Value string
  358. Usage string
  359. EnvVar string
  360. Destination *string
  361. Hidden bool
  362. }
  363. // String returns the usage
  364. func (f StringFlag) String() string {
  365. return FlagStringer(f)
  366. }
  367. // Apply populates the flag given the flag set and environment
  368. func (f StringFlag) Apply(set *flag.FlagSet) {
  369. if f.EnvVar != "" {
  370. for _, envVar := range strings.Split(f.EnvVar, ",") {
  371. envVar = strings.TrimSpace(envVar)
  372. if envVal := os.Getenv(envVar); envVal != "" {
  373. f.Value = envVal
  374. break
  375. }
  376. }
  377. }
  378. eachName(f.Name, func(name string) {
  379. if f.Destination != nil {
  380. set.StringVar(f.Destination, name, f.Value, f.Usage)
  381. return
  382. }
  383. set.String(name, f.Value, f.Usage)
  384. })
  385. }
  386. // GetName returns the name of the flag.
  387. func (f StringFlag) GetName() string {
  388. return f.Name
  389. }
  390. // IntFlag is a flag that takes an integer
  391. type IntFlag struct {
  392. Name string
  393. Value int
  394. Usage string
  395. EnvVar string
  396. Destination *int
  397. Hidden bool
  398. }
  399. // String returns the usage
  400. func (f IntFlag) String() string {
  401. return FlagStringer(f)
  402. }
  403. // Apply populates the flag given the flag set and environment
  404. func (f IntFlag) Apply(set *flag.FlagSet) {
  405. if f.EnvVar != "" {
  406. for _, envVar := range strings.Split(f.EnvVar, ",") {
  407. envVar = strings.TrimSpace(envVar)
  408. if envVal := os.Getenv(envVar); envVal != "" {
  409. envValInt, err := strconv.ParseInt(envVal, 0, 64)
  410. if err == nil {
  411. f.Value = int(envValInt)
  412. break
  413. }
  414. }
  415. }
  416. }
  417. eachName(f.Name, func(name string) {
  418. if f.Destination != nil {
  419. set.IntVar(f.Destination, name, f.Value, f.Usage)
  420. return
  421. }
  422. set.Int(name, f.Value, f.Usage)
  423. })
  424. }
  425. // GetName returns the name of the flag.
  426. func (f IntFlag) GetName() string {
  427. return f.Name
  428. }
  429. // Int64Flag is a flag that takes a 64-bit integer
  430. type Int64Flag struct {
  431. Name string
  432. Value int64
  433. Usage string
  434. EnvVar string
  435. Destination *int64
  436. Hidden bool
  437. }
  438. // String returns the usage
  439. func (f Int64Flag) String() string {
  440. return FlagStringer(f)
  441. }
  442. // Apply populates the flag given the flag set and environment
  443. func (f Int64Flag) Apply(set *flag.FlagSet) {
  444. if f.EnvVar != "" {
  445. for _, envVar := range strings.Split(f.EnvVar, ",") {
  446. envVar = strings.TrimSpace(envVar)
  447. if envVal := os.Getenv(envVar); envVal != "" {
  448. envValInt, err := strconv.ParseInt(envVal, 0, 64)
  449. if err == nil {
  450. f.Value = envValInt
  451. break
  452. }
  453. }
  454. }
  455. }
  456. eachName(f.Name, func(name string) {
  457. if f.Destination != nil {
  458. set.Int64Var(f.Destination, name, f.Value, f.Usage)
  459. return
  460. }
  461. set.Int64(name, f.Value, f.Usage)
  462. })
  463. }
  464. // GetName returns the name of the flag.
  465. func (f Int64Flag) GetName() string {
  466. return f.Name
  467. }
  468. // UintFlag is a flag that takes an unsigned integer
  469. type UintFlag struct {
  470. Name string
  471. Value uint
  472. Usage string
  473. EnvVar string
  474. Destination *uint
  475. Hidden bool
  476. }
  477. // String returns the usage
  478. func (f UintFlag) String() string {
  479. return FlagStringer(f)
  480. }
  481. // Apply populates the flag given the flag set and environment
  482. func (f UintFlag) Apply(set *flag.FlagSet) {
  483. if f.EnvVar != "" {
  484. for _, envVar := range strings.Split(f.EnvVar, ",") {
  485. envVar = strings.TrimSpace(envVar)
  486. if envVal := os.Getenv(envVar); envVal != "" {
  487. envValInt, err := strconv.ParseUint(envVal, 0, 64)
  488. if err == nil {
  489. f.Value = uint(envValInt)
  490. break
  491. }
  492. }
  493. }
  494. }
  495. eachName(f.Name, func(name string) {
  496. if f.Destination != nil {
  497. set.UintVar(f.Destination, name, f.Value, f.Usage)
  498. return
  499. }
  500. set.Uint(name, f.Value, f.Usage)
  501. })
  502. }
  503. // GetName returns the name of the flag.
  504. func (f UintFlag) GetName() string {
  505. return f.Name
  506. }
  507. // Uint64Flag is a flag that takes an unsigned 64-bit integer
  508. type Uint64Flag struct {
  509. Name string
  510. Value uint64
  511. Usage string
  512. EnvVar string
  513. Destination *uint64
  514. Hidden bool
  515. }
  516. // String returns the usage
  517. func (f Uint64Flag) String() string {
  518. return FlagStringer(f)
  519. }
  520. // Apply populates the flag given the flag set and environment
  521. func (f Uint64Flag) Apply(set *flag.FlagSet) {
  522. if f.EnvVar != "" {
  523. for _, envVar := range strings.Split(f.EnvVar, ",") {
  524. envVar = strings.TrimSpace(envVar)
  525. if envVal := os.Getenv(envVar); envVal != "" {
  526. envValInt, err := strconv.ParseUint(envVal, 0, 64)
  527. if err == nil {
  528. f.Value = uint64(envValInt)
  529. break
  530. }
  531. }
  532. }
  533. }
  534. eachName(f.Name, func(name string) {
  535. if f.Destination != nil {
  536. set.Uint64Var(f.Destination, name, f.Value, f.Usage)
  537. return
  538. }
  539. set.Uint64(name, f.Value, f.Usage)
  540. })
  541. }
  542. // GetName returns the name of the flag.
  543. func (f Uint64Flag) GetName() string {
  544. return f.Name
  545. }
  546. // DurationFlag is a flag that takes a duration specified in Go's duration
  547. // format: https://golang.org/pkg/time/#ParseDuration
  548. type DurationFlag struct {
  549. Name string
  550. Value time.Duration
  551. Usage string
  552. EnvVar string
  553. Destination *time.Duration
  554. Hidden bool
  555. }
  556. // String returns a readable representation of this value (for usage defaults)
  557. func (f DurationFlag) String() string {
  558. return FlagStringer(f)
  559. }
  560. // Apply populates the flag given the flag set and environment
  561. func (f DurationFlag) Apply(set *flag.FlagSet) {
  562. if f.EnvVar != "" {
  563. for _, envVar := range strings.Split(f.EnvVar, ",") {
  564. envVar = strings.TrimSpace(envVar)
  565. if envVal := os.Getenv(envVar); envVal != "" {
  566. envValDuration, err := time.ParseDuration(envVal)
  567. if err == nil {
  568. f.Value = envValDuration
  569. break
  570. }
  571. }
  572. }
  573. }
  574. eachName(f.Name, func(name string) {
  575. if f.Destination != nil {
  576. set.DurationVar(f.Destination, name, f.Value, f.Usage)
  577. return
  578. }
  579. set.Duration(name, f.Value, f.Usage)
  580. })
  581. }
  582. // GetName returns the name of the flag.
  583. func (f DurationFlag) GetName() string {
  584. return f.Name
  585. }
  586. // Float64Flag is a flag that takes an float value
  587. type Float64Flag struct {
  588. Name string
  589. Value float64
  590. Usage string
  591. EnvVar string
  592. Destination *float64
  593. Hidden bool
  594. }
  595. // String returns the usage
  596. func (f Float64Flag) String() string {
  597. return FlagStringer(f)
  598. }
  599. // Apply populates the flag given the flag set and environment
  600. func (f Float64Flag) Apply(set *flag.FlagSet) {
  601. if f.EnvVar != "" {
  602. for _, envVar := range strings.Split(f.EnvVar, ",") {
  603. envVar = strings.TrimSpace(envVar)
  604. if envVal := os.Getenv(envVar); envVal != "" {
  605. envValFloat, err := strconv.ParseFloat(envVal, 10)
  606. if err == nil {
  607. f.Value = float64(envValFloat)
  608. }
  609. }
  610. }
  611. }
  612. eachName(f.Name, func(name string) {
  613. if f.Destination != nil {
  614. set.Float64Var(f.Destination, name, f.Value, f.Usage)
  615. return
  616. }
  617. set.Float64(name, f.Value, f.Usage)
  618. })
  619. }
  620. // GetName returns the name of the flag.
  621. func (f Float64Flag) GetName() string {
  622. return f.Name
  623. }
  624. func visibleFlags(fl []Flag) []Flag {
  625. visible := []Flag{}
  626. for _, flag := range fl {
  627. if !flagValue(flag).FieldByName("Hidden").Bool() {
  628. visible = append(visible, flag)
  629. }
  630. }
  631. return visible
  632. }
  633. func prefixFor(name string) (prefix string) {
  634. if len(name) == 1 {
  635. prefix = "-"
  636. } else {
  637. prefix = "--"
  638. }
  639. return
  640. }
  641. // Returns the placeholder, if any, and the unquoted usage string.
  642. func unquoteUsage(usage string) (string, string) {
  643. for i := 0; i < len(usage); i++ {
  644. if usage[i] == '`' {
  645. for j := i + 1; j < len(usage); j++ {
  646. if usage[j] == '`' {
  647. name := usage[i+1 : j]
  648. usage = usage[:i] + name + usage[j+1:]
  649. return name, usage
  650. }
  651. }
  652. break
  653. }
  654. }
  655. return "", usage
  656. }
  657. func prefixedNames(fullName, placeholder string) string {
  658. var prefixed string
  659. parts := strings.Split(fullName, ",")
  660. for i, name := range parts {
  661. name = strings.Trim(name, " ")
  662. prefixed += prefixFor(name) + name
  663. if placeholder != "" {
  664. prefixed += " " + placeholder
  665. }
  666. if i < len(parts)-1 {
  667. prefixed += ", "
  668. }
  669. }
  670. return prefixed
  671. }
  672. func withEnvHint(envVar, str string) string {
  673. envText := ""
  674. if envVar != "" {
  675. prefix := "$"
  676. suffix := ""
  677. sep := ", $"
  678. if runtime.GOOS == "windows" {
  679. prefix = "%"
  680. suffix = "%"
  681. sep = "%, %"
  682. }
  683. envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(strings.Split(envVar, ","), sep), suffix)
  684. }
  685. return str + envText
  686. }
  687. func flagValue(f Flag) reflect.Value {
  688. fv := reflect.ValueOf(f)
  689. for fv.Kind() == reflect.Ptr {
  690. fv = reflect.Indirect(fv)
  691. }
  692. return fv
  693. }
  694. func stringifyFlag(f Flag) string {
  695. fv := flagValue(f)
  696. switch f.(type) {
  697. case IntSliceFlag:
  698. return withEnvHint(fv.FieldByName("EnvVar").String(),
  699. stringifyIntSliceFlag(f.(IntSliceFlag)))
  700. case Int64SliceFlag:
  701. return withEnvHint(fv.FieldByName("EnvVar").String(),
  702. stringifyInt64SliceFlag(f.(Int64SliceFlag)))
  703. case StringSliceFlag:
  704. return withEnvHint(fv.FieldByName("EnvVar").String(),
  705. stringifyStringSliceFlag(f.(StringSliceFlag)))
  706. }
  707. placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String())
  708. needsPlaceholder := false
  709. defaultValueString := ""
  710. val := fv.FieldByName("Value")
  711. if val.IsValid() {
  712. needsPlaceholder = true
  713. defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface())
  714. if val.Kind() == reflect.String && val.String() != "" {
  715. defaultValueString = fmt.Sprintf(" (default: %q)", val.String())
  716. }
  717. }
  718. if defaultValueString == " (default: )" {
  719. defaultValueString = ""
  720. }
  721. if needsPlaceholder && placeholder == "" {
  722. placeholder = defaultPlaceholder
  723. }
  724. usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultValueString))
  725. return withEnvHint(fv.FieldByName("EnvVar").String(),
  726. fmt.Sprintf("%s\t%s", prefixedNames(fv.FieldByName("Name").String(), placeholder), usageWithDefault))
  727. }
  728. func stringifyIntSliceFlag(f IntSliceFlag) string {
  729. defaultVals := []string{}
  730. if f.Value != nil && len(f.Value.Value()) > 0 {
  731. for _, i := range f.Value.Value() {
  732. defaultVals = append(defaultVals, fmt.Sprintf("%d", i))
  733. }
  734. }
  735. return stringifySliceFlag(f.Usage, f.Name, defaultVals)
  736. }
  737. func stringifyInt64SliceFlag(f Int64SliceFlag) string {
  738. defaultVals := []string{}
  739. if f.Value != nil && len(f.Value.Value()) > 0 {
  740. for _, i := range f.Value.Value() {
  741. defaultVals = append(defaultVals, fmt.Sprintf("%d", i))
  742. }
  743. }
  744. return stringifySliceFlag(f.Usage, f.Name, defaultVals)
  745. }
  746. func stringifyStringSliceFlag(f StringSliceFlag) string {
  747. defaultVals := []string{}
  748. if f.Value != nil && len(f.Value.Value()) > 0 {
  749. for _, s := range f.Value.Value() {
  750. if len(s) > 0 {
  751. defaultVals = append(defaultVals, fmt.Sprintf("%q", s))
  752. }
  753. }
  754. }
  755. return stringifySliceFlag(f.Usage, f.Name, defaultVals)
  756. }
  757. func stringifySliceFlag(usage, name string, defaultVals []string) string {
  758. placeholder, usage := unquoteUsage(usage)
  759. if placeholder == "" {
  760. placeholder = defaultPlaceholder
  761. }
  762. defaultVal := ""
  763. if len(defaultVals) > 0 {
  764. defaultVal = fmt.Sprintf(" (default: %s)", strings.Join(defaultVals, ", "))
  765. }
  766. usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal))
  767. return fmt.Sprintf("%s\t%s", prefixedNames(name, placeholder), usageWithDefault)
  768. }