forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 1
/
flags.go
148 lines (128 loc) · 4.72 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
package flags
import (
"fmt"
"strings"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"
)
// Apply stores the provided arguments onto a flag set, reporting any errors
// encountered during the process.
func Apply(args map[string][]string, flags *pflag.FlagSet) []error {
var errs []error
for key, value := range args {
flag := flags.Lookup(key)
if flag == nil {
errs = append(errs, field.Invalid(field.NewPath("flag"), key, "is not a valid flag"))
continue
}
for _, s := range value {
if err := flag.Value.Set(s); err != nil {
errs = append(errs, field.Invalid(field.NewPath(key), s, fmt.Sprintf("could not be set: %v", err)))
break
}
}
}
return errs
}
func Resolve(args map[string][]string, fn func(*pflag.FlagSet)) []error {
fs := pflag.NewFlagSet("extended", pflag.ContinueOnError)
fn(fs)
return Apply(args, fs)
}
// ComponentFlag represents a set of enabled components used in a command line.
type ComponentFlag struct {
enabled string
disabled string
enabledSet func() bool
calculated sets.String
allowed sets.String
mappings map[string][]string
}
// NewComponentFlag returns a flag that represents the allowed components and can be bound to command line flags.
func NewComponentFlag(mappings map[string][]string, allowed ...string) *ComponentFlag {
set := sets.NewString(allowed...)
return &ComponentFlag{
allowed: set,
mappings: mappings,
enabled: strings.Join(set.List(), ","),
enabledSet: func() bool { return false },
}
}
// DefaultEnable resets the enabled components to only those provided that are also in the allowed
// list.
func (f *ComponentFlag) DefaultEnable(components ...string) *ComponentFlag {
f.enabled = strings.Join(f.allowed.Union(sets.NewString(components...)).List(), ",")
return f
}
// DefaultDisable resets the default enabled set to all allowed components except the provided.
func (f *ComponentFlag) DefaultDisable(components ...string) *ComponentFlag {
f.enabled = strings.Join(f.allowed.Difference(sets.NewString(components...)).List(), ",")
return f
}
// Disable marks the provided components as disabled.
func (f *ComponentFlag) Disable(components ...string) {
f.Calculated().Delete(components...)
}
// Enabled returns true if the component is enabled.
func (f *ComponentFlag) Enabled(name string) bool {
return f.Calculated().Has(name)
}
// Calculated returns the effective enabled list.
func (f *ComponentFlag) Calculated() sets.String {
if f.calculated == nil {
f.calculated = f.Expand(f.enabled).Difference(f.Expand(f.disabled)).Intersection(f.allowed)
}
return f.calculated
}
// Validate returns a copy of the set of enabled components, or an error if there are conflicts.
func (f *ComponentFlag) Validate() (sets.String, error) {
enabled := f.Expand(f.enabled)
disabled := f.Expand(f.disabled)
if diff := enabled.Difference(f.allowed); enabled.Len() > 0 && diff.Len() > 0 {
return nil, fmt.Errorf("the following components are not recognized: %s", strings.Join(diff.List(), ", "))
}
if diff := disabled.Difference(f.allowed); disabled.Len() > 0 && diff.Len() > 0 {
return nil, fmt.Errorf("the following components are not recognized: %s", strings.Join(diff.List(), ", "))
}
if inter := enabled.Intersection(disabled); f.enabledSet() && inter.Len() > 0 {
return nil, fmt.Errorf("the following components can't be both disabled and enabled: %s", strings.Join(inter.List(), ", "))
}
return enabled.Difference(disabled), nil
}
// Expand turns a string into a fully expanded set of components, resolving any mappings.
func (f *ComponentFlag) Expand(value string) sets.String {
if len(value) == 0 {
return sets.NewString()
}
items := strings.Split(value, ",")
set := sets.NewString()
for _, s := range items {
if mapped, ok := f.mappings[s]; ok {
set.Insert(mapped...)
} else {
set.Insert(s)
}
}
return set
}
// Allowed returns a copy of the allowed list of components.
func (f *ComponentFlag) Allowed() sets.String {
return sets.NewString(f.allowed.List()...)
}
// Mappings returns a copy of the mapping list for short names.
func (f *ComponentFlag) Mappings() map[string][]string {
copied := make(map[string][]string)
for k, v := range f.mappings {
copiedV := make([]string, len(v))
copy(copiedV, v)
copied[k] = copiedV
}
return copied
}
// Bind registers the necessary flags with a flag set.
func (f *ComponentFlag) Bind(flags *pflag.FlagSet, flagFormat, messagePrefix string) {
flags.StringVar(&f.enabled, fmt.Sprintf(flagFormat, "enable"), f.enabled, messagePrefix+" enable")
flags.StringVar(&f.disabled, fmt.Sprintf(flagFormat, "disable"), f.disabled, messagePrefix+" disable")
f.enabledSet = func() bool { return flags.Lookup(fmt.Sprintf(flagFormat, "enable")).Changed }
}