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.
 
 
 

800 lines
20 KiB

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