-
Notifications
You must be signed in to change notification settings - Fork 0
/
args.go
187 lines (145 loc) · 3.68 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
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
package main
import (
"errors"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"regexp"
"strings"
"gopkg.in/yaml.v2"
)
type VarValues map[interface{}]interface{}
func (dest *VarValues) Merge(src VarValues) {
for k, v := range src {
(*dest)[k] = v
}
}
type VarValuesable interface {
Values() VarValues
}
type Var struct {
Name string
Value string
}
func (v Var) Values() VarValues {
var vv = make(VarValues)
vv[v.Name] = v.Value
return vv
}
type Vars []Var
func (v *Vars) Set(value string) error {
parts := strings.SplitN(value, "=", 2)
if len(parts) != 2 {
return errors.New("argument should be in the form: name=value")
}
varName := strings.TrimSpace(parts[0])
if len(varName) == 0 {
return errors.New("no name defined for template variable")
}
*v = append(*v, Var{Name: varName, Value: parts[1]})
return nil
}
func (v *Vars) String() string {
var s []string
for _, i := range *v {
s = append(s, fmt.Sprintf("%v=%v", i.Name, i.Value))
}
return strings.Join(s, ", ")
}
type VarFile string
func (v VarFile) Values() VarValues {
var vv VarValues
data, err := ioutil.ReadFile(string(v))
if err != nil {
log.Fatal(err)
}
yaml.Unmarshal(data, &vv)
return vv
}
type VarFiles []VarFile
func (v *VarFiles) Set(value string) error {
if value == "" {
return errors.New("no filename defined")
}
varFilesRegexp := regexp.MustCompile(`^(.+)\.y(a)?ml$`)
if !varFilesRegexp.Match([]byte(value)) {
return errors.New("only YAML files are supported")
}
*v = append(*v, VarFile(value))
return nil
}
func (v *VarFiles) String() string {
var s []string
for _, i := range *v {
s = append(s, string(i))
}
return strings.Join(s, ", ")
}
type Args struct {
Help bool
Version bool
Force bool
PreCheck bool
InputFile string
WriteFile string
Vars Vars
VarFiles VarFiles
}
func fatalError(message string) {
fmt.Println("Error:", message)
fmt.Printf("\n---\n\n")
flag.Usage()
os.Exit(1)
}
func ParseArgs() Args {
args := Args{}
flag.BoolVar(&args.Help, "help", false, "Display this help message")
flag.BoolVar(&args.Version, "version", false, "Print version and exit")
flag.BoolVar(&args.Force, "force", false, "Force file overwrite")
flag.BoolVar(&args.PreCheck, "pre-check", false, "Check a file for issues prior to editing as a go template")
flag.Var(&args.Vars, "var", "Define a template variable (e.g., -var name=value)")
flag.Var(&args.VarFiles, "var-file", "Import template variables from a file (e.g., -var-file vars.yaml)")
flag.StringVar(&args.WriteFile, "write-file", "", "Output the interpolated template to a file")
// Custom usage message
flag.Usage = func() {
PrintVersion()
fmt.Println(`
Usage:-
prep [args] <input file>`)
fmt.Println()
flag.PrintDefaults()
fmt.Println(`
Command examples:-
Processes "my_file.conf.tmpl", using variables defined in the variables file
"my_vars.yaml" and defining/overriding the variable "username" and outputting
the result to the terminal:
prep -var-file my_vars.yaml -var username=jbloggs my_file.conf.tmpl
... the same command, but writes specifically to the named file, "my_file.conf":
prep -var-file my_vars.yaml -var username=jbloggs -write-file my_file.conf -force my_file.conf.tmpl
A useful command to check for any go templating related issues before you start
adding any go template syntax:
prep -pre-check my_file.conf.tmpl`)
fmt.Println()
}
flag.Parse()
if args.Help {
flag.Usage()
os.Exit(0)
}
if args.Version {
PrintVersion()
os.Exit(0)
}
// Parse positional arguments
switch flag.NArg() {
case 0:
fatalError("no input file specified")
case 1:
args.InputFile = flag.Arg(0)
default:
fatalError("this command takes a maximum of one input file")
}
return args
}