Skip to content

Commit 103c934

Browse files
authored
Merge pull request #2088 from dearchap/issue_2056
Fix:(issue_2056) Add cmd.XXXArgs() functions for retrieving args
2 parents 117ef1c + f87d093 commit 103c934

File tree

6 files changed

+856
-148
lines changed

6 files changed

+856
-148
lines changed

args.go

Lines changed: 246 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,25 @@ func (a *stringSliceArgs) Slice() []string {
6161
return ret
6262
}
6363

64+
// Argument captures a positional argument that can
65+
// be parsed
6466
type Argument interface {
67+
// which this argument can be accessed using the given name
68+
HasName(string) bool
69+
70+
// Parse the given args and return unparsed args and/or error
6571
Parse([]string) ([]string, error)
72+
73+
// The usage template for this argument to use in help
6674
Usage() string
75+
76+
// The Value of this Arg
77+
Get() any
6778
}
6879

6980
// AnyArguments to differentiate between no arguments(nil) vs aleast one
7081
var AnyArguments = []Argument{
71-
&StringArg{
82+
&StringArgs{
7283
Max: -1,
7384
},
7485
}
@@ -77,14 +88,78 @@ type ArgumentBase[T any, C any, VC ValueCreator[T, C]] struct {
7788
Name string `json:"name"` // the name of this argument
7889
Value T `json:"value"` // the default value of this argument
7990
Destination *T `json:"-"` // the destination point for this argument
80-
Values *[]T `json:"-"` // all the values of this argument, only if multiple are supported
91+
UsageText string `json:"usageText"` // the usage text to show
92+
Config C `json:"config"` // config for this argument similar to Flag Config
93+
94+
value *T
95+
}
96+
97+
func (a *ArgumentBase[T, C, VC]) HasName(s string) bool {
98+
return s == a.Name
99+
}
100+
101+
func (a *ArgumentBase[T, C, VC]) Usage() string {
102+
if a.UsageText != "" {
103+
return a.UsageText
104+
}
105+
106+
usageFormat := "%[1]s"
107+
return fmt.Sprintf(usageFormat, a.Name)
108+
}
109+
110+
func (a *ArgumentBase[T, C, VC]) Parse(s []string) ([]string, error) {
111+
tracef("calling arg%[1] parse with args %[2]", a.Name, s)
112+
113+
var vc VC
114+
var t T
115+
value := vc.Create(a.Value, &t, a.Config)
116+
a.value = &t
117+
118+
tracef("attempting arg%[1] parse", &a.Name)
119+
if len(s) > 0 {
120+
if err := value.Set(s[0]); err != nil {
121+
return s, err
122+
}
123+
*a.value = value.Get().(T)
124+
tracef("set arg%[1] one value", a.Name, *a.value)
125+
}
126+
127+
if a.Destination != nil {
128+
tracef("setting destination")
129+
*a.Destination = *a.value
130+
}
131+
132+
if len(s) > 0 {
133+
return s[1:], nil
134+
}
135+
return s, nil
136+
}
137+
138+
func (a *ArgumentBase[T, C, VC]) Get() any {
139+
if a.value != nil {
140+
return *a.value
141+
}
142+
return a.Value
143+
}
144+
145+
// ArgumentsBase is a base type for slice arguments
146+
type ArgumentsBase[T any, C any, VC ValueCreator[T, C]] struct {
147+
Name string `json:"name"` // the name of this argument
148+
Value T `json:"value"` // the default value of this argument
149+
Destination *[]T `json:"-"` // the destination point for this argument
81150
UsageText string `json:"usageText"` // the usage text to show
82151
Min int `json:"minTimes"` // the min num of occurrences of this argument
83152
Max int `json:"maxTimes"` // the max num of occurrences of this argument, set to -1 for unlimited
84153
Config C `json:"config"` // config for this argument similar to Flag Config
154+
155+
values []T
85156
}
86157

87-
func (a *ArgumentBase[T, C, VC]) Usage() string {
158+
func (a *ArgumentsBase[T, C, VC]) HasName(s string) bool {
159+
return s == a.Name
160+
}
161+
162+
func (a *ArgumentsBase[T, C, VC]) Usage() string {
88163
if a.UsageText != "" {
89164
return a.UsageText
90165
}
@@ -102,7 +177,7 @@ func (a *ArgumentBase[T, C, VC]) Usage() string {
102177
return fmt.Sprintf(usageFormat, a.Name)
103178
}
104179

105-
func (a *ArgumentBase[T, C, VC]) Parse(s []string) ([]string, error) {
180+
func (a *ArgumentsBase[T, C, VC]) Parse(s []string) ([]string, error) {
106181
tracef("calling arg%[1] parse with args %[2]", &a.Name, s)
107182
if a.Max == 0 {
108183
fmt.Printf("WARNING args %s has max 0, not parsing argument\n", a.Name)
@@ -117,13 +192,15 @@ func (a *ArgumentBase[T, C, VC]) Parse(s []string) ([]string, error) {
117192
var vc VC
118193
var t T
119194
value := vc.Create(a.Value, &t, a.Config)
120-
values := []T{}
195+
a.values = []T{}
121196

197+
tracef("attempting arg%[1] parse", &a.Name)
122198
for _, arg := range s {
123199
if err := value.Set(arg); err != nil {
124200
return s, err
125201
}
126-
values = append(values, value.Get().(T))
202+
tracef("set arg%[1] one value", &a.Name, value.Get().(T))
203+
a.values = append(a.values, value.Get().(T))
127204
count++
128205
if count >= a.Max && a.Max > -1 {
129206
break
@@ -133,36 +210,173 @@ func (a *ArgumentBase[T, C, VC]) Parse(s []string) ([]string, error) {
133210
return s, fmt.Errorf("sufficient count of arg %s not provided, given %d expected %d", a.Name, count, a.Min)
134211
}
135212

136-
if a.Values == nil {
137-
a.Values = &values
138-
} else if count > 0 {
139-
*a.Values = values
140-
}
141-
142-
if a.Max == 1 && a.Destination != nil {
143-
if len(values) > 0 {
144-
*a.Destination = values[0]
145-
} else {
146-
*a.Destination = t
147-
}
213+
if a.Destination != nil {
214+
tracef("appending destination")
215+
*a.Destination = a.values // append(*a.Destination, a.values...)
148216
}
149217

150218
return s[count:], nil
151219
}
152220

221+
func (a *ArgumentsBase[T, C, VC]) Get() any {
222+
if a.values != nil {
223+
return a.values
224+
}
225+
return []T{}
226+
}
227+
153228
type (
154-
FloatArg = ArgumentBase[float64, NoConfig, floatValue]
155-
IntArg = ArgumentBase[int, IntegerConfig, intValue[int]]
156-
Int8Arg = ArgumentBase[int8, IntegerConfig, intValue[int8]]
157-
Int16Arg = ArgumentBase[int16, IntegerConfig, intValue[int16]]
158-
Int32Arg = ArgumentBase[int32, IntegerConfig, intValue[int32]]
159-
Int64Arg = ArgumentBase[int64, IntegerConfig, intValue[int64]]
160-
StringArg = ArgumentBase[string, StringConfig, stringValue]
161-
StringMapArg = ArgumentBase[map[string]string, StringConfig, StringMap]
162-
TimestampArg = ArgumentBase[time.Time, TimestampConfig, timestampValue]
163-
UintArg = ArgumentBase[uint, IntegerConfig, uintValue[uint]]
164-
Uint8Arg = ArgumentBase[uint8, IntegerConfig, uintValue[uint8]]
165-
Uint16Arg = ArgumentBase[uint16, IntegerConfig, uintValue[uint16]]
166-
Uint32Arg = ArgumentBase[uint32, IntegerConfig, uintValue[uint32]]
167-
Uint64Arg = ArgumentBase[uint64, IntegerConfig, uintValue[uint64]]
229+
FloatArg = ArgumentBase[float64, NoConfig, floatValue]
230+
IntArg = ArgumentBase[int, IntegerConfig, intValue[int]]
231+
Int8Arg = ArgumentBase[int8, IntegerConfig, intValue[int8]]
232+
Int16Arg = ArgumentBase[int16, IntegerConfig, intValue[int16]]
233+
Int32Arg = ArgumentBase[int32, IntegerConfig, intValue[int32]]
234+
Int64Arg = ArgumentBase[int64, IntegerConfig, intValue[int64]]
235+
StringArg = ArgumentBase[string, StringConfig, stringValue]
236+
StringMapArgs = ArgumentBase[map[string]string, StringConfig, StringMap]
237+
TimestampArg = ArgumentBase[time.Time, TimestampConfig, timestampValue]
238+
UintArg = ArgumentBase[uint, IntegerConfig, uintValue[uint]]
239+
Uint8Arg = ArgumentBase[uint8, IntegerConfig, uintValue[uint8]]
240+
Uint16Arg = ArgumentBase[uint16, IntegerConfig, uintValue[uint16]]
241+
Uint32Arg = ArgumentBase[uint32, IntegerConfig, uintValue[uint32]]
242+
Uint64Arg = ArgumentBase[uint64, IntegerConfig, uintValue[uint64]]
243+
244+
FloatArgs = ArgumentsBase[float64, NoConfig, floatValue]
245+
IntArgs = ArgumentsBase[int, IntegerConfig, intValue[int]]
246+
Int8Args = ArgumentsBase[int8, IntegerConfig, intValue[int8]]
247+
Int16Args = ArgumentsBase[int16, IntegerConfig, intValue[int16]]
248+
Int32Args = ArgumentsBase[int32, IntegerConfig, intValue[int32]]
249+
Int64Args = ArgumentsBase[int64, IntegerConfig, intValue[int64]]
250+
StringArgs = ArgumentsBase[string, StringConfig, stringValue]
251+
TimestampArgs = ArgumentsBase[time.Time, TimestampConfig, timestampValue]
252+
UintArgs = ArgumentsBase[uint, IntegerConfig, uintValue[uint]]
253+
Uint8Args = ArgumentsBase[uint8, IntegerConfig, uintValue[uint8]]
254+
Uint16Args = ArgumentsBase[uint16, IntegerConfig, uintValue[uint16]]
255+
Uint32Args = ArgumentsBase[uint32, IntegerConfig, uintValue[uint32]]
256+
Uint64Args = ArgumentsBase[uint64, IntegerConfig, uintValue[uint64]]
168257
)
258+
259+
func (c *Command) getArgValue(name string) any {
260+
tracef("command %s looking for args %s", c.Name, name)
261+
for _, arg := range c.Arguments {
262+
if arg.HasName(name) {
263+
tracef("command %s found args %s", c.Name, name)
264+
return arg.Get()
265+
}
266+
}
267+
tracef("command %s did not find args %s", c.Name, name)
268+
return nil
269+
}
270+
271+
func arg[T any](name string, c *Command) T {
272+
val := c.getArgValue(name)
273+
if a, ok := val.(T); ok {
274+
return a
275+
}
276+
var zero T
277+
return zero
278+
}
279+
280+
func (c *Command) StringArg(name string) string {
281+
return arg[string](name, c)
282+
}
283+
284+
func (c *Command) StringArgs(name string) []string {
285+
return arg[[]string](name, c)
286+
}
287+
288+
func (c *Command) FloatArg(name string) float64 {
289+
return arg[float64](name, c)
290+
}
291+
292+
func (c *Command) FloatArgs(name string) []float64 {
293+
return arg[[]float64](name, c)
294+
}
295+
296+
func (c *Command) IntArg(name string) int {
297+
return arg[int](name, c)
298+
}
299+
300+
func (c *Command) IntArgs(name string) []int {
301+
return arg[[]int](name, c)
302+
}
303+
304+
func (c *Command) Int8Arg(name string) int8 {
305+
return arg[int8](name, c)
306+
}
307+
308+
func (c *Command) Int8Args(name string) []int8 {
309+
return arg[[]int8](name, c)
310+
}
311+
312+
func (c *Command) Int16Arg(name string) int16 {
313+
return arg[int16](name, c)
314+
}
315+
316+
func (c *Command) Int16Args(name string) []int16 {
317+
return arg[[]int16](name, c)
318+
}
319+
320+
func (c *Command) Int32Arg(name string) int32 {
321+
return arg[int32](name, c)
322+
}
323+
324+
func (c *Command) Int32Args(name string) []int32 {
325+
return arg[[]int32](name, c)
326+
}
327+
328+
func (c *Command) Int64Arg(name string) int64 {
329+
return arg[int64](name, c)
330+
}
331+
332+
func (c *Command) Int64Args(name string) []int64 {
333+
return arg[[]int64](name, c)
334+
}
335+
336+
func (c *Command) UintArg(name string) uint {
337+
return arg[uint](name, c)
338+
}
339+
340+
func (c *Command) Uint8Arg(name string) uint8 {
341+
return arg[uint8](name, c)
342+
}
343+
344+
func (c *Command) Uint16Arg(name string) uint16 {
345+
return arg[uint16](name, c)
346+
}
347+
348+
func (c *Command) Uint32Arg(name string) uint32 {
349+
return arg[uint32](name, c)
350+
}
351+
352+
func (c *Command) Uint64Arg(name string) uint64 {
353+
return arg[uint64](name, c)
354+
}
355+
356+
func (c *Command) UintArgs(name string) []uint {
357+
return arg[[]uint](name, c)
358+
}
359+
360+
func (c *Command) Uint8Args(name string) []uint8 {
361+
return arg[[]uint8](name, c)
362+
}
363+
364+
func (c *Command) Uint16Args(name string) []uint16 {
365+
return arg[[]uint16](name, c)
366+
}
367+
368+
func (c *Command) Uint32Args(name string) []uint32 {
369+
return arg[[]uint32](name, c)
370+
}
371+
372+
func (c *Command) Uint64Args(name string) []uint64 {
373+
return arg[[]uint64](name, c)
374+
}
375+
376+
func (c *Command) TimestampArg(name string) time.Time {
377+
return arg[time.Time](name, c)
378+
}
379+
380+
func (c *Command) TimestampArgs(name string) []time.Time {
381+
return arg[[]time.Time](name, c)
382+
}

0 commit comments

Comments
 (0)