This repository has been archived by the owner on Aug 27, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
flag_string_slice.go
267 lines (230 loc) · 7.19 KB
/
flag_string_slice.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
// Copyright 2020 The vine Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cli
import (
"encoding/json"
"flag"
"fmt"
"strings"
)
// StringSlice wraps a []string to satisfy flag.Value
type StringSlice struct {
value *[]string
hasBeenSet bool
}
// NewStringSlice creates a *StringSlice with default values
func NewStringSlice(defaults ...string) *StringSlice {
return newStringSlice(defaults, nil)
}
func newStringSlice(value []string, p *[]string) *StringSlice {
slice := new(StringSlice)
if p == nil {
p = &[]string{}
}
slice.value = p
*slice.value = value
return slice
}
// Set appends the string value to the list of values
func (s *StringSlice) Set(value string) error {
if !s.hasBeenSet {
s.value = &[]string{}
s.hasBeenSet = true
}
if strings.HasPrefix(value, slPfx) {
// Deserializing assumes overwrite
_ = json.Unmarshal([]byte(strings.Replace(value, slPfx, "", 1)), &(*s.value))
s.hasBeenSet = true
return nil
}
tmp, err := stringSliceConv(value)
if err != nil {
return err
}
*s.value = append(*s.value, tmp...)
return nil
}
func stringSliceConv(val string) ([]string, error) {
val = strings.Trim(val, "[]")
// Empty string would cause a slice with one (empty) entry
if len(val) == 0 {
return []string{}, nil
}
ss := strings.Split(val, ",")
out := make([]string, len(ss))
for i, s := range ss {
out[i] = strings.TrimSpace(s)
}
return out, nil
}
// String returns a readable representation of this value (for usage defaults)
func (s *StringSlice) String() string {
if s.value == nil {
return "[]"
}
out := make([]string, len(*s.value))
for i, s := range *s.value {
out[i] = strings.TrimSpace(s)
}
return "[" + strings.Join(out, ",") + "]"
}
// Serialize allows StringSlice to fulfill Serializer
func (s *StringSlice) Serialize() string {
jsonBytes, _ := json.Marshal(*s.value)
return fmt.Sprintf("%s%s", slPfx, string(jsonBytes))
}
// Value returns the slice of strings set by this flag
func (s *StringSlice) Value() []string {
if s.value == nil {
s.value = &[]string{}
}
return *s.value
}
// Get returns the slice of strings set by this flag
func (s *StringSlice) Get() interface{} {
return *s
}
// StringSliceFlag is a flag with type *StringSlice
type StringSliceFlag struct {
Name string
Aliases []string
Usage string
EnvVars []string
FilePath string
Required bool
Hidden bool
TakesFile bool
Value *StringSlice
DefaultText string
HasBeenSet bool
}
// IsSet returns whether or not the flag has been set through env or file
func (f *StringSliceFlag) IsSet() bool {
return f.HasBeenSet
}
// String returns a readable representation of this value
// (for usage defaults)
func (f *StringSliceFlag) String() string {
return FlagStringer(f)
}
// Names returns the names of the flag
func (f *StringSliceFlag) Names() []string {
return flagNames(f.Name, f.Aliases)
}
// IsRequired returns whether or not the flag is required
func (f *StringSliceFlag) IsRequired() bool {
return f.Required
}
// TakesValue returns true of the flag takes a value, otherwise false
func (f *StringSliceFlag) TakesValue() bool {
return true
}
// GetUsage returns the usage string for the flag
func (f *StringSliceFlag) GetUsage() string {
return f.Usage
}
// GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all.
func (f *StringSliceFlag) GetValue() string {
if f.Value != nil {
return f.Value.String()
}
return ""
}
// Apply populates the flag given the flag set and environment
func (f *StringSliceFlag) Apply(set *flag.FlagSet) error {
if val, ok := flagFromEnvOrFile(f.EnvVars, f.FilePath); ok {
f.Value = &StringSlice{}
for _, s := range strings.Split(val, ",") {
if err := f.Value.Set(strings.TrimSpace(s)); err != nil {
return fmt.Errorf("could not parse %q as string value for flag %s: %s", val, f.Name, err)
}
}
f.HasBeenSet = true
}
for _, name := range f.Names() {
if f.Value == nil {
f.Value = &StringSlice{}
}
set.Var(f.Value, name, f.Usage)
}
return nil
}
func (a *App) stringSliceVar(p *[]string, name, alias string, value []string, usage, env string) {
if a.Flags == nil {
a.Flags = make([]Flag, 0)
}
flag := &StringSliceFlag{
Name: name,
Usage: usage,
Value: newStringSlice(value, p),
}
if alias != "" {
flag.Aliases = []string{alias}
}
if env != "" {
flag.EnvVars = []string{env}
}
a.Flags = append(a.Flags, flag)
}
// StringSliceVar defines a []string flag with specified name, default value, usage string and env string.
// The argument p points to a []string variable in which to store the value of the flag.
func (a *App) StringSliceVar(p *[]string, name string, value []string, usage, env string) {
a.stringSliceVar(p, name, "", value, usage, env)
}
// StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash.
func (a *App) StringSliceVarP(p *[]string, name, alias string, value []string, usage, env string) {
a.stringSliceVar(p, name, alias, value, usage, env)
}
// StringSliceVar defines a string flag with specified name, default value, usage string and env string.
// The argument p points to a string variable in which to store the value of the flag.
func StringSliceVar(p *[]string, name string, value []string, usage, env string) {
CommandLine.StringSliceVar(p, name, value, usage, env)
}
// StringSliceVarP is like StringSliceVar, but accepts a shorthand letter that can be used after a single dash.
func StringSliceVarP(p *[]string, name, alias string, value []string, usage, env string) {
CommandLine.StringSliceVarP(p, name, alias, value, usage, env)
}
// StringSlice defines a string flag with specified name, default value, usage string and env string.
// The return value is the address of a string variable that stores the value of the flag.
func (a *App) StringSlice(name string, value []string, usage, env string) *[]string {
p := new([]string)
a.StringSliceVar(p, name, value, usage, env)
return p
}
// StringSliceP is like StringSlice, but accepts a shorthand letter that can be used after a single dash.
func (a *App) StringSliceP(name, alias string, value []string, usage, env string) *[]string {
p := new([]string)
a.StringSliceVarP(p, name, alias, value, usage, env)
return p
}
// StringSlice looks up the value of a local StringSliceFlag, returns
// nil if not found
func (c *Context) StringSlice(name string) []string {
if fs := lookupFlagSet(name, c); fs != nil {
return lookupStringSlice(name, fs)
}
return nil
}
func lookupStringSlice(name string, set *flag.FlagSet) []string {
f := set.Lookup(name)
if f != nil {
parsed, err := (f.Value.(*StringSlice)).Value(), error(nil)
if err != nil {
return nil
}
return parsed
}
return nil
}