-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
optional.go
160 lines (133 loc) · 3.89 KB
/
optional.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
/*
Copyright 2021 The Vitess 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 flagutil
import (
"errors"
"strconv"
"github.com/spf13/pflag"
)
// OptionalFlag augements the pflag.Value interface with a method to determine
// if a flag was set explicitly on the comand-line.
//
// Though not part of the interface, because the return type would be different
// for each implementation, by convention, each implementation should define a
// Get() method to access the underlying value.
//
// TODO (ajm188) - replace this interface with a generic type.
// c.f. https://github.com/vitessio/vitess/issues/11154.
type OptionalFlag interface {
pflag.Value
IsSet() bool
}
var (
_ OptionalFlag = (*OptionalFloat64)(nil)
_ OptionalFlag = (*OptionalString)(nil)
)
// OptionalFloat64 implements OptionalFlag for float64 values.
type OptionalFloat64 struct {
val float64
set bool
}
// NewOptionalFloat64 returns an OptionalFloat64 with the specified value as its
// starting value.
func NewOptionalFloat64(val float64) *OptionalFloat64 {
return &OptionalFloat64{
val: val,
set: false,
}
}
// Set is part of the pflag.Value interface.
func (f *OptionalFloat64) Set(arg string) error {
v, err := strconv.ParseFloat(arg, 64)
if err != nil {
return numError(err)
}
f.val = v
f.set = true
return nil
}
// String is part of the pflag.Value interface.
func (f *OptionalFloat64) String() string {
return strconv.FormatFloat(f.val, 'g', -1, 64)
}
// Type is part of the pflag.Value interface.
func (f *OptionalFloat64) Type() string {
return "float64"
}
// Get returns the underlying float64 value of this flag. If the flag was not
// explicitly set, this will be the initial value passed to the constructor.
func (f *OptionalFloat64) Get() float64 {
return f.val
}
// IsSet is part of the OptionalFlag interface.
func (f *OptionalFloat64) IsSet() bool {
return f.set
}
// OptionalString implements OptionalFlag for string values.
type OptionalString struct {
val string
set bool
}
// NewOptionalString returns an OptionalString with the specified value as its
// starting value.
func NewOptionalString(val string) *OptionalString {
return &OptionalString{
val: val,
set: false,
}
}
// Set is part of the pflag.Value interface.
func (f *OptionalString) Set(arg string) error {
f.val = arg
f.set = true
return nil
}
// String is part of the pflag.Value interface.
func (f *OptionalString) String() string {
return f.val
}
// Type is part of the pflag.Value interface.
func (f *OptionalString) Type() string {
return "string"
}
// Get returns the underlying string value of this flag. If the flag was not
// explicitly set, this will be the initial value passed to the constructor.
func (f *OptionalString) Get() string {
return f.val
}
// IsSet is part of the OptionalFlag interface.
func (f *OptionalString) IsSet() bool {
return f.set
}
// lifted directly from package flag to make the behavior of numeric parsing
// consistent with the standard library for our custom optional types.
var (
errParse = errors.New("parse error")
errRange = errors.New("value out of range")
)
// lifted directly from package flag to make the behavior of numeric parsing
// consistent with the standard library for our custom optional types.
func numError(err error) error {
ne, ok := err.(*strconv.NumError)
if !ok {
return err
}
switch ne.Err {
case strconv.ErrSyntax:
return errParse
case strconv.ErrRange:
return errRange
default:
return err
}
}