Skip to content

Commit 7d4b65e

Browse files
committed
feat: report unknown cli flag
Upgrade goNixArgParser to have abillity to identify unkown cli args.
1 parent 79c2dd6 commit 7d4b65e

File tree

9 files changed

+132
-35
lines changed

9 files changed

+132
-35
lines changed

src/goNixArgParser/command.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import (
99
func NewCommand(
1010
names []string,
1111
summary, mergeFlagPrefix string,
12-
restsSigns, groupSeps []string,
12+
restsSigns, groupSeps, undefFlagPrefixes []string,
1313
) *Command {
1414
return &Command{
1515
names: names,
1616
summary: summary,
17-
options: NewOptionSet(mergeFlagPrefix, restsSigns, groupSeps),
17+
options: NewOptionSet(mergeFlagPrefix, restsSigns, groupSeps, undefFlagPrefixes),
1818
subCommands: []*Command{},
1919
}
2020
}
@@ -35,9 +35,9 @@ func NewSimpleCommand(name, summary string, aliasNames ...string) *Command {
3535
func (c *Command) NewSubCommand(
3636
names []string,
3737
summary, mergeFlagPrefix string,
38-
restsSigns, groupSeps []string,
38+
restsSigns, groupSeps, undefFlagPrefixes []string,
3939
) *Command {
40-
subCommand := NewCommand(names, summary, mergeFlagPrefix, restsSigns, groupSeps)
40+
subCommand := NewCommand(names, summary, mergeFlagPrefix, restsSigns, groupSeps, undefFlagPrefixes)
4141
c.subCommands = append(c.subCommands, subCommand)
4242
return subCommand
4343
}

src/goNixArgParser/optionSet.go

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"errors"
66
"os"
7+
"strings"
78
)
89

910
var defaultOptionDelimiters = []rune{',', ' ', '\t', '\v', '\r', '\n'}
@@ -20,11 +21,13 @@ func NewOptionSet(
2021
mergeFlagPrefix string,
2122
restsSigns []string,
2223
groupSeps []string,
24+
undefFlagPrefixes []string,
2325
) *OptionSet {
2426
s := &OptionSet{
25-
mergeFlagPrefix: mergeFlagPrefix,
26-
restsSigns: restsSigns,
27-
groupSeps: groupSeps,
27+
mergeFlagPrefix: mergeFlagPrefix,
28+
restsSigns: restsSigns,
29+
groupSeps: groupSeps,
30+
undefFlagPrefixes: undefFlagPrefixes,
2831

2932
options: []*Option{},
3033

@@ -49,8 +52,12 @@ func (s *OptionSet) GroupSeps() []string {
4952
return s.groupSeps
5053
}
5154

55+
func (s *OptionSet) UndefFlagPrefixes() []string {
56+
return s.undefFlagPrefixes
57+
}
58+
5259
func NewSimpleOptionSet() *OptionSet {
53-
return NewOptionSet("-", []string{"--"}, []string{",,"})
60+
return NewOptionSet("-", []string{"--"}, []string{",,"}, []string{"-"})
5461
}
5562

5663
func (s *OptionSet) isRestSign(input string) bool {
@@ -63,7 +70,7 @@ func (s *OptionSet) isRestSign(input string) bool {
6370
return false
6471
}
6572

66-
func (s *OptionSet) isGroupSeps(input string) bool {
73+
func (s *OptionSet) isGroupSep(input string) bool {
6774
for _, sep := range s.groupSeps {
6875
if input == sep {
6976
return true
@@ -73,6 +80,16 @@ func (s *OptionSet) isGroupSeps(input string) bool {
7380
return false
7481
}
7582

83+
func (s *OptionSet) isUdefFlag(input string) bool {
84+
for _, prefix := range s.undefFlagPrefixes {
85+
if strings.HasPrefix(input, prefix) {
86+
return true
87+
}
88+
}
89+
90+
return false
91+
}
92+
7693
func (s *OptionSet) Append(opt *Option) error {
7794
// verify
7895
if len(opt.Key) == 0 {

src/goNixArgParser/optionSetParse.go

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ func (s *OptionSet) splitMergedArg(arg *Arg) (args []*Arg, success bool) {
99
optionMap := s.flagOptionMap
1010
argText := arg.Text
1111

12-
if arg.Type != UnknownArg ||
12+
if arg.Type != UndetermArg ||
1313
len(argText) <= len(s.mergeFlagPrefix) ||
1414
!strings.HasPrefix(argText, s.mergeFlagPrefix) {
1515
return
@@ -49,7 +49,7 @@ func (s *OptionSet) splitMergedArg(arg *Arg) (args []*Arg, success bool) {
4949
}
5050

5151
// re-generate standalone flag with values
52-
splittedArgs[len(splittedArgs)-1] = NewArg(prevFlag.Name+mergedArgs[i:], UnknownArg)
52+
splittedArgs[len(splittedArgs)-1] = NewArg(prevFlag.Name+mergedArgs[i:], UndetermArg)
5353
break
5454
}
5555

@@ -72,7 +72,7 @@ func (s *OptionSet) splitMergedArgs(initArgs []*Arg) []*Arg {
7272
func (s *OptionSet) splitAssignSignArg(arg *Arg) (args []*Arg) {
7373
args = make([]*Arg, 0, 2)
7474

75-
if arg.Type != UnknownArg {
75+
if arg.Type != UndetermArg {
7676
args = append(args, arg)
7777
return
7878
}
@@ -115,7 +115,7 @@ func (s *OptionSet) splitAssignSignArgs(initArgs []*Arg) []*Arg {
115115
func (s *OptionSet) splitConcatAssignArg(arg *Arg) (args []*Arg) {
116116
args = make([]*Arg, 0, 2)
117117

118-
if arg.Type != UnknownArg {
118+
if arg.Type != UndetermArg {
119119
args = append(args, arg)
120120
return
121121
}
@@ -149,20 +149,37 @@ func (s *OptionSet) splitConcatAssignArgs(initArgs []*Arg) []*Arg {
149149
return args
150150
}
151151

152+
func (s *OptionSet) markUndefArgsValues(args []*Arg) {
153+
foundUndefFlag := false
154+
for _, arg := range args {
155+
if arg.Type != UndetermArg {
156+
foundUndefFlag = false
157+
continue
158+
}
159+
if s.isUdefFlag(arg.Text) {
160+
arg.Type = UndefFlagArg
161+
foundUndefFlag = true
162+
} else if foundUndefFlag {
163+
arg.Type = UndefFlagValueArg
164+
}
165+
}
166+
}
167+
152168
func isValueArg(flag *Flag, arg *Arg) bool {
153169
switch arg.Type {
154170
case ValueArg:
155171
return true
156-
case UnknownArg:
172+
case UndetermArg:
157173
return flag.canFollowAssign
158174
default:
159175
return false
160176
}
161177
}
162178

163-
func (s *OptionSet) parseArgsInGroup(argObjs []*Arg) (args map[string][]string, rests []string) {
179+
func (s *OptionSet) parseArgsInGroup(argObjs []*Arg) (args map[string][]string, rests, undefs []string) {
164180
args = map[string][]string{}
165181
rests = []string{}
182+
undefs = []string{}
166183

167184
flagOptionMap := s.flagOptionMap
168185
flagMap := s.flagMap
@@ -177,22 +194,36 @@ func (s *OptionSet) parseArgsInGroup(argObjs []*Arg) (args map[string][]string,
177194
argObjs = s.splitConcatAssignArgs(argObjs)
178195
}
179196

197+
s.markUndefArgsValues(argObjs)
198+
180199
// walk
181200
for i, argCount, peeked := 0, len(argObjs), 0; i < argCount; i, peeked = i+1+peeked, 0 {
182201
arg := argObjs[i]
183202

203+
// rests
184204
if arg.Type == RestSignArg {
185205
continue
186206
}
187207

188-
if arg.Type == UnknownArg {
208+
if arg.Type == UndetermArg {
189209
arg.Type = RestArg
190210
}
191211
if arg.Type == RestArg {
192212
rests = append(rests, arg.Text)
193213
continue
194214
}
195215

216+
// undefs
217+
if arg.Type == UndefFlagValueArg {
218+
continue
219+
}
220+
221+
if arg.Type == UndefFlagArg {
222+
undefs = append(undefs, arg.Text)
223+
continue
224+
}
225+
226+
// normal
196227
opt := flagOptionMap[arg.Text]
197228
flag := flagMap[arg.Text]
198229

@@ -253,15 +284,15 @@ func (s *OptionSet) parseArgsInGroup(argObjs []*Arg) (args map[string][]string,
253284
}
254285
}
255286

256-
return args, rests
287+
return args, rests, undefs
257288
}
258289

259290
func (s *OptionSet) parseInGroup(argObjs, configObjs []*Arg) *ParseResult {
260291
keyOptionMap := s.keyOptionMap
261292

262-
args, argRests := s.parseArgsInGroup(argObjs)
293+
args, argRests, argUndefs := s.parseArgsInGroup(argObjs)
263294
envs := s.keyEnvMap
264-
configs, configRests := s.parseArgsInGroup(configObjs)
295+
configs, configRests, configUndefs := s.parseArgsInGroup(configObjs)
265296
defaults := s.keyDefaultMap
266297

267298
return &ParseResult{
@@ -274,6 +305,9 @@ func (s *OptionSet) parseInGroup(argObjs, configObjs []*Arg) *ParseResult {
274305

275306
argRests: argRests,
276307
configRests: configRests,
308+
309+
argUndefs: argUndefs,
310+
configUndefs: configUndefs,
277311
}
278312
}
279313

@@ -283,7 +317,7 @@ func (s *OptionSet) getNormalizedArgs(initArgs []string) []*Arg {
283317
foundRestSign := false
284318
for _, arg := range initArgs {
285319
switch {
286-
case s.isGroupSeps(arg):
320+
case s.isGroupSep(arg):
287321
foundRestSign = false
288322
args = append(args, NewArg(arg, GroupSepArg))
289323
case foundRestSign:
@@ -294,7 +328,7 @@ func (s *OptionSet) getNormalizedArgs(initArgs []string) []*Arg {
294328
case s.flagMap[arg] != nil:
295329
args = append(args, NewArg(arg, FlagArg))
296330
default:
297-
args = append(args, NewArg(arg, UnknownArg))
331+
args = append(args, NewArg(arg, UndetermArg))
298332
}
299333
}
300334

src/goNixArgParser/optionSetParse1_test.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
func TestParse1(t *testing.T) {
99
var err error
1010

11-
s := NewOptionSet("-", []string{"--"}, []string{",,"})
11+
s := NewOptionSet("-", []string{"--"}, []string{",,"}, []string{"-"})
1212
err = s.Append(&Option{
1313
Key: "tag",
1414
Summary: "tag summary",
@@ -197,10 +197,14 @@ func TestParse1(t *testing.T) {
197197
t.Error("withConcat:", withConcat)
198198
}
199199

200-
fmt.Println("rests:", r.GetRests())
200+
if undefs := r.GetUndefs(); len(undefs) != 3 {
201+
t.Error("undefs:", undefs)
202+
}
201203

202204
fmt.Print("fromenv: ")
203205
fmt.Println(r.GetStrings("fromenv"))
204206

205-
fmt.Print(string(s.GetHelp()))
207+
fmt.Println("rests:", r.GetRests())
208+
209+
fmt.Println("undefs:", r.GetUndefs())
206210
}

src/goNixArgParser/optionSetParse2_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
func TestParse2(t *testing.T) {
99
var err error
1010

11-
s := NewOptionSet("", nil, nil)
11+
s := NewOptionSet("", nil, nil,nil)
1212

1313
err = s.Append(&Option{
1414
Key: "deft",

src/goNixArgParser/optionSetParse3_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
func TestParse3(t *testing.T) {
88
var err error
99

10-
s := NewOptionSet("-", nil, []string{",,"})
10+
s := NewOptionSet("-", nil, []string{",,"}, []string{"-"})
1111

1212
err = s.Append(&Option{
1313
Key: "bool",

src/goNixArgParser/parseResult.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,3 +248,28 @@ func (r *ParseResult) GetRests() (rests []string) {
248248
func (r *ParseResult) GetCommands() []string {
249249
return copys(r.commands)
250250
}
251+
252+
///////////////////////////////
253+
// undefs
254+
//////////////////////////////
255+
func (r *ParseResult) HasUndef() bool {
256+
return len(r.argUndefs) > 0 || len(r.configUndefs) > 0
257+
}
258+
259+
func (r *ParseResult) GetUndefs() []string {
260+
flags := make([]string, 0, len(r.argUndefs)+len(r.configUndefs))
261+
262+
for _, flag := range r.argUndefs {
263+
if !contains(flags, flag) {
264+
flags = append(flags, flag)
265+
}
266+
}
267+
268+
for _, flag := range r.configUndefs {
269+
if !contains(flags, flag) {
270+
flags = append(flags, flag)
271+
}
272+
}
273+
274+
return flags
275+
}

src/goNixArgParser/type.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ type Command struct {
88
}
99

1010
type OptionSet struct {
11-
mergeFlagPrefix string
12-
restsSigns []string
13-
groupSeps []string
11+
mergeFlagPrefix string
12+
restsSigns []string
13+
groupSeps []string
14+
undefFlagPrefixes []string
1415

1516
options []*Option
1617

@@ -50,10 +51,12 @@ type Flag struct {
5051
type ArgType int
5152

5253
const (
53-
UnknownArg ArgType = iota
54+
UndetermArg ArgType = iota
5455
CommandArg
5556
FlagArg
5657
ValueArg
58+
UndefFlagArg
59+
UndefFlagValueArg
5760
RestSignArg
5861
RestArg
5962
GroupSepArg
@@ -75,4 +78,7 @@ type ParseResult struct {
7578

7679
argRests []string
7780
configRests []string
81+
82+
argUndefs []string
83+
configUndefs []string
7884
}

0 commit comments

Comments
 (0)