-
Notifications
You must be signed in to change notification settings - Fork 4.4k
/
flags.go
178 lines (159 loc) · 4.38 KB
/
flags.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
/*
*
* Copyright 2019 gRPC 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 flags provide convenience types and routines to accept specific types
of flag values on the command line.
*/
package flags
import (
"bytes"
"encoding/csv"
"flag"
"fmt"
"strconv"
"strings"
"time"
)
// stringFlagWithAllowedValues represents a string flag which can only take a
// predefined set of values.
type stringFlagWithAllowedValues struct {
val string
allowed []string
}
// StringWithAllowedValues returns a flag variable of type
// stringFlagWithAllowedValues configured with the provided parameters.
// 'allowed` is the set of values that this flag can be set to.
func StringWithAllowedValues(name, defaultVal, usage string, allowed []string) *string {
as := &stringFlagWithAllowedValues{defaultVal, allowed}
flag.CommandLine.Var(as, name, usage)
return &as.val
}
// String implements the flag.Value interface.
func (as *stringFlagWithAllowedValues) String() string {
return as.val
}
// Set implements the flag.Value interface.
func (as *stringFlagWithAllowedValues) Set(val string) error {
for _, a := range as.allowed {
if a == val {
as.val = val
return nil
}
}
return fmt.Errorf("want one of: %v", strings.Join(as.allowed, ", "))
}
type durationSliceValue []time.Duration
// DurationSlice returns a flag representing a slice of time.Duration objects.
func DurationSlice(name string, defaultVal []time.Duration, usage string) *[]time.Duration {
ds := make([]time.Duration, len(defaultVal))
copy(ds, defaultVal)
dsv := (*durationSliceValue)(&ds)
flag.CommandLine.Var(dsv, name, usage)
return &ds
}
// Set implements the flag.Value interface.
func (dsv *durationSliceValue) Set(s string) error {
ds := strings.Split(s, ",")
var dd []time.Duration
for _, n := range ds {
d, err := time.ParseDuration(n)
if err != nil {
return err
}
dd = append(dd, d)
}
*dsv = durationSliceValue(dd)
return nil
}
// String implements the flag.Value interface.
func (dsv *durationSliceValue) String() string {
var b bytes.Buffer
for i, d := range *dsv {
if i > 0 {
b.WriteRune(',')
}
b.WriteString(d.String())
}
return b.String()
}
type intSliceValue []int
// IntSlice returns a flag representing a slice of ints.
func IntSlice(name string, defaultVal []int, usage string) *[]int {
is := make([]int, len(defaultVal))
copy(is, defaultVal)
isv := (*intSliceValue)(&is)
flag.CommandLine.Var(isv, name, usage)
return &is
}
// Set implements the flag.Value interface.
func (isv *intSliceValue) Set(s string) error {
is := strings.Split(s, ",")
var ret []int
for _, n := range is {
i, err := strconv.Atoi(n)
if err != nil {
return err
}
ret = append(ret, i)
}
*isv = intSliceValue(ret)
return nil
}
// String implements the flag.Value interface.
func (isv *intSliceValue) String() string {
var b bytes.Buffer
for i, n := range *isv {
if i > 0 {
b.WriteRune(',')
}
b.WriteString(strconv.Itoa(n))
}
return b.String()
}
type stringSliceValue []string
// StringSlice returns a flag representing a slice of strings.
func StringSlice(name string, defaultVal []string, usage string) *[]string {
ss := make([]string, len(defaultVal))
copy(ss, defaultVal)
ssv := (*stringSliceValue)(&ss)
flag.CommandLine.Var(ssv, name, usage)
return &ss
}
// escapedCommaSplit splits a comma-separated list of strings in the same way
// CSV files work (escaping a comma requires double-quotes).
func escapedCommaSplit(str string) ([]string, error) {
r := csv.NewReader(strings.NewReader(str))
ret, err := r.Read()
if err != nil {
return nil, err
}
return ret, nil
}
// Set implements the flag.Value interface.
func (ss *stringSliceValue) Set(str string) error {
var err error
*ss, err = escapedCommaSplit(str)
if err != nil {
return err
}
return nil
}
// String implements the flag.Value interface.
func (ss *stringSliceValue) String() string {
return strings.Join(*ss, ",")
}