-
Notifications
You must be signed in to change notification settings - Fork 0
/
args.go
129 lines (108 loc) · 3.17 KB
/
args.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
package cli
import (
"fmt"
"strings"
"github.com/awee-ai/structs"
)
const tagArg = "arg"
const tagShort = "short"
const optionPrefix = "-"
const keyValuePairSeparator = "="
const catchAllChar = "-"
func findField(fields []structs.Field, tag string, name string) *structs.Field {
for _, field := range fields {
if field.Tags[tag] != "" && field.Tags[tag] == name {
return &field
}
}
return nil
}
// getCommandArgs parses the args line arguments and returns the parsed args and options and all unknowns
func getCommandArgs(args []string, fields []structs.Field) ([]string, []string, map[string]any, map[string]any) {
if len(args) < 1 {
return []string{}, []string{}, map[string]any{}, map[string]any{}
}
var parsedArgs = make([]string, 0)
var unknownArgs = make([]string, 0)
var parsedOptions = make(map[string]any)
var unknownOptions = make(map[string]any)
for index := 0; index < len(args); index++ {
arg := args[index]
// logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
// logger = logger.With("i", index)
// "-key arg" or "-key=value" syntax
if strings.HasPrefix(arg, optionPrefix) {
dePrefixedArg := strings.TrimLeft(arg, optionPrefix)
var foundField *structs.Field
for _, field := range fields {
if field.Tags[tagArg] == dePrefixedArg {
foundField = &field
break
} else if field.Tags[tagShort] == dePrefixedArg {
foundField = &field
break
}
}
// TODO: handle key=value syntax
// if strings.Contains(arg, keyValuePairSeparator) {
// optionName, optionValue := splitKeyValue(arg)
// addOption(parsedOptions, optionName, optionValue)
// }
if foundField != nil {
// empty bool options are set to true
// logger.Info("field", "opt", dePrefixedArg, "type", foundField.Type)
if foundField.Type == "bool" {
parsedOptions[dePrefixedArg] = true
continue
}
// next arg is the value for the current option
nextArg := ""
if len(args) > index+1 {
nextArg = args[index+1]
}
parsedOptions[dePrefixedArg] = nextArg
// skip the next arg
index++
continue
} else {
if len(args) > index+1 {
nextArg := args[index+1]
unknownOptions[dePrefixedArg] = nextArg
index++
continue
}
unknownOptions[dePrefixedArg] = true
}
}
// arg is not an option, it's a command or an argument
if !strings.HasPrefix(arg, optionPrefix) {
var foundField *structs.Field
for _, field := range fields {
if field.Tags[tagArg] == fmt.Sprintf("%d", index) {
foundField = &field
break
} else if field.Tags[tagShort] == fmt.Sprintf("%d", index) {
foundField = &field
break
}
}
if foundField != nil {
parsedArgs = append(parsedArgs, arg)
} else {
unknownArgs = append(unknownArgs, arg)
}
}
}
return parsedArgs, unknownArgs, parsedOptions, unknownOptions
}
func splitKeyValue(arg string) (string, string) {
pair := strings.SplitN(arg, keyValuePairSeparator, 2)
optionName := pair[0]
optionName = strings.TrimLeft(optionName, "-")
optionValue := ""
if len(pair) > 1 {
optionValue = pair[1]
}
// slog.Info("key=value", "opt", optionName, "value", optionValue)
return optionName, optionValue
}