forked from alecthomas/kingpin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathalias.go
172 lines (151 loc) · 5.04 KB
/
alias.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
package kingpin
import (
"fmt"
"strings"
)
type aliasMixin struct {
aliases map[string]aliasKind
autoShortcut *bool // Only set if explicitly configured
}
type flagAlias struct {
*FlagClause
kind aliasKind
}
type aliasKind byte
const (
aliasNone aliasKind = iota
aliasName
aliasNegative
aliasShortcut
)
// Alias defines alias name that could be used instead of the long name.
func (f *FlagClause) Alias(aliases ...string) *FlagClause {
if aliases == nil {
f.aliases = nil // If supplied alias is nil, we clear the previously defined aliases
}
for _, alias := range aliases {
f.addAlias(alias, aliasName)
}
return f
}
// AutoShortcut enables automatic shortcut for this flag (overriding the flag group setting).
func (f *FlagClause) AutoShortcut() *FlagClause { return f.setAutoShortcut(true) }
// NoAutoShortcut disables automatic shortcut for this flag (overriding the flag group setting).
func (f *FlagClause) NoAutoShortcut() *FlagClause { return f.setAutoShortcut(false) }
func (f *FlagClause) setAutoShortcut(value bool) *FlagClause {
f.autoShortcut = &value
return f
}
// Add an alias to the selected flag.
func (f *FlagClause) addAlias(alias string, kind aliasKind) error {
if f.aliases == nil {
f.aliases = make(map[string]aliasKind)
}
if current, exist := f.aliases[alias]; exist && current != kind {
return fmt.Errorf("Alias %s already exist", alias)
}
f.aliases[alias] = kind
return nil
}
// This function find the corresponding flag either by name or though aliases.
// If the resulted flag correspond to a negative alias (-no-boolOption), invert is set to true
func (fg *flagGroup) getFlagAlias(name string) (flag *FlagClause, invert bool, err error) {
if err = fg.ensureAliases(); err != nil {
return
} else if flag = fg.long[name]; flag != nil {
return
} else if alias := fg.aliases[name]; alias.kind != aliasNone {
flag = alias.FlagClause
invert = alias.kind == aliasNegative
}
return
}
// Clear the aliases and regenerate it.
// Used when the ParseContext change to a sub command.
func (fg *flagGroup) resetAliases() error {
fg.aliases = nil
return fg.ensureAliases()
}
// Ensure that the aliases are evaluated.
// Called during the parsing since we do not know the nature of flags until we launch the parsing.
func (fg *flagGroup) ensureAliases() error {
if fg.aliases != nil {
return nil
}
// The alias map is not yet initialized, so we do it
fg.aliases = make(map[string]flagAlias)
for _, flag := range fg.flagOrder {
if err := fg.addShortcut(flag.name, flag); err != nil {
return err
}
if err := fg.addNegativeAlias(flag.name, flag, aliasNone); err != nil {
return err
}
for alias, kind := range flag.aliases {
if kind != aliasName {
continue
}
if err := fg.addGroupAlias(alias, flag, kind); err != nil {
return err
}
if err := fg.addShortcut(alias, flag); err != nil {
return err
}
}
}
return nil
}
// Add an alias to the current flag group and return an error if the alias conflict with another flag.
func (fg *flagGroup) addGroupAlias(name string, flag *FlagClause, kind aliasKind) error {
if existing := fg.long[name]; existing != nil {
return aliasErrorf("Alias %s on %s is already associated to flag %s", name, flag.name, existing.name)
}
if alias := fg.aliases[name]; alias.kind != aliasNone && (alias.kind != kind || alias.FlagClause != flag) {
return aliasErrorf("Alias %s on %s is already associated to flag %s", name, flag.name, alias.name)
}
if err := fg.addNegativeAlias(name, flag, kind); err != nil {
return err
}
fg.aliases[name] = flagAlias{FlagClause: flag, kind: kind}
if err := flag.addAlias(name, kind); err != nil {
return aliasErrorf("Unable to add alias %s to %s: %v", name, flag.name, err)
}
return nil
}
func (fg *flagGroup) addShortcut(name string, flag *FlagClause) error {
if flag.autoShortcut == nil {
flag.autoShortcut = &fg.autoShortcut
}
if !*flag.autoShortcut || flag.shorthand != 0 && !strings.Contains(name, "-") {
// We do not add single letter shortcut for flag that already have a shorthand
return nil
}
var shortcut string
for _, word := range strings.Split(name, "-") {
shortcut += string(word[0])
}
if err := fg.addGroupAlias(shortcut, flag, aliasShortcut); err != nil {
return err
}
return fg.addNegativeAlias(shortcut, flag, aliasShortcut)
}
// If the flag is a boolFlag, add its negative counterpart.
func (fg *flagGroup) addNegativeAlias(name string, flag *FlagClause, kind aliasKind) error {
if fb, isSwitch := flag.value.(boolFlag); kind != aliasNegative && isSwitch && fb.IsBoolFlag() {
if err := fg.addGroupAlias("no-"+name, flag, aliasNegative); err != nil {
return err
}
if len(name) <= 3 && !strings.Contains(name, "-") {
// For short single word name, we also negative form simply prefixed by a n
if err := fg.addGroupAlias("n"+name, flag, aliasNegative); err != nil {
return err
}
}
}
return nil
}
type aliasError string
func (ae aliasError) Error() string { return string(ae) }
func aliasErrorf(format string, args ...interface{}) aliasError {
return aliasError(fmt.Sprintf(format, args...))
}