From d1b0c49a988426023ab923a5b3b6baf4fae372df Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Fri, 29 Apr 2016 02:30:49 -0400 Subject: [PATCH] Ensure slice types can safely round-trip through flag.FlagSet --- context.go | 3 ++- flag.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/context.go b/context.go index c542a67..a4c3904 100644 --- a/context.go +++ b/context.go @@ -362,7 +362,8 @@ func lookupBoolT(name string, set *flag.FlagSet) bool { func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { switch ff.Value.(type) { - case *StringSlice: + case Serializeder: + set.Set(name, ff.Value.(Serializeder).Serialized()) default: set.Set(name, ff.Value.String()) } diff --git a/flag.go b/flag.go index 95eefc4..38029c4 100644 --- a/flag.go +++ b/flag.go @@ -1,6 +1,7 @@ package cli import ( + "encoding/json" "flag" "fmt" "os" @@ -10,6 +11,10 @@ import ( "time" ) +var ( + slPfx = fmt.Sprintf("sl:::%d:::", time.Now().UTC().UnixNano()) +) + // This flag enables bash-completion for all commands and subcommands var BashCompletionFlag = BoolFlag{ Name: "generate-bash-completion", @@ -29,6 +34,11 @@ var HelpFlag = BoolFlag{ 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. // For more advanced flag parsing techniques, it is recommended that // this interface be implemented. @@ -130,6 +140,13 @@ func (f *StringSlice) Set(value string) error { 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) return nil } @@ -139,6 +156,12 @@ func (f *StringSlice) String() string { 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 func (f *StringSlice) Value() []string { return f.slice @@ -219,6 +242,13 @@ func (i *IntSlice) Set(value string) error { 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) if err != nil { return err