forked from knative/client-pkg
/
bool.go
126 lines (112 loc) · 3.57 KB
/
bool.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
// Copyright © 2019 The Knative 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
import (
"fmt"
"strconv"
"strings"
"unicode"
"unicode/utf8"
"github.com/spf13/pflag"
)
var (
negPrefix = "no-"
)
// AddBothBoolFlagsUnhidden is just like AddBothBoolFlags but shows both flags.
func AddBothBoolFlagsUnhidden(f *pflag.FlagSet, p *bool, name, short string, value bool, usage string) {
negativeName := negPrefix + name
f.BoolVarP(p, name, short, value, usage)
f.Bool(negativeName, !value, InvertUsage(usage))
}
// AddBothBoolFlags adds the given flag in both `--foo` and `--no-foo` variants.
// If you do this, make sure you call ReconcileBoolFlags later to catch errors
// and set the relationship between the flag values. Only the flag that does the
// non-default behavior is visible; the other is hidden.
func AddBothBoolFlags(f *pflag.FlagSet, p *bool, name, short string, value bool, usage string) {
AddBothBoolFlagsUnhidden(f, p, name, short, value, usage)
negativeName := negPrefix + name
if value {
err := f.MarkHidden(name)
if err != nil {
panic(err)
}
} else {
err := f.MarkHidden(negativeName)
if err != nil {
panic(err)
}
}
}
// ReconcileBoolFlags sets the value of the all the "--foo" flags based on
// "--no-foo" if provided, and returns an error if both were provided or an
// explicit value of false was provided to either (as that's confusing).
func ReconcileBoolFlags(f *pflag.FlagSet) error {
var err error
f.VisitAll(func(flag *pflag.Flag) {
// Return early from our comprehension
if err != nil {
return
}
// Walk the "no-" versions of the flags. Make sure we didn't set
// both, and set the positive value to the opposite of the "no-"
// value if it exists.
if strings.HasPrefix(flag.Name, negPrefix) {
positiveName := flag.Name[len(negPrefix):]
positive := f.Lookup(positiveName)
// Non-paired flag, or wrong types
if positive == nil || positive.Value.Type() != "bool" || flag.Value.Type() != "bool" {
return
}
if flag.Changed {
if positive.Changed {
err = fmt.Errorf("only one of --%s and --%s may be specified",
flag.Name, positiveName)
return
}
err = checkExplicitFalse(flag, positiveName)
if err != nil {
return
}
err = positive.Value.Set("false")
} else {
err = checkExplicitFalse(positive, flag.Name)
}
}
})
return err
}
// checkExplicitFalse returns an error if the flag was explicitly set to false.
func checkExplicitFalse(f *pflag.Flag, betterFlag string) error {
if !f.Changed {
return nil
}
val, err := strconv.ParseBool(f.Value.String())
if err != nil {
return err
}
if !val {
return fmt.Errorf("use --%s instead of providing \"%s\" to --%s",
betterFlag, f.Value.String(), f.Name)
}
return nil
}
// FirstCharToLower converts first char in given string to lowercase
func FirstCharToLower(s string) string {
r, n := utf8.DecodeRuneInString(s)
return string(unicode.ToLower(r)) + s[n:]
}
// InvertUsage inverts the usage string with prefix "Do not"
func InvertUsage(usage string) string {
return "Do not " + FirstCharToLower(usage)
}