Ensure slice types can safely round-trip through flag.FlagSet

This commit is contained in:
Dan Buch 2016-04-29 02:30:49 -04:00
parent ee736e063a
commit d1b0c49a98
No known key found for this signature in database
GPG Key ID: FAEF12936DD3E3EC
2 changed files with 32 additions and 1 deletions

View File

@ -362,7 +362,8 @@ func lookupBoolT(name string, set *flag.FlagSet) bool {
func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) {
switch ff.Value.(type) { switch ff.Value.(type) {
case *StringSlice: case Serializeder:
set.Set(name, ff.Value.(Serializeder).Serialized())
default: default:
set.Set(name, ff.Value.String()) set.Set(name, ff.Value.String())
} }

30
flag.go
View File

@ -1,6 +1,7 @@
package cli package cli
import ( import (
"encoding/json"
"flag" "flag"
"fmt" "fmt"
"os" "os"
@ -10,6 +11,10 @@ import (
"time" "time"
) )
var (
slPfx = fmt.Sprintf("sl:::%d:::", time.Now().UTC().UnixNano())
)
// This flag enables bash-completion for all commands and subcommands // This flag enables bash-completion for all commands and subcommands
var BashCompletionFlag = BoolFlag{ var BashCompletionFlag = BoolFlag{
Name: "generate-bash-completion", Name: "generate-bash-completion",
@ -29,6 +34,11 @@ var HelpFlag = BoolFlag{
Usage: "show help", Usage: "show help",
} }
// Serializeder is used to circumvent the limitations of flag.FlagSet.Set
type Serializeder interface {
Serialized() string
}
// Flag is a common interface related to parsing flags in cli. // Flag is a common interface related to parsing flags in cli.
// For more advanced flag parsing techniques, it is recommended that // For more advanced flag parsing techniques, it is recommended that
// this interface be implemented. // this interface be implemented.
@ -130,6 +140,13 @@ func (f *StringSlice) Set(value string) error {
f.hasBeenSet = true f.hasBeenSet = true
} }
if strings.HasPrefix(value, slPfx) {
v := []string{}
_ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), v)
f.slice = append(f.slice, v...)
return nil
}
f.slice = append(f.slice, value) f.slice = append(f.slice, value)
return nil return nil
} }
@ -139,6 +156,12 @@ func (f *StringSlice) String() string {
return fmt.Sprintf("%s", f.slice) return fmt.Sprintf("%s", f.slice)
} }
// Serialized allows StringSlice to fulfill Serializeder
func (f *StringSlice) Serialized() string {
jsonBytes, _ := json.Marshal(f.slice)
return fmt.Sprintf("%s%s", slPfx, string(jsonBytes))
}
// Value returns the slice of strings set by this flag // Value returns the slice of strings set by this flag
func (f *StringSlice) Value() []string { func (f *StringSlice) Value() []string {
return f.slice return f.slice
@ -219,6 +242,13 @@ func (i *IntSlice) Set(value string) error {
i.hasBeenSet = true i.hasBeenSet = true
} }
if strings.HasPrefix(slPfx, value) {
v := []int{}
_ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), v)
i.slice = append(i.slice, v...)
return nil
}
tmp, err := strconv.Atoi(value) tmp, err := strconv.Atoi(value)
if err != nil { if err != nil {
return err return err