-
Notifications
You must be signed in to change notification settings - Fork 14
/
argsAndFlags.go
447 lines (423 loc) · 15.7 KB
/
argsAndFlags.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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
package system
import (
"os"
"strings"
)
// get saptune arguments and flags
var saptArgs, saptFlags = ParseCliArgs()
// RereadArgs parses the cli parameter again
func RereadArgs() {
saptArgs, saptFlags = ParseCliArgs()
}
// CliArg returns the i-th command line parameter,
// or empty string if it is not specified.
func CliArg(i int) string {
if len(saptArgs) >= i+1 {
return saptArgs[i]
}
return ""
}
// CliArgs returns all remaining command line parameters starting with i,
// or empty string if it is not specified.
func CliArgs(i int) []string {
if len(saptArgs) >= i+1 {
return saptArgs[i:]
}
return []string{}
}
// IsFlagSet returns true, if the flag is available on the command line
// or false, if not
func IsFlagSet(flag string) bool {
if saptFlags[flag] == "false" || saptFlags[flag] == "" {
return false
}
return true
}
// GetFlagVal returns the value of a saptune commandline flag
func GetFlagVal(flag string) string {
return saptFlags[flag]
}
// ParseCliArgs parses the command line to identify special flags and the
// 'normal' arguments
// returns a map of Flags (set/not set or value) and a slice containing the
// remaining arguments
// possible Flags - force, dryrun, help, version, show-non-compliant, format,
// colorscheme, non-compliance-check
// on command line - --force, --dry-run or --dryrun, --help, --version, --color-scheme, --format
// Some Flags (like 'format') can have a value (--format json or --format csv)
func ParseCliArgs() ([]string, map[string]string) {
stArgs := []string{}
// supported flags
stFlags := map[string]string{"force": "false", "dryrun": "false", "help": "false", "version": "false", "show-non-compliant": "false", "format": "", "colorscheme": "", "non-compliance-check": "false", "notSupported": ""}
skip := false
for i, arg := range os.Args {
if skip {
// skip this command line parameter, because it's the value
// belonging to a flag
skip = false
continue
}
if strings.HasPrefix(arg, "--") || strings.HasPrefix(arg, "-") {
// argument is a flag
// skip next command line parameter, if it is the value
// belonging to a flag
skip = handleFlags(arg, i, stFlags)
continue
}
// other args
stArgs = append(stArgs, arg)
}
return stArgs, stFlags
}
// handleFlags checks for valid flags in the CLI arg list
func handleFlags(arg string, idx int, flags map[string]string) bool {
fval := idx + 1
farg := "flag_value"
if fval < len(os.Args) {
farg = os.Args[fval]
}
skip := handleValueFlags(arg, farg, flags)
if !skip {
handleSimpleFlags(arg, flags)
}
return skip
}
// handleValueFlags checks for valid flags with value in the CLI arg list
func handleValueFlags(arg, farg string, flags map[string]string) bool {
skip := false
if strings.Contains(arg, "--format") {
// --format json
flags["format"] = farg
skip = true
}
if strings.Contains(arg, "-colorscheme") {
// --colorscheme zebra
flags["colorscheme"] = farg
skip = true
}
return skip
}
// handleSimpleFlags checks for valid flags in the CLI arg list
func handleSimpleFlags(arg string, flags map[string]string) {
// simple flags
switch arg {
case "--force", "-force":
flags["force"] = "true"
case "--dry-run", "-dry-run", "--dryrun", "-dryrun":
flags["dryrun"] = "true"
case "--help", "-help", "-h":
flags["help"] = "true"
case "--version", "-version":
flags["version"] = "true"
case "--show-non-compliant", "-show-non-compliant":
flags["show-non-compliant"] = "true"
case "--non-compliance-check", "-non-compliance-check":
flags["non-compliance-check"] = "true"
default:
setUnsupportedFlag(arg, flags)
}
}
// setUnsupportedFlag sets or appends a value to the unsupported Flag
// collection of unsupported Flags
func setUnsupportedFlag(val string, flags map[string]string) {
if flags["notSupported"] == "" {
flags["notSupported"] = flags["notSupported"] + val
} else {
flags["notSupported"] = flags["notSupported"] + " " + val
}
}
// ChkCliSyntax checks, if command line parameter are in the right order
// only checking the right position of the 'options' aka 'flags'
// saptune globOpt realm realmOpt cmd cmdOpt param
func ChkCliSyntax() bool {
ret := true
cmdLinePos := map[string]int{"globOpt": 1, "realm": 1, "realmOpt": 2, "cmd": 2, "cmdOpt": 3}
// check some universal syntax and the global option
// manipulating cmdLinePos values
if !chkGlobalSyntax(cmdLinePos) {
DebugLog("ChkCliSyntax - chkGlobalSyntax failed")
return false
}
// check for realm options
// manipulating cmdLinePos values
if !chkRealmOpts(cmdLinePos) {
DebugLog("ChkCliSyntax - chkRealmOpts failed")
return false
}
// check for command options
if !chkCmdOpts(cmdLinePos) {
DebugLog("ChkCliSyntax - chkCmdOpts failed")
return false
}
return ret
}
// chkGlobalSyntax checks some universal syntax and the global options
func chkGlobalSyntax(cmdLinePos map[string]int) bool {
ret := true
// check minimum of arguments without flags (saptune + realm)
if (IsFlagSet("version") || IsFlagSet("help")) && len(saptArgs) > 1 {
// too many arguments
DebugLog("chkGlobalSyntax failed - too many arguments")
ret = false
}
if !IsFlagSet("version") && !IsFlagSet("help") && len(saptArgs) < 2 {
// too few arguments
DebugLog("chkGlobalSyntax failed - too few arguments")
ret = false
}
if IsFlagSet("notSupported") {
// unknown flag in command line found
DebugLog("chkGlobalSyntax failed - unknown flag '%+v' found in command line", GetFlagVal("notSupported"))
ret = false
}
if IsFlagSet("force") && IsFlagSet("dryrun") {
// both together are not supported
// even that this case is handled correctly
DebugLog("chkGlobalSyntax failed - both 'force' and 'dryrun' set - unsupported")
ret = false
}
if IsFlagSet("colorscheme") && IsFlagSet("show-non-compliant") && len(os.Args) < cmdLinePos["cmdOpt"]+2 {
// too few options for both flags set
DebugLog("chkGlobalSyntax failed - both 'colorscheme' and 'show-non-compliant' set, but too few options")
ret = false
}
if ret {
// check global option
ret = chkGlobalOpts(cmdLinePos)
}
return ret
}
// chkGlobalOpts checks for global options
// saptune -format FORMAT [--version|--help]
// saptune --version or saptune --help
func chkGlobalOpts(cmdLinePos map[string]int) bool {
stArgs := os.Args
ret := true
globOpt := false
globPos := 1
if len(stArgs) < globPos {
// too few arguments
DebugLog("chkGlobalOpts failed - too few arguments")
return false
}
if IsFlagSet("version") && IsFlagSet("help") {
// both together are not supported
DebugLog("chkGlobalOpts failed - both 'version' and 'help' set - unsupported")
ret = false
}
if IsFlagSet("format") {
if GetFlagVal("format") != "json" {
DebugLog("chkGlobalOpts failed - wrong 'format' value '%+v'", GetFlagVal("format"))
ret = false
}
if !strings.Contains(stArgs[1], "--format") {
DebugLog("chkGlobalOpts failed - 'format' flag on wrong position in command line")
ret = false
} else {
globPos = globPos + 2
// the flag '--format' has a value (e.g. json), so we
// have '2' positions to skip in the command line
cmdLinePos["realm"] = cmdLinePos["realm"] + 2
cmdLinePos["realmOpt"] = cmdLinePos["realmOpt"] + 2
cmdLinePos["cmd"] = cmdLinePos["cmd"] + 2
cmdLinePos["cmdOpt"] = cmdLinePos["cmdOpt"] + 2
}
}
if IsFlagSet("version") {
// support '--version' and '-version'
if !strings.Contains(stArgs[globPos], "-version") {
DebugLog("chkGlobalOpts failed - 'version' flag on wrong position in command line")
ret = false
} else {
globOpt = true
}
}
if IsFlagSet("help") {
// support '--help' and '-help'
if !strings.Contains(stArgs[globPos], "-help") {
DebugLog("chkGlobalOpts failed - 'help' flag on wrong position in command line")
ret = false
} else {
globOpt = true
}
}
if globOpt {
cmdLinePos["realm"] = cmdLinePos["realm"] + 1
cmdLinePos["realmOpt"] = cmdLinePos["realmOpt"] + 1
cmdLinePos["cmd"] = cmdLinePos["cmd"] + 1
cmdLinePos["cmdOpt"] = cmdLinePos["cmdOpt"] + 1
}
return ret
}
// chkRealmOpts checks for realm options
// at the moment only 'saptune status' has an option (--non-compliance-check)
func chkRealmOpts(cmdLinePos map[string]int) bool {
stArgs := os.Args
ret := true
if IsFlagSet("non-compliance-check") {
// check for valid realm
if !(stArgs[cmdLinePos["realm"]] == "status" || stArgs[cmdLinePos["realm"]] == "service" || stArgs[cmdLinePos["realm"]] == "daemon") {
DebugLog("chkRealmOpts failed - 'non-compliance-check' flag used with wrong realm '%+v'", stArgs[cmdLinePos["realm"]])
ret = false
}
if stArgs[cmdLinePos["realm"]] == "status" {
// realm option set
// check minimum of values items in cmd line
// (saptune + realm + option)
if len(stArgs) < cmdLinePos["realmOpt"]+1 {
// too few arguments
DebugLog("chkRealmOpts failed - too few arguments for realm 'status'")
ret = false
} else if stArgs[cmdLinePos["realmOpt"]] != "--non-compliance-check" {
DebugLog("chkRealmOpts failed - 'non-compliance-check' flag on wrong position in command line")
ret = false
} else {
cmdLinePos["cmd"] = cmdLinePos["cmd"] + 1
cmdLinePos["cmdOpt"] = cmdLinePos["cmdOpt"] + 1
}
}
}
return ret
}
// chkCmdOpts checks for command options
func chkCmdOpts(cmdLinePos map[string]int) bool {
ret := true
// check minimum of arguments for command options
// saptune realm cmd
if len(saptArgs) < 3 && (IsFlagSet("force") || IsFlagSet("dryrun") || IsFlagSet("colorscheme") || IsFlagSet("show-non-compliant")) {
// too few arguments for the active flags
DebugLog("chkCmdOpts failed - too few arguments for flags 'force' or 'dryrun' or 'colorscheme' or 'show-non-compliant'")
return false
}
if len(os.Args) < cmdLinePos["cmdOpt"]+1 || (!IsFlagSet("force") && !IsFlagSet("dryrun") && !IsFlagSet("colorscheme") && !IsFlagSet("show-non-compliant") && !IsFlagSet("non-compliance-check")) {
// no command options set or too few options
// and/or non of the flags set, which need further checks
// so let the 'old' default checks (in main and/or actions) set
// the appropriate result
DebugLog("chkCmdOpts nok - no command options set or too few options and/or non of the flags set, which need further checks, so let the 'old' default checks set the appropriate result")
return true
}
// saptune solution change [--force] SOLUTIONNAME
// saptune staging release [--force|--dry-run] [NOTE...|SOLUTION...|all]
if !chkForceFlag(cmdLinePos) {
DebugLog("chkCmdOpts - chkForceFlag failed")
ret = false
}
// saptune staging release [--force|--dry-run] [NOTE...|SOLUTION...|all]
if !chkDryrunFlag(cmdLinePos) {
DebugLog("chkCmdOpts - chkDryrunFlag failed")
ret = false
}
// saptune note verify [--colorscheme <color scheme>] [--show-non-compliant] [NOTEID]
// saptune solution verify [--colorscheme <color scheme>] [--show-non-compliant] [SOLUTIONNAME]
if !chkVerifySyntax(cmdLinePos) {
DebugLog("chkCmdOpts - chkVerifySyntax failed")
ret = false
}
// saptune (service) status [--non-compliance-check]
if !chkServiceStatusSyntax(cmdLinePos) {
DebugLog("chkCmdOpts - chkServiceStatusSyntax failed")
ret = false
}
return ret
}
// chkForceFlag checks the syntax of 'saptune solution change'
// and 'saptune staging release' command line regarding the use
// of the 'force' flag
// saptune solution change [--force] SOLUTIONNAME
// saptune staging release [--force|--dry-run] [NOTE...|SOLUTION...|all]
func chkForceFlag(cmdLinePos map[string]int) bool {
stArgs := os.Args
ret := true
if IsFlagSet("force") {
if !(stArgs[cmdLinePos["realm"]] == "solution" && stArgs[cmdLinePos["cmd"]] == "change") && !(stArgs[cmdLinePos["realm"]] == "staging" && stArgs[cmdLinePos["cmd"]] == "release") {
DebugLog("chkForceFlag failed - 'force' flag used with wrong realm '%+v' or command '%+v'", stArgs[cmdLinePos["realm"]], stArgs[cmdLinePos["cmd"]])
ret = false
}
if stArgs[cmdLinePos["cmdOpt"]] != "--force" {
DebugLog("chkForceFlag failed - 'force' flag on wrong position in command line")
ret = false
}
}
return ret
}
// chkDryrunFlag checks the syntax of 'saptune staging release'
// command line regarding command line the use of the 'dry-run' flag
// saptune staging release [--force|--dry-run] [NOTE...|SOLUTION...|all]
func chkDryrunFlag(cmdLinePos map[string]int) bool {
stArgs := os.Args
ret := true
if IsFlagSet("dryrun") {
if !(stArgs[cmdLinePos["realm"]] == "staging" && stArgs[cmdLinePos["cmd"]] == "release") {
DebugLog("chkDryrunFlag failed - 'dryrun' flag used with wrong realm '%+v' or wrong command '%+v'", stArgs[cmdLinePos["realm"]], stArgs[cmdLinePos["cmd"]])
ret = false
}
if stArgs[cmdLinePos["cmdOpt"]] != "--dry-run" {
DebugLog("chkDryrunFlag failed - 'dryrun' flag on wrong position in command line")
ret = false
}
}
return ret
}
// chkVerifySyntax checks the syntax of 'saptune note|solution verify' command
// line regarding command line options
// saptune note verify [--colorscheme <color scheme>] [--show-non-compliant] [NOTEID]
// saptune solution verify [--colorscheme <color scheme>] [--show-non-compliant] [SOLUTIONNAME]
func chkVerifySyntax(cmdLinePos map[string]int) bool {
stArgs := os.Args
ret := true
if IsFlagSet("colorscheme") || IsFlagSet("show-non-compliant") {
if !((stArgs[cmdLinePos["realm"]] == "note" || stArgs[cmdLinePos["realm"]] == "solution") && stArgs[cmdLinePos["cmd"]] == "verify") {
DebugLog("chkVerifySyntax failed - 'colorscheme' or 'show-non-compliant' flag used with wrong realm '%+v' or wrong command '%+v'", stArgs[cmdLinePos["realm"]], stArgs[cmdLinePos["cmd"]])
ret = false
}
}
DebugLog("chkVerifySyntax - colorscheme is '%+v', show-non-compliant is '%+v'", GetFlagVal("colorscheme"), IsFlagSet("show-non-compliant"))
if IsFlagSet("colorscheme") && IsFlagSet("show-non-compliant") {
// both flags set, check order
poscor := 2
if GetFlagVal("colorscheme") == "flag_value" {
poscor = 1
}
if stArgs[cmdLinePos["cmdOpt"]] != "--colorscheme" && stArgs[cmdLinePos["cmdOpt"]+poscor] != "--show-non-compliant" {
DebugLog("chkVerifySyntax failed - wrong order of flags 'colorscheme' and 'show-non-compliant'")
ret = false
}
} else if IsFlagSet("colorscheme") {
if GetFlagVal("colorscheme") == "--show-non-compliant" {
DebugLog("chkVerifySyntax failed - missing colorscheme leads to wrong position of 'show-non-compliant' flag in command line")
ret = false
}
if stArgs[cmdLinePos["cmdOpt"]] != "--colorscheme" {
// flag at wrong place in arg list
DebugLog("chkVerifySyntax failed - 'colorscheme' flag on wrong position in command line")
ret = false
}
} else if IsFlagSet("show-non-compliant") && stArgs[cmdLinePos["cmdOpt"]] != "--show-non-compliant" {
// flag at wrong place in arg list
DebugLog("chkVerifySyntax failed - 'show-non-compliant' flag on wrong position in command line")
ret = false
}
return ret
}
// chkServiceStatusSyntax checks the syntax of 'saptune service status' or
// 'saptune daemon status' command line regarding command line options
// saptune service status [--non-compliance-check]
// saptune status [--non-compliance-check] is checked earlier (as 'realm')
func chkServiceStatusSyntax(cmdLinePos map[string]int) bool {
stArgs := os.Args
ret := true
if IsFlagSet("non-compliance-check") {
// saptune service status --non-compliance-check
// saptune daemon status --non-compliance-check
if !(stArgs[cmdLinePos["realm"]] == "service" && stArgs[cmdLinePos["cmd"]] == "status") && !(stArgs[cmdLinePos["realm"]] == "daemon" && stArgs[cmdLinePos["cmd"]] == "status") {
DebugLog("chkServiceStatusSyntax failed - 'non-compliance-check' flag used with wrong realm '%+v' or wrong command '%+v'", stArgs[cmdLinePos["realm"]], stArgs[cmdLinePos["cmd"]])
ret = false
}
if stArgs[cmdLinePos["cmdOpt"]] != "--non-compliance-check" {
DebugLog("chkServiceStatusSyntax failed - 'non-compliance-check' flag on wrong position in command line")
ret = false
}
}
return ret
}