-
Notifications
You must be signed in to change notification settings - Fork 0
/
flag.go
130 lines (105 loc) · 2.71 KB
/
flag.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
package cli
import (
"fmt"
"strings"
"github.com/rdeusser/cli/internal/join"
)
var HelpFlag = &Flag[bool]{
Name: "help",
Shorthand: "h",
Desc: "Print help information",
}
// Flags is a slice of flags represented as Options.
type Flags []option
func (flags Flags) Lookup(name string) option {
for _, flag := range flags {
if matchesFlag(name, flag) {
return flag
}
}
return nil
}
var _ option = (*Flag[bool])(nil)
// Flag is a generic type for defining flags with types constrained by Value.
type Flag[T Value] struct {
Name string
Shorthand string
Desc string
Separator byte // only applies if the value is actually many
Layout string // only applies to time.Time values
Default T
Value *T
EnvVar EnvVar[T]
Required bool
isSlice bool
hasBeenSet bool
}
// Init initializes the value of a flag.
func (f *Flag[T]) Init() error {
if f.Value == nil {
f.Value = new(T)
}
if len(f.Shorthand) > 1 {
return ErrInvalidShorthand
}
if !isZeroValue(f.Default) {
result, err := parseValue[T](f.Default, f.Separator, f.Layout)
if err != nil {
return err
}
*f.Value = result
}
if f.EnvVar.Name != "" {
result, err := parseValue[T](f.EnvVar.Name, f.Separator, f.Layout)
if err != nil {
return err
}
*f.Value = result
}
return nil
}
// Set parses the value of s and sets the value according to the flags type.
func (f *Flag[T]) Set(s string) error {
value, err := parseValue[T](s, f.Separator, f.Layout)
if err != nil {
return err
}
*f.Value = value
f.isSlice = strings.HasPrefix(fmt.Sprint(value), "[")
f.hasBeenSet = true
return nil
}
// String returns the string form of the flags value.
func (f *Flag[T]) String() string {
if f == nil || f.Value == nil {
return ""
}
// If the flag type is a slice, we have to remove the brackets that
// fmt.Sprint will add, and rejoin the string with the flags separator.
return join.WithSeparator(trimBrackets(*f.Value), f.Separator)
}
// Options returns the common Options available to both flags and arguments.
func (f *Flag[T]) Options() Options {
t := *new(T)
if isZeroValue(f.Default) {
f.Default = t
}
return Options{
IsSlice: f.isSlice,
Name: f.Name,
Shorthand: f.Shorthand,
Desc: f.Desc,
Separator: f.Separator,
Layout: f.Layout,
Default: f.Default,
Value: f.Value,
EnvVar: f.EnvVar,
Required: f.Required,
HasBeenSet: f.hasBeenSet,
}
}
// SortFlagsByName sorts flags by name.
type SortFlagsByName Flags
func (n SortFlagsByName) Len() int { return len(n) }
func (n SortFlagsByName) Swap(i, j int) { n[i], n[j] = n[j], n[i] }
func (n SortFlagsByName) Less(i, j int) bool { return n[i].Options().Name < n[j].Options().Name }