-
Notifications
You must be signed in to change notification settings - Fork 244
/
Copy pathargs.go
140 lines (122 loc) · 3.3 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
130
131
132
133
134
135
136
137
138
139
140
// Copyright 2017 Microsoft. All rights reserved.
// MIT License
package common
import (
"flag"
"fmt"
"os"
"strconv"
"strings"
)
// Argument represents a command line argument.
type Argument struct {
Name string
Shorthand string
Description string
Type string
DefaultValue interface{}
Value interface{}
ValueMap map[string]interface{}
strVal string
boolVal bool
}
// ArgumentList represents a set of command line arguments.
type ArgumentList []*Argument
var (
argList *ArgumentList
usageFunc func()
)
// ParseArgs parses and validates command line arguments based on rules in the given ArgumentList.
func ParseArgs(args *ArgumentList, usage func()) {
argList = args
usageFunc = usage
// Setup all arguments.
for _, arg := range *args {
switch arg.Type {
case "bool":
flag.BoolVar(&arg.boolVal, arg.Name, arg.DefaultValue.(bool), arg.Description)
flag.BoolVar(&arg.boolVal, arg.Shorthand, arg.DefaultValue.(bool), arg.Description)
case "int", "string":
flag.StringVar(&arg.strVal, arg.Name, arg.DefaultValue.(string), arg.Description)
flag.StringVar(&arg.strVal, arg.Shorthand, arg.DefaultValue.(string), arg.Description)
}
}
// Parse the flag set.
flag.Usage = printHelp
flag.Parse()
// Validate arguments and convert them to their mapped values.
for _, arg := range *args {
switch arg.Type {
case "bool":
arg.Value = arg.boolVal
case "string":
if arg.ValueMap == nil {
// Argument is a free-form string.
arg.Value = arg.strVal
} else {
// Argument must match one of the values in the map.
arg.strVal = strings.ToLower(arg.strVal)
arg.Value = arg.strVal
if arg.ValueMap[arg.strVal] == nil {
printErrorForArg(arg)
}
}
case "int":
if arg.ValueMap == nil {
// Argument is a free-form integer.
arg.Value, _ = strconv.Atoi(arg.strVal)
} else {
// Argument must match one of the values in the map.
arg.strVal = strings.ToLower(arg.strVal)
arg.Value = arg.ValueMap[arg.strVal]
if arg.Value == nil {
printErrorForArg(arg)
}
}
}
}
}
// GetArg returns the parsed value of the given argument.
func GetArg(name string) interface{} {
for _, arg := range *argList {
if arg.Name == name {
return arg.Value
}
}
return nil
}
// printErrorForArg prints the error line for the given argument.
func printErrorForArg(arg *Argument) {
fmt.Printf("Invalid value '%v' for argument '%v'.\n\n", arg.strVal, arg.Name)
flag.Usage()
os.Exit(1)
}
// printHelpForArg prints the help line for the given argument.
func printHelpForArg(arg *Argument) {
left := fmt.Sprintf(" -%v, --%v", arg.Shorthand, arg.Name)
right := fmt.Sprintf("%v", arg.Description)
if arg.ValueMap != nil {
left += fmt.Sprintf("=%v", arg.DefaultValue)
var values []string
for k := range arg.ValueMap {
values = append(values, k)
}
right += " {" + strings.Join(values, ",") + "}"
}
fmt.Printf("%-30v %v\n", left, right)
}
// printHelp prints help and usage information for the argument list.
func printHelp() {
usageFunc()
fmt.Printf("\nUsage: %v [OPTIONS]\n\n", os.Args[0])
fmt.Printf("Options:\n")
for _, arg := range *argList {
printHelpForArg(arg)
}
// -h is implicit.
printHelpForArg(&Argument{
Name: "help",
Shorthand: "h",
Description: "Print usage information",
})
}