forked from openshift/origin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
flags.go
135 lines (117 loc) · 4.17 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
package flags
import (
"fmt"
"strings"
"github.com/spf13/pflag"
"k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/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 },
}
}
// 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 }
}