forked from cerc-io/plugeth
289b30715d
This commit converts the dependency management from Godeps to the vendor folder, also switching the tool from godep to trash. Since the upstream tool lacks a few features proposed via a few PRs, until those PRs are merged in (if), use github.com/karalabe/trash. You can update dependencies via trash --update. All dependencies have been updated to their latest version. Parts of the build system are reworked to drop old notions of Godeps and invocation of the go vet command so that it doesn't run against the vendor folder, as that will just blow up during vetting. The conversion drops OpenCL (and hence GPU mining support) from ethash and our codebase. The short reasoning is that there's noone to maintain and having opencl libs in our deps messes up builds as go install ./... tries to build them, failing with unsatisfied link errors for the C OpenCL deps. golang.org/x/net/context is not vendored in. We expect it to be fetched by the user (i.e. using go get). To keep ci.go builds reproducible the package is "vendored" in build/_vendor.
883 lines
20 KiB
Go
883 lines
20 KiB
Go
package cli
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"reflect"
|
|
"runtime"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const defaultPlaceholder = "value"
|
|
|
|
// BashCompletionFlag enables bash-completion for all commands and subcommands
|
|
var BashCompletionFlag = BoolFlag{
|
|
Name: "generate-bash-completion",
|
|
Hidden: true,
|
|
}
|
|
|
|
// VersionFlag prints the version for the application
|
|
var VersionFlag = BoolFlag{
|
|
Name: "version, v",
|
|
Usage: "print the version",
|
|
}
|
|
|
|
// HelpFlag prints the help for all commands and subcommands
|
|
// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand
|
|
// unless HideHelp is set to true)
|
|
var HelpFlag = BoolFlag{
|
|
Name: "help, h",
|
|
Usage: "show help",
|
|
}
|
|
|
|
// FlagStringer converts a flag definition to a string. This is used by help
|
|
// to display a flag.
|
|
var FlagStringer FlagStringFunc = stringifyFlag
|
|
|
|
// Flag is a common interface related to parsing flags in cli.
|
|
// For more advanced flag parsing techniques, it is recommended that
|
|
// this interface be implemented.
|
|
type Flag interface {
|
|
fmt.Stringer
|
|
// Apply Flag settings to the given flag set
|
|
Apply(*flag.FlagSet)
|
|
GetName() string
|
|
}
|
|
|
|
func flagSet(name string, flags []Flag) *flag.FlagSet {
|
|
set := flag.NewFlagSet(name, flag.ContinueOnError)
|
|
|
|
for _, f := range flags {
|
|
f.Apply(set)
|
|
}
|
|
return set
|
|
}
|
|
|
|
func eachName(longName string, fn func(string)) {
|
|
parts := strings.Split(longName, ",")
|
|
for _, name := range parts {
|
|
name = strings.Trim(name, " ")
|
|
fn(name)
|
|
}
|
|
}
|
|
|
|
// Generic is a generic parseable type identified by a specific flag
|
|
type Generic interface {
|
|
Set(value string) error
|
|
String() string
|
|
}
|
|
|
|
// GenericFlag is the flag type for types implementing Generic
|
|
type GenericFlag struct {
|
|
Name string
|
|
Value Generic
|
|
Usage string
|
|
EnvVar string
|
|
Hidden bool
|
|
}
|
|
|
|
// String returns the string representation of the generic flag to display the
|
|
// help text to the user (uses the String() method of the generic flag to show
|
|
// the value)
|
|
func (f GenericFlag) String() string {
|
|
return FlagStringer(f)
|
|
}
|
|
|
|
// Apply takes the flagset and calls Set on the generic flag with the value
|
|
// provided by the user for parsing by the flag
|
|
func (f GenericFlag) Apply(set *flag.FlagSet) {
|
|
val := f.Value
|
|
if f.EnvVar != "" {
|
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
envVar = strings.TrimSpace(envVar)
|
|
if envVal := os.Getenv(envVar); envVal != "" {
|
|
val.Set(envVal)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
eachName(f.Name, func(name string) {
|
|
set.Var(f.Value, name, f.Usage)
|
|
})
|
|
}
|
|
|
|
// GetName returns the name of a flag.
|
|
func (f GenericFlag) GetName() string {
|
|
return f.Name
|
|
}
|
|
|
|
// StringSlice is an opaque type for []string to satisfy flag.Value
|
|
type StringSlice []string
|
|
|
|
// Set appends the string value to the list of values
|
|
func (f *StringSlice) Set(value string) error {
|
|
*f = append(*f, value)
|
|
return nil
|
|
}
|
|
|
|
// String returns a readable representation of this value (for usage defaults)
|
|
func (f *StringSlice) String() string {
|
|
return fmt.Sprintf("%s", *f)
|
|
}
|
|
|
|
// Value returns the slice of strings set by this flag
|
|
func (f *StringSlice) Value() []string {
|
|
return *f
|
|
}
|
|
|
|
// StringSliceFlag is a string flag that can be specified multiple times on the
|
|
// command-line
|
|
type StringSliceFlag struct {
|
|
Name string
|
|
Value *StringSlice
|
|
Usage string
|
|
EnvVar string
|
|
Hidden bool
|
|
}
|
|
|
|
// String returns the usage
|
|
func (f StringSliceFlag) String() string {
|
|
return FlagStringer(f)
|
|
}
|
|
|
|
// Apply populates the flag given the flag set and environment
|
|
func (f StringSliceFlag) Apply(set *flag.FlagSet) {
|
|
if f.EnvVar != "" {
|
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
envVar = strings.TrimSpace(envVar)
|
|
if envVal := os.Getenv(envVar); envVal != "" {
|
|
newVal := &StringSlice{}
|
|
for _, s := range strings.Split(envVal, ",") {
|
|
s = strings.TrimSpace(s)
|
|
newVal.Set(s)
|
|
}
|
|
f.Value = newVal
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
eachName(f.Name, func(name string) {
|
|
if f.Value == nil {
|
|
f.Value = &StringSlice{}
|
|
}
|
|
set.Var(f.Value, name, f.Usage)
|
|
})
|
|
}
|
|
|
|
// GetName returns the name of a flag.
|
|
func (f StringSliceFlag) GetName() string {
|
|
return f.Name
|
|
}
|
|
|
|
// IntSlice is an opaque type for []int to satisfy flag.Value
|
|
type IntSlice []int
|
|
|
|
// Set parses the value into an integer and appends it to the list of values
|
|
func (f *IntSlice) Set(value string) error {
|
|
tmp, err := strconv.Atoi(value)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*f = append(*f, tmp)
|
|
return nil
|
|
}
|
|
|
|
// String returns a readable representation of this value (for usage defaults)
|
|
func (f *IntSlice) String() string {
|
|
return fmt.Sprintf("%#v", *f)
|
|
}
|
|
|
|
// Value returns the slice of ints set by this flag
|
|
func (f *IntSlice) Value() []int {
|
|
return *f
|
|
}
|
|
|
|
// IntSliceFlag is an int flag that can be specified multiple times on the
|
|
// command-line
|
|
type IntSliceFlag struct {
|
|
Name string
|
|
Value *IntSlice
|
|
Usage string
|
|
EnvVar string
|
|
Hidden bool
|
|
}
|
|
|
|
// String returns the usage
|
|
func (f IntSliceFlag) String() string {
|
|
return FlagStringer(f)
|
|
}
|
|
|
|
// Apply populates the flag given the flag set and environment
|
|
func (f IntSliceFlag) Apply(set *flag.FlagSet) {
|
|
if f.EnvVar != "" {
|
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
envVar = strings.TrimSpace(envVar)
|
|
if envVal := os.Getenv(envVar); envVal != "" {
|
|
newVal := &IntSlice{}
|
|
for _, s := range strings.Split(envVal, ",") {
|
|
s = strings.TrimSpace(s)
|
|
err := newVal.Set(s)
|
|
if err != nil {
|
|
fmt.Fprintf(ErrWriter, err.Error())
|
|
}
|
|
}
|
|
f.Value = newVal
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
eachName(f.Name, func(name string) {
|
|
if f.Value == nil {
|
|
f.Value = &IntSlice{}
|
|
}
|
|
set.Var(f.Value, name, f.Usage)
|
|
})
|
|
}
|
|
|
|
// GetName returns the name of the flag.
|
|
func (f IntSliceFlag) GetName() string {
|
|
return f.Name
|
|
}
|
|
|
|
// Int64Slice is an opaque type for []int to satisfy flag.Value
|
|
type Int64Slice []int64
|
|
|
|
// Set parses the value into an integer and appends it to the list of values
|
|
func (f *Int64Slice) Set(value string) error {
|
|
tmp, err := strconv.ParseInt(value, 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*f = append(*f, tmp)
|
|
return nil
|
|
}
|
|
|
|
// String returns a readable representation of this value (for usage defaults)
|
|
func (f *Int64Slice) String() string {
|
|
return fmt.Sprintf("%#v", *f)
|
|
}
|
|
|
|
// Value returns the slice of ints set by this flag
|
|
func (f *Int64Slice) Value() []int64 {
|
|
return *f
|
|
}
|
|
|
|
// Int64SliceFlag is an int flag that can be specified multiple times on the
|
|
// command-line
|
|
type Int64SliceFlag struct {
|
|
Name string
|
|
Value *Int64Slice
|
|
Usage string
|
|
EnvVar string
|
|
Hidden bool
|
|
}
|
|
|
|
// String returns the usage
|
|
func (f Int64SliceFlag) String() string {
|
|
return FlagStringer(f)
|
|
}
|
|
|
|
// Apply populates the flag given the flag set and environment
|
|
func (f Int64SliceFlag) Apply(set *flag.FlagSet) {
|
|
if f.EnvVar != "" {
|
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
envVar = strings.TrimSpace(envVar)
|
|
if envVal := os.Getenv(envVar); envVal != "" {
|
|
newVal := &Int64Slice{}
|
|
for _, s := range strings.Split(envVal, ",") {
|
|
s = strings.TrimSpace(s)
|
|
err := newVal.Set(s)
|
|
if err != nil {
|
|
fmt.Fprintf(ErrWriter, err.Error())
|
|
}
|
|
}
|
|
f.Value = newVal
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
eachName(f.Name, func(name string) {
|
|
if f.Value == nil {
|
|
f.Value = &Int64Slice{}
|
|
}
|
|
set.Var(f.Value, name, f.Usage)
|
|
})
|
|
}
|
|
|
|
// GetName returns the name of the flag.
|
|
func (f Int64SliceFlag) GetName() string {
|
|
return f.Name
|
|
}
|
|
|
|
// BoolFlag is a switch that defaults to false
|
|
type BoolFlag struct {
|
|
Name string
|
|
Usage string
|
|
EnvVar string
|
|
Destination *bool
|
|
Hidden bool
|
|
}
|
|
|
|
// String returns a readable representation of this value (for usage defaults)
|
|
func (f BoolFlag) String() string {
|
|
return FlagStringer(f)
|
|
}
|
|
|
|
// Apply populates the flag given the flag set and environment
|
|
func (f BoolFlag) Apply(set *flag.FlagSet) {
|
|
val := false
|
|
if f.EnvVar != "" {
|
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
envVar = strings.TrimSpace(envVar)
|
|
if envVal := os.Getenv(envVar); envVal != "" {
|
|
envValBool, err := strconv.ParseBool(envVal)
|
|
if err == nil {
|
|
val = envValBool
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
eachName(f.Name, func(name string) {
|
|
if f.Destination != nil {
|
|
set.BoolVar(f.Destination, name, val, f.Usage)
|
|
return
|
|
}
|
|
set.Bool(name, val, f.Usage)
|
|
})
|
|
}
|
|
|
|
// GetName returns the name of the flag.
|
|
func (f BoolFlag) GetName() string {
|
|
return f.Name
|
|
}
|
|
|
|
// BoolTFlag this represents a boolean flag that is true by default, but can
|
|
// still be set to false by --some-flag=false
|
|
type BoolTFlag struct {
|
|
Name string
|
|
Usage string
|
|
EnvVar string
|
|
Destination *bool
|
|
Hidden bool
|
|
}
|
|
|
|
// String returns a readable representation of this value (for usage defaults)
|
|
func (f BoolTFlag) String() string {
|
|
return FlagStringer(f)
|
|
}
|
|
|
|
// Apply populates the flag given the flag set and environment
|
|
func (f BoolTFlag) Apply(set *flag.FlagSet) {
|
|
val := true
|
|
if f.EnvVar != "" {
|
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
envVar = strings.TrimSpace(envVar)
|
|
if envVal := os.Getenv(envVar); envVal != "" {
|
|
envValBool, err := strconv.ParseBool(envVal)
|
|
if err == nil {
|
|
val = envValBool
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
eachName(f.Name, func(name string) {
|
|
if f.Destination != nil {
|
|
set.BoolVar(f.Destination, name, val, f.Usage)
|
|
return
|
|
}
|
|
set.Bool(name, val, f.Usage)
|
|
})
|
|
}
|
|
|
|
// GetName returns the name of the flag.
|
|
func (f BoolTFlag) GetName() string {
|
|
return f.Name
|
|
}
|
|
|
|
// StringFlag represents a flag that takes as string value
|
|
type StringFlag struct {
|
|
Name string
|
|
Value string
|
|
Usage string
|
|
EnvVar string
|
|
Destination *string
|
|
Hidden bool
|
|
}
|
|
|
|
// String returns the usage
|
|
func (f StringFlag) String() string {
|
|
return FlagStringer(f)
|
|
}
|
|
|
|
// Apply populates the flag given the flag set and environment
|
|
func (f StringFlag) Apply(set *flag.FlagSet) {
|
|
if f.EnvVar != "" {
|
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
envVar = strings.TrimSpace(envVar)
|
|
if envVal := os.Getenv(envVar); envVal != "" {
|
|
f.Value = envVal
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
eachName(f.Name, func(name string) {
|
|
if f.Destination != nil {
|
|
set.StringVar(f.Destination, name, f.Value, f.Usage)
|
|
return
|
|
}
|
|
set.String(name, f.Value, f.Usage)
|
|
})
|
|
}
|
|
|
|
// GetName returns the name of the flag.
|
|
func (f StringFlag) GetName() string {
|
|
return f.Name
|
|
}
|
|
|
|
// IntFlag is a flag that takes an integer
|
|
type IntFlag struct {
|
|
Name string
|
|
Value int
|
|
Usage string
|
|
EnvVar string
|
|
Destination *int
|
|
Hidden bool
|
|
}
|
|
|
|
// String returns the usage
|
|
func (f IntFlag) String() string {
|
|
return FlagStringer(f)
|
|
}
|
|
|
|
// Apply populates the flag given the flag set and environment
|
|
func (f IntFlag) Apply(set *flag.FlagSet) {
|
|
if f.EnvVar != "" {
|
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
envVar = strings.TrimSpace(envVar)
|
|
if envVal := os.Getenv(envVar); envVal != "" {
|
|
envValInt, err := strconv.ParseInt(envVal, 0, 64)
|
|
if err == nil {
|
|
f.Value = int(envValInt)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
eachName(f.Name, func(name string) {
|
|
if f.Destination != nil {
|
|
set.IntVar(f.Destination, name, f.Value, f.Usage)
|
|
return
|
|
}
|
|
set.Int(name, f.Value, f.Usage)
|
|
})
|
|
}
|
|
|
|
// GetName returns the name of the flag.
|
|
func (f IntFlag) GetName() string {
|
|
return f.Name
|
|
}
|
|
|
|
// Int64Flag is a flag that takes a 64-bit integer
|
|
type Int64Flag struct {
|
|
Name string
|
|
Value int64
|
|
Usage string
|
|
EnvVar string
|
|
Destination *int64
|
|
Hidden bool
|
|
}
|
|
|
|
// String returns the usage
|
|
func (f Int64Flag) String() string {
|
|
return FlagStringer(f)
|
|
}
|
|
|
|
// Apply populates the flag given the flag set and environment
|
|
func (f Int64Flag) Apply(set *flag.FlagSet) {
|
|
if f.EnvVar != "" {
|
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
envVar = strings.TrimSpace(envVar)
|
|
if envVal := os.Getenv(envVar); envVal != "" {
|
|
envValInt, err := strconv.ParseInt(envVal, 0, 64)
|
|
if err == nil {
|
|
f.Value = envValInt
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
eachName(f.Name, func(name string) {
|
|
if f.Destination != nil {
|
|
set.Int64Var(f.Destination, name, f.Value, f.Usage)
|
|
return
|
|
}
|
|
set.Int64(name, f.Value, f.Usage)
|
|
})
|
|
}
|
|
|
|
// GetName returns the name of the flag.
|
|
func (f Int64Flag) GetName() string {
|
|
return f.Name
|
|
}
|
|
|
|
// UintFlag is a flag that takes an unsigned integer
|
|
type UintFlag struct {
|
|
Name string
|
|
Value uint
|
|
Usage string
|
|
EnvVar string
|
|
Destination *uint
|
|
Hidden bool
|
|
}
|
|
|
|
// String returns the usage
|
|
func (f UintFlag) String() string {
|
|
return FlagStringer(f)
|
|
}
|
|
|
|
// Apply populates the flag given the flag set and environment
|
|
func (f UintFlag) Apply(set *flag.FlagSet) {
|
|
if f.EnvVar != "" {
|
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
envVar = strings.TrimSpace(envVar)
|
|
if envVal := os.Getenv(envVar); envVal != "" {
|
|
envValInt, err := strconv.ParseUint(envVal, 0, 64)
|
|
if err == nil {
|
|
f.Value = uint(envValInt)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
eachName(f.Name, func(name string) {
|
|
if f.Destination != nil {
|
|
set.UintVar(f.Destination, name, f.Value, f.Usage)
|
|
return
|
|
}
|
|
set.Uint(name, f.Value, f.Usage)
|
|
})
|
|
}
|
|
|
|
// GetName returns the name of the flag.
|
|
func (f UintFlag) GetName() string {
|
|
return f.Name
|
|
}
|
|
|
|
// Uint64Flag is a flag that takes an unsigned 64-bit integer
|
|
type Uint64Flag struct {
|
|
Name string
|
|
Value uint64
|
|
Usage string
|
|
EnvVar string
|
|
Destination *uint64
|
|
Hidden bool
|
|
}
|
|
|
|
// String returns the usage
|
|
func (f Uint64Flag) String() string {
|
|
return FlagStringer(f)
|
|
}
|
|
|
|
// Apply populates the flag given the flag set and environment
|
|
func (f Uint64Flag) Apply(set *flag.FlagSet) {
|
|
if f.EnvVar != "" {
|
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
envVar = strings.TrimSpace(envVar)
|
|
if envVal := os.Getenv(envVar); envVal != "" {
|
|
envValInt, err := strconv.ParseUint(envVal, 0, 64)
|
|
if err == nil {
|
|
f.Value = uint64(envValInt)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
eachName(f.Name, func(name string) {
|
|
if f.Destination != nil {
|
|
set.Uint64Var(f.Destination, name, f.Value, f.Usage)
|
|
return
|
|
}
|
|
set.Uint64(name, f.Value, f.Usage)
|
|
})
|
|
}
|
|
|
|
// GetName returns the name of the flag.
|
|
func (f Uint64Flag) GetName() string {
|
|
return f.Name
|
|
}
|
|
|
|
// DurationFlag is a flag that takes a duration specified in Go's duration
|
|
// format: https://golang.org/pkg/time/#ParseDuration
|
|
type DurationFlag struct {
|
|
Name string
|
|
Value time.Duration
|
|
Usage string
|
|
EnvVar string
|
|
Destination *time.Duration
|
|
Hidden bool
|
|
}
|
|
|
|
// String returns a readable representation of this value (for usage defaults)
|
|
func (f DurationFlag) String() string {
|
|
return FlagStringer(f)
|
|
}
|
|
|
|
// Apply populates the flag given the flag set and environment
|
|
func (f DurationFlag) Apply(set *flag.FlagSet) {
|
|
if f.EnvVar != "" {
|
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
envVar = strings.TrimSpace(envVar)
|
|
if envVal := os.Getenv(envVar); envVal != "" {
|
|
envValDuration, err := time.ParseDuration(envVal)
|
|
if err == nil {
|
|
f.Value = envValDuration
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
eachName(f.Name, func(name string) {
|
|
if f.Destination != nil {
|
|
set.DurationVar(f.Destination, name, f.Value, f.Usage)
|
|
return
|
|
}
|
|
set.Duration(name, f.Value, f.Usage)
|
|
})
|
|
}
|
|
|
|
// GetName returns the name of the flag.
|
|
func (f DurationFlag) GetName() string {
|
|
return f.Name
|
|
}
|
|
|
|
// Float64Flag is a flag that takes an float value
|
|
type Float64Flag struct {
|
|
Name string
|
|
Value float64
|
|
Usage string
|
|
EnvVar string
|
|
Destination *float64
|
|
Hidden bool
|
|
}
|
|
|
|
// String returns the usage
|
|
func (f Float64Flag) String() string {
|
|
return FlagStringer(f)
|
|
}
|
|
|
|
// Apply populates the flag given the flag set and environment
|
|
func (f Float64Flag) Apply(set *flag.FlagSet) {
|
|
if f.EnvVar != "" {
|
|
for _, envVar := range strings.Split(f.EnvVar, ",") {
|
|
envVar = strings.TrimSpace(envVar)
|
|
if envVal := os.Getenv(envVar); envVal != "" {
|
|
envValFloat, err := strconv.ParseFloat(envVal, 10)
|
|
if err == nil {
|
|
f.Value = float64(envValFloat)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
eachName(f.Name, func(name string) {
|
|
if f.Destination != nil {
|
|
set.Float64Var(f.Destination, name, f.Value, f.Usage)
|
|
return
|
|
}
|
|
set.Float64(name, f.Value, f.Usage)
|
|
})
|
|
}
|
|
|
|
// GetName returns the name of the flag.
|
|
func (f Float64Flag) GetName() string {
|
|
return f.Name
|
|
}
|
|
|
|
func visibleFlags(fl []Flag) []Flag {
|
|
visible := []Flag{}
|
|
for _, flag := range fl {
|
|
if !flagValue(flag).FieldByName("Hidden").Bool() {
|
|
visible = append(visible, flag)
|
|
}
|
|
}
|
|
return visible
|
|
}
|
|
|
|
func prefixFor(name string) (prefix string) {
|
|
if len(name) == 1 {
|
|
prefix = "-"
|
|
} else {
|
|
prefix = "--"
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// Returns the placeholder, if any, and the unquoted usage string.
|
|
func unquoteUsage(usage string) (string, string) {
|
|
for i := 0; i < len(usage); i++ {
|
|
if usage[i] == '`' {
|
|
for j := i + 1; j < len(usage); j++ {
|
|
if usage[j] == '`' {
|
|
name := usage[i+1 : j]
|
|
usage = usage[:i] + name + usage[j+1:]
|
|
return name, usage
|
|
}
|
|
}
|
|
break
|
|
}
|
|
}
|
|
return "", usage
|
|
}
|
|
|
|
func prefixedNames(fullName, placeholder string) string {
|
|
var prefixed string
|
|
parts := strings.Split(fullName, ",")
|
|
for i, name := range parts {
|
|
name = strings.Trim(name, " ")
|
|
prefixed += prefixFor(name) + name
|
|
if placeholder != "" {
|
|
prefixed += " " + placeholder
|
|
}
|
|
if i < len(parts)-1 {
|
|
prefixed += ", "
|
|
}
|
|
}
|
|
return prefixed
|
|
}
|
|
|
|
func withEnvHint(envVar, str string) string {
|
|
envText := ""
|
|
if envVar != "" {
|
|
prefix := "$"
|
|
suffix := ""
|
|
sep := ", $"
|
|
if runtime.GOOS == "windows" {
|
|
prefix = "%"
|
|
suffix = "%"
|
|
sep = "%, %"
|
|
}
|
|
envText = fmt.Sprintf(" [%s%s%s]", prefix, strings.Join(strings.Split(envVar, ","), sep), suffix)
|
|
}
|
|
return str + envText
|
|
}
|
|
|
|
func flagValue(f Flag) reflect.Value {
|
|
fv := reflect.ValueOf(f)
|
|
for fv.Kind() == reflect.Ptr {
|
|
fv = reflect.Indirect(fv)
|
|
}
|
|
return fv
|
|
}
|
|
|
|
func stringifyFlag(f Flag) string {
|
|
fv := flagValue(f)
|
|
|
|
switch f.(type) {
|
|
case IntSliceFlag:
|
|
return withEnvHint(fv.FieldByName("EnvVar").String(),
|
|
stringifyIntSliceFlag(f.(IntSliceFlag)))
|
|
case Int64SliceFlag:
|
|
return withEnvHint(fv.FieldByName("EnvVar").String(),
|
|
stringifyInt64SliceFlag(f.(Int64SliceFlag)))
|
|
case StringSliceFlag:
|
|
return withEnvHint(fv.FieldByName("EnvVar").String(),
|
|
stringifyStringSliceFlag(f.(StringSliceFlag)))
|
|
}
|
|
|
|
placeholder, usage := unquoteUsage(fv.FieldByName("Usage").String())
|
|
|
|
needsPlaceholder := false
|
|
defaultValueString := ""
|
|
val := fv.FieldByName("Value")
|
|
|
|
if val.IsValid() {
|
|
needsPlaceholder = true
|
|
defaultValueString = fmt.Sprintf(" (default: %v)", val.Interface())
|
|
|
|
if val.Kind() == reflect.String && val.String() != "" {
|
|
defaultValueString = fmt.Sprintf(" (default: %q)", val.String())
|
|
}
|
|
}
|
|
|
|
if defaultValueString == " (default: )" {
|
|
defaultValueString = ""
|
|
}
|
|
|
|
if needsPlaceholder && placeholder == "" {
|
|
placeholder = defaultPlaceholder
|
|
}
|
|
|
|
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultValueString))
|
|
|
|
return withEnvHint(fv.FieldByName("EnvVar").String(),
|
|
fmt.Sprintf("%s\t%s", prefixedNames(fv.FieldByName("Name").String(), placeholder), usageWithDefault))
|
|
}
|
|
|
|
func stringifyIntSliceFlag(f IntSliceFlag) string {
|
|
defaultVals := []string{}
|
|
if f.Value != nil && len(f.Value.Value()) > 0 {
|
|
for _, i := range f.Value.Value() {
|
|
defaultVals = append(defaultVals, fmt.Sprintf("%d", i))
|
|
}
|
|
}
|
|
|
|
return stringifySliceFlag(f.Usage, f.Name, defaultVals)
|
|
}
|
|
|
|
func stringifyInt64SliceFlag(f Int64SliceFlag) string {
|
|
defaultVals := []string{}
|
|
if f.Value != nil && len(f.Value.Value()) > 0 {
|
|
for _, i := range f.Value.Value() {
|
|
defaultVals = append(defaultVals, fmt.Sprintf("%d", i))
|
|
}
|
|
}
|
|
|
|
return stringifySliceFlag(f.Usage, f.Name, defaultVals)
|
|
}
|
|
|
|
func stringifyStringSliceFlag(f StringSliceFlag) string {
|
|
defaultVals := []string{}
|
|
if f.Value != nil && len(f.Value.Value()) > 0 {
|
|
for _, s := range f.Value.Value() {
|
|
if len(s) > 0 {
|
|
defaultVals = append(defaultVals, fmt.Sprintf("%q", s))
|
|
}
|
|
}
|
|
}
|
|
|
|
return stringifySliceFlag(f.Usage, f.Name, defaultVals)
|
|
}
|
|
|
|
func stringifySliceFlag(usage, name string, defaultVals []string) string {
|
|
placeholder, usage := unquoteUsage(usage)
|
|
if placeholder == "" {
|
|
placeholder = defaultPlaceholder
|
|
}
|
|
|
|
defaultVal := ""
|
|
if len(defaultVals) > 0 {
|
|
defaultVal = fmt.Sprintf(" (default: %s)", strings.Join(defaultVals, ", "))
|
|
}
|
|
|
|
usageWithDefault := strings.TrimSpace(fmt.Sprintf("%s%s", usage, defaultVal))
|
|
return fmt.Sprintf("%s\t%s", prefixedNames(name, placeholder), usageWithDefault)
|
|
}
|