...
1 package cli
2
3 import (
4 "encoding/json"
5 "flag"
6 "fmt"
7 "strconv"
8 "strings"
9 )
10
11
12 type StringSlice struct {
13 slice []string
14 separator separatorSpec
15 hasBeenSet bool
16 keepSpace bool
17 }
18
19
20 func NewStringSlice(defaults ...string) *StringSlice {
21 return &StringSlice{slice: append([]string{}, defaults...)}
22 }
23
24
25 func (s *StringSlice) clone() *StringSlice {
26 n := &StringSlice{
27 slice: make([]string, len(s.slice)),
28 hasBeenSet: s.hasBeenSet,
29 }
30 copy(n.slice, s.slice)
31 return n
32 }
33
34
35 func (s *StringSlice) Set(value string) error {
36 if !s.hasBeenSet {
37 s.slice = []string{}
38 s.hasBeenSet = true
39 }
40
41 if strings.HasPrefix(value, slPfx) {
42
43 _ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &s.slice)
44 s.hasBeenSet = true
45 return nil
46 }
47
48 for _, t := range s.separator.flagSplitMultiValues(value) {
49 if !s.keepSpace {
50 t = strings.TrimSpace(t)
51 }
52 s.slice = append(s.slice, t)
53 }
54
55 return nil
56 }
57
58 func (s *StringSlice) WithSeparatorSpec(spec separatorSpec) {
59 s.separator = spec
60 }
61
62
63 func (s *StringSlice) String() string {
64 return fmt.Sprintf("%s", s.slice)
65 }
66
67
68 func (s *StringSlice) Serialize() string {
69 jsonBytes, _ := json.Marshal(s.slice)
70 return fmt.Sprintf("%s%s", slPfx, string(jsonBytes))
71 }
72
73
74 func (s *StringSlice) Value() []string {
75 return s.slice
76 }
77
78
79 func (s *StringSlice) Get() interface{} {
80 return *s
81 }
82
83
84
85 func (f *StringSliceFlag) String() string {
86 return FlagStringer(f)
87 }
88
89
90 func (f *StringSliceFlag) TakesValue() bool {
91 return true
92 }
93
94
95 func (f *StringSliceFlag) GetUsage() string {
96 return f.Usage
97 }
98
99
100 func (f *StringSliceFlag) GetCategory() string {
101 return f.Category
102 }
103
104
105
106 func (f *StringSliceFlag) GetValue() string {
107 var defaultVals []string
108 if f.Value != nil && len(f.Value.Value()) > 0 {
109 for _, s := range f.Value.Value() {
110 if len(s) > 0 {
111 defaultVals = append(defaultVals, strconv.Quote(s))
112 }
113 }
114 }
115 return strings.Join(defaultVals, ", ")
116 }
117
118
119 func (f *StringSliceFlag) GetDefaultText() string {
120 if f.DefaultText != "" {
121 return f.DefaultText
122 }
123 return f.GetValue()
124 }
125
126
127 func (f *StringSliceFlag) GetEnvVars() []string {
128 return f.EnvVars
129 }
130
131
132 func (f *StringSliceFlag) IsSliceFlag() bool {
133 return true
134 }
135
136
137 func (f *StringSliceFlag) Apply(set *flag.FlagSet) error {
138
139 if f.Destination != nil && f.Value != nil {
140 f.Destination.slice = make([]string, len(f.Value.slice))
141 copy(f.Destination.slice, f.Value.slice)
142 }
143
144
145 var setValue *StringSlice
146 switch {
147 case f.Destination != nil:
148 setValue = f.Destination
149 case f.Value != nil:
150 setValue = f.Value.clone()
151 default:
152 setValue = new(StringSlice)
153 setValue.WithSeparatorSpec(f.separator)
154 }
155
156 setValue.keepSpace = f.KeepSpace
157
158 if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {
159 for _, s := range f.separator.flagSplitMultiValues(val) {
160 if !f.KeepSpace {
161 s = strings.TrimSpace(s)
162 }
163 if err := setValue.Set(s); err != nil {
164 return fmt.Errorf("could not parse %q as string value from %s for flag %s: %s", val, source, f.Name, err)
165 }
166 }
167
168
169
170 setValue.hasBeenSet = false
171 f.HasBeenSet = true
172 }
173
174 for _, name := range f.Names() {
175 set.Var(setValue, name, f.Usage)
176 }
177
178 return nil
179 }
180
181 func (f *StringSliceFlag) WithSeparatorSpec(spec separatorSpec) {
182 f.separator = spec
183 }
184
185
186 func (f *StringSliceFlag) Get(ctx *Context) []string {
187 return ctx.StringSlice(f.Name)
188 }
189
190
191 func (f *StringSliceFlag) RunAction(c *Context) error {
192 if f.Action != nil {
193 return f.Action(c, c.StringSlice(f.Name))
194 }
195
196 return nil
197 }
198
199
200
201 func (cCtx *Context) StringSlice(name string) []string {
202 if fs := cCtx.lookupFlagSet(name); fs != nil {
203 return lookupStringSlice(name, fs)
204 }
205 return nil
206 }
207
208 func lookupStringSlice(name string, set *flag.FlagSet) []string {
209 f := set.Lookup(name)
210 if f != nil {
211 if slice, ok := unwrapFlagValue(f.Value).(*StringSlice); ok {
212 return slice.Value()
213 }
214 }
215 return nil
216 }
217
View as plain text