5903a0a844
Compared to BoolFlag type, BoolTFlag treats 'true' as the default value for the flag. Without it, we have to use --no-action flag if we set the action is done in default. But sometimes it is bad to maintain flags with negative meanings. And it will be painful if we change the default value for the flag. As this implementation, it keeps all existing functionality. So it is compatible with old versions.
234 lines
4.2 KiB
Go
234 lines
4.2 KiB
Go
package cli
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// Flag is a common interface related to parsing flags in cli.
|
|
// For more advanced flag parsing techniques, it is recomended 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)
|
|
}
|
|
}
|
|
|
|
type StringSlice []string
|
|
|
|
func (f *StringSlice) Set(value string) error {
|
|
*f = append(*f, value)
|
|
return nil
|
|
}
|
|
|
|
func (f *StringSlice) String() string {
|
|
return fmt.Sprintf("%s", *f)
|
|
}
|
|
|
|
func (f *StringSlice) Value() []string {
|
|
return *f
|
|
}
|
|
|
|
type StringSliceFlag struct {
|
|
Name string
|
|
Value *StringSlice
|
|
Usage string
|
|
}
|
|
|
|
func (f StringSliceFlag) String() string {
|
|
return fmt.Sprintf("%s%s %v\t`%v` %s", prefixFor(f.Name), f.Name, f.Value, "-"+f.Name+" option -"+f.Name+" option", f.Usage)
|
|
}
|
|
|
|
func (f StringSliceFlag) Apply(set *flag.FlagSet) {
|
|
eachName(f.Name, func(name string) {
|
|
set.Var(f.Value, name, f.Usage)
|
|
})
|
|
}
|
|
|
|
func (f StringSliceFlag) getName() string {
|
|
return f.Name
|
|
}
|
|
|
|
type IntSlice []int
|
|
|
|
func (f *IntSlice) Set(value string) error {
|
|
|
|
tmp, err := strconv.Atoi(value)
|
|
if err != nil {
|
|
return err
|
|
} else {
|
|
*f = append(*f, tmp)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (f *IntSlice) String() string {
|
|
return fmt.Sprintf("%d", *f)
|
|
}
|
|
|
|
func (f *IntSlice) Value() []int {
|
|
return *f
|
|
}
|
|
|
|
type IntSliceFlag struct {
|
|
Name string
|
|
Value *IntSlice
|
|
Usage string
|
|
}
|
|
|
|
func (f IntSliceFlag) String() string {
|
|
firstName := strings.Trim(strings.Split(f.Name, ",")[0], " ")
|
|
pref := prefixFor(firstName)
|
|
return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), pref+firstName+" option "+pref+firstName+" option", f.Usage)
|
|
}
|
|
|
|
func (f IntSliceFlag) Apply(set *flag.FlagSet) {
|
|
eachName(f.Name, func(name string) {
|
|
set.Var(f.Value, name, f.Usage)
|
|
})
|
|
}
|
|
|
|
func (f IntSliceFlag) getName() string {
|
|
return f.Name
|
|
}
|
|
|
|
type BoolFlag struct {
|
|
Name string
|
|
Usage string
|
|
}
|
|
|
|
func (f BoolFlag) String() string {
|
|
return fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)
|
|
}
|
|
|
|
func (f BoolFlag) Apply(set *flag.FlagSet) {
|
|
eachName(f.Name, func(name string) {
|
|
set.Bool(name, false, f.Usage)
|
|
})
|
|
}
|
|
|
|
func (f BoolFlag) getName() string {
|
|
return f.Name
|
|
}
|
|
|
|
type BoolTFlag struct {
|
|
Name string
|
|
Usage string
|
|
}
|
|
|
|
func (f BoolTFlag) String() string {
|
|
return fmt.Sprintf("%s\t%v", prefixedNames(f.Name), f.Usage)
|
|
}
|
|
|
|
func (f BoolTFlag) Apply(set *flag.FlagSet) {
|
|
eachName(f.Name, func(name string) {
|
|
set.Bool(name, true, f.Usage)
|
|
})
|
|
}
|
|
|
|
func (f BoolTFlag) getName() string {
|
|
return f.Name
|
|
}
|
|
|
|
type StringFlag struct {
|
|
Name string
|
|
Value string
|
|
Usage string
|
|
}
|
|
|
|
func (f StringFlag) String() string {
|
|
return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage)
|
|
}
|
|
|
|
func (f StringFlag) Apply(set *flag.FlagSet) {
|
|
eachName(f.Name, func(name string) {
|
|
set.String(name, f.Value, f.Usage)
|
|
})
|
|
}
|
|
|
|
func (f StringFlag) getName() string {
|
|
return f.Name
|
|
}
|
|
|
|
type IntFlag struct {
|
|
Name string
|
|
Value int
|
|
Usage string
|
|
}
|
|
|
|
func (f IntFlag) String() string {
|
|
return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage)
|
|
}
|
|
|
|
func (f IntFlag) Apply(set *flag.FlagSet) {
|
|
eachName(f.Name, func(name string) {
|
|
set.Int(name, f.Value, f.Usage)
|
|
})
|
|
}
|
|
|
|
func (f IntFlag) getName() string {
|
|
return f.Name
|
|
}
|
|
|
|
type Float64Flag struct {
|
|
Name string
|
|
Value float64
|
|
Usage string
|
|
}
|
|
|
|
func (f Float64Flag) String() string {
|
|
return fmt.Sprintf("%s '%v'\t%v", prefixedNames(f.Name), f.Value, f.Usage)
|
|
}
|
|
|
|
func (f Float64Flag) Apply(set *flag.FlagSet) {
|
|
eachName(f.Name, func(name string) {
|
|
set.Float64(name, f.Value, f.Usage)
|
|
})
|
|
}
|
|
|
|
func (f Float64Flag) getName() string {
|
|
return f.Name
|
|
}
|
|
|
|
func prefixFor(name string) (prefix string) {
|
|
if len(name) == 1 {
|
|
prefix = "-"
|
|
} else {
|
|
prefix = "--"
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func prefixedNames(fullName string) (prefixed string) {
|
|
parts := strings.Split(fullName, ",")
|
|
for i, name := range parts {
|
|
name = strings.Trim(name, " ")
|
|
prefixed += prefixFor(name) + name
|
|
if i < len(parts)-1 {
|
|
prefixed += ", "
|
|
}
|
|
}
|
|
return
|
|
}
|