Skip to content

Commit 8bfa372

Browse files
committed
feat: upgrade goNixArgParser
1 parent 52e85ab commit 8bfa372

File tree

15 files changed

+467
-484
lines changed

15 files changed

+467
-484
lines changed

src/goNixArgParser/arg.go

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/goNixArgParser/command.go

Lines changed: 60 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,27 @@ package goNixArgParser
22

33
import (
44
"bytes"
5-
"os"
5+
"io"
66
"path"
77
)
88

99
func NewCommand(
1010
names []string,
1111
summary, mergeFlagPrefix string,
12-
restsSigns, groupSeps, undefFlagPrefixes []string,
12+
restsSigns, groupSeps, assignSigns, undefFlagPrefixes []string,
1313
) *Command {
1414
return &Command{
1515
names: names,
1616
summary: summary,
17-
options: NewOptionSet(mergeFlagPrefix, restsSigns, groupSeps, undefFlagPrefixes),
17+
options: NewOptionSet(mergeFlagPrefix, restsSigns, groupSeps, assignSigns, undefFlagPrefixes),
1818
subCommands: []*Command{},
1919
}
2020
}
2121

2222
func NewSimpleCommand(name, summary string, aliasNames ...string) *Command {
23-
names := make([]string, 0, 1+len(aliasNames))
24-
names = append(names, name)
25-
names = append(names, aliasNames...)
23+
names := make([]string, 1+len(aliasNames))
24+
names[0] = name
25+
copy(names[1:], aliasNames)
2626

2727
return &Command{
2828
names: names,
@@ -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, undefFlagPrefixes []string,
38+
restsSigns, groupSeps, assignSigns, undefFlagPrefixes []string,
3939
) *Command {
40-
subCommand := NewCommand(names, summary, mergeFlagPrefix, restsSigns, groupSeps, undefFlagPrefixes)
40+
subCommand := NewCommand(names, summary, mergeFlagPrefix, restsSigns, groupSeps, assignSigns, undefFlagPrefixes)
4141
c.subCommands = append(c.subCommands, subCommand)
4242
return subCommand
4343
}
@@ -58,10 +58,6 @@ func (c *Command) hasName(name string) bool {
5858
}
5959

6060
func (c *Command) GetSubCommand(name string) *Command {
61-
if c.subCommands == nil {
62-
return nil
63-
}
64-
6561
for _, cmd := range c.subCommands {
6662
if cmd.hasName(name) {
6763
return cmd
@@ -79,7 +75,9 @@ func (c *Command) Name() (name string) {
7975
}
8076

8177
func (c *Command) Names() []string {
82-
return c.names
78+
names := make([]string, len(c.names))
79+
copy(names, c.names)
80+
return names
8381
}
8482

8583
func (c *Command) Summary() string {
@@ -94,116 +92,107 @@ func (c *Command) SubCommands() []*Command {
9492
return c.subCommands
9593
}
9694

97-
func (c *Command) getNormalizedArgs(initArgs []string) (*Command, []*Arg) {
98-
cmd := c
95+
func (c *Command) getLeafCmd(args []string) (explicitCmd *Command, inferredCmd *Command, cmdPaths []string) {
96+
inferredCmd = c
9997

100-
if len(initArgs) == 0 {
101-
return cmd, []*Arg{}
98+
if len(args) == 0 {
99+
return explicitCmd, inferredCmd, []string{}
102100
}
103101

104-
args := make([]*Arg, 0, len(initArgs))
105-
106-
for i, arg := range initArgs {
107-
if i == 0 && cmd.hasName(arg) {
108-
args = append(args, NewArg(cmd.Name(), CommandArg))
109-
} else if subCmd := cmd.GetSubCommand(arg); subCmd != nil {
110-
args = append(args, NewArg(subCmd.Name(), CommandArg))
111-
cmd = subCmd
102+
for i, arg := range args {
103+
if i == 0 && inferredCmd.hasName(arg) {
104+
explicitCmd = c
105+
cmdPaths = append(cmdPaths, inferredCmd.Name())
106+
} else if subCmd := inferredCmd.GetSubCommand(arg); subCmd != nil {
107+
explicitCmd = subCmd
108+
inferredCmd = subCmd
109+
cmdPaths = append(cmdPaths, inferredCmd.Name())
112110
} else {
113111
break
114112
}
115113
}
116114

117-
return cmd, args
115+
return
118116
}
119117

120-
func (c *Command) splitCommandsArgs(initArgs, initConfigs []string) (
121-
argsLeafCmd *Command,
122-
commands, optionSetInitArgs, optionSetInitConfigs []string,
118+
func (c *Command) extractCmdOptionArgs(specifiedArgs, configArgs []string) (
119+
specifiedCmd *Command,
120+
cmdPaths, specifiedOptionArgs, configOptionArgs []string,
123121
) {
124-
argsLeafCmd, argCmds := c.getNormalizedArgs(initArgs)
125-
configsLeafCmd, configCmds := c.getNormalizedArgs(initConfigs)
122+
_, specifiedCmd, specifiedCmdPaths := c.getLeafCmd(specifiedArgs)
123+
explicitConfigCmd, configCmd, configCmdPaths := c.getLeafCmd(configArgs)
126124

127-
commands = []string{}
128-
for _, arg := range argCmds {
129-
commands = append(commands, arg.Text)
130-
}
125+
cmdPaths = specifiedCmdPaths
131126

132-
optionSetInitArgs = initArgs[len(argCmds):]
127+
specifiedOptionArgs = specifiedArgs[len(specifiedCmdPaths):]
133128

134-
if argsLeafCmd == configsLeafCmd {
135-
optionSetInitConfigs = initConfigs[len(configCmds):]
129+
if specifiedCmd == configCmd {
130+
configOptionArgs = configArgs[len(configCmdPaths):]
131+
} else if explicitConfigCmd == nil {
132+
configOptionArgs = configArgs
136133
} else {
137-
optionSetInitConfigs = []string{}
134+
configOptionArgs = []string{}
138135
}
139136

140137
return
141138
}
142139

143-
func (c *Command) Parse(initArgs, initConfigs []string) *ParseResult {
144-
leafCmd, commands, optionSetInitArgs, optionSetInitConfigs := c.splitCommandsArgs(initArgs, initConfigs)
145-
result := leafCmd.options.Parse(optionSetInitArgs, optionSetInitConfigs)
146-
result.commands = commands
140+
func (c *Command) Parse(specifiedArgs, configArgs []string) *ParseResult {
141+
cmd, cmdPaths, specifiedOptionArgs, configOptionArgs := c.extractCmdOptionArgs(specifiedArgs, configArgs)
142+
result := cmd.options.Parse(specifiedOptionArgs, configOptionArgs)
143+
result.commands = cmdPaths
147144

148145
return result
149146
}
150147

151-
func (c *Command) ParseGroups(initArgs, initConfigs []string) (results []*ParseResult) {
152-
leafCmd, commands, optionSetInitArgs, optionSetInitConfigs := c.splitCommandsArgs(initArgs, initConfigs)
148+
func (c *Command) ParseGroups(specifiedArgs, configArgs []string) (results []*ParseResult) {
149+
cmd, cmdPaths, specifiedOptionArgs, configOptionArgs := c.extractCmdOptionArgs(specifiedArgs, configArgs)
153150

154-
if len(optionSetInitArgs) == 0 && len(optionSetInitConfigs) == 0 {
155-
result := leafCmd.options.Parse(optionSetInitArgs, optionSetInitConfigs)
151+
if len(specifiedOptionArgs) == 0 && len(configOptionArgs) == 0 {
152+
result := cmd.options.Parse(specifiedOptionArgs, configOptionArgs)
156153
results = append(results, result)
157154
} else {
158-
results = leafCmd.options.ParseGroups(optionSetInitArgs, optionSetInitConfigs)
155+
results = cmd.options.ParseGroups(specifiedOptionArgs, configOptionArgs)
159156
}
160157

161158
for _, result := range results {
162-
result.commands = commands
159+
result.commands = cmdPaths
163160
}
164161

165162
return results
166163
}
167164

168-
func (c *Command) GetHelp() []byte {
165+
func (c *Command) OutputHelp(w io.Writer) {
166+
newline := []byte{'\n'}
169167
buffer := &bytes.Buffer{}
170168

171169
name := c.Name()
172170
if len(name) > 0 {
173-
buffer.WriteString(path.Base(name))
174-
buffer.WriteString(": ")
171+
io.WriteString(w, path.Base(name))
172+
io.WriteString(w, ": ")
175173
}
176174
if len(c.summary) > 0 {
177-
buffer.WriteString(c.summary)
175+
io.WriteString(w, c.summary)
178176
}
179177
if buffer.Len() > 0 {
180178
buffer.WriteByte('\n')
181179
} else {
182-
buffer.WriteString("Usage:\n")
180+
io.WriteString(w, "Usage:\n")
183181
}
184182

185-
optionsHelp := c.options.GetHelp()
186-
if len(optionsHelp) > 0 {
187-
buffer.WriteString("\nOptions:\n\n")
188-
buffer.Write(optionsHelp)
189-
}
183+
io.WriteString(w, "\nOptions:\n\n")
184+
c.options.OutputHelp(w)
190185

191186
if len(c.subCommands) > 0 {
192-
buffer.WriteString("\nSub commands:\n\n")
187+
io.WriteString(w, "\nSub commands:\n\n")
193188
for _, cmd := range c.subCommands {
194-
buffer.WriteString(cmd.Name())
195-
buffer.WriteByte('\n')
189+
io.WriteString(w, cmd.Name())
190+
w.Write(newline)
196191
if len(cmd.summary) > 0 {
197-
buffer.WriteString(cmd.summary)
198-
buffer.WriteByte('\n')
192+
io.WriteString(w, cmd.summary)
193+
w.Write(newline)
199194
}
200-
buffer.WriteByte('\n')
195+
w.Write(newline)
201196
}
202197
}
203-
204-
return buffer.Bytes()
205-
}
206-
207-
func (c *Command) PrintHelp() {
208-
os.Stdout.Write(c.GetHelp())
209198
}

src/goNixArgParser/commandParse_test.go

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package goNixArgParser
22

33
import (
4-
"fmt"
54
"testing"
65
)
76

@@ -25,14 +24,16 @@ func getGitCommand() *Command {
2524
return cmdGit
2625
}
2726

28-
func TestNormalizeCmdArgs(t *testing.T) {
27+
/*
28+
func TestGetLeafCmd(t *testing.T) {
2929
cmd := getGitCommand()
3030
args := []string{"git", "rmt", "set-url", "--push", "origin", "https://github.com/mjpclab/goNixArgParser.git"}
31-
_, normalizedArgs := cmd.getNormalizedArgs(args)
31+
_, normalizedArgs := cmd.getLeafCmd(args)
3232
for i, arg := range normalizedArgs {
3333
fmt.Printf("%d %+v\n", i, arg)
3434
}
3535
}
36+
*/
3637

3738
func TestParseCommand1(t *testing.T) {
3839
cmd := getGitCommand()
@@ -49,12 +50,10 @@ func TestParseCommand1(t *testing.T) {
4950
t.Error("push")
5051
}
5152

52-
if result.argRests[0] != "origin" ||
53-
result.argRests[1] != "https://github.com/mjpclab/goNixArgParser.git" {
54-
t.Error("rests", result.argRests)
53+
if result.specifiedRests[0] != "origin" ||
54+
result.specifiedRests[1] != "https://github.com/mjpclab/goNixArgParser.git" {
55+
t.Error("rests", result.specifiedRests)
5556
}
56-
57-
cmd.PrintHelp()
5857
}
5958

6059
func TestParseCommand2(t *testing.T) {
@@ -67,11 +66,11 @@ func TestParseCommand2(t *testing.T) {
6766
t.Error("commands", result.commands)
6867
}
6968

70-
if result.argRests[0] != "xxx" ||
71-
result.argRests[1] != "set-url" ||
72-
result.argRests[2] != "origin" ||
73-
result.argRests[3] != "https://github.com/mjpclab/goNixArgParser.git" {
74-
t.Error("rests", result.argRests)
69+
if result.specifiedRests[0] != "xxx" ||
70+
result.specifiedRests[1] != "set-url" ||
71+
result.specifiedRests[2] != "origin" ||
72+
result.specifiedRests[3] != "https://github.com/mjpclab/goNixArgParser.git" {
73+
t.Error("rests", result.specifiedRests)
7574
}
7675
}
7776

@@ -83,17 +82,15 @@ func TestParseCommand3(t *testing.T) {
8382

8483
dummy, _ := result.GetString("dummy")
8584
if dummy != "dummyconfigvalue" {
86-
fmt.Println("dummy:", dummy)
87-
t.Error("dummy config value error")
85+
t.Error("dummy config value error", dummy)
8886
}
8987

9088
configArgs = configArgs[1:]
9189
result = cmd.Parse(args, configArgs)
9290

9391
dummy, _ = result.GetString("dummy")
9492
if dummy != "dummyconfigvalue" {
95-
fmt.Println("dummy:", dummy)
96-
t.Error("dummy config value error")
93+
t.Error("dummy config value error", dummy)
9794
}
9895
}
9996

@@ -160,3 +157,30 @@ func TestParseCommand6(t *testing.T) {
160157
t.Error(results[1].GetStrings("dummy"))
161158
}
162159
}
160+
161+
func TestParseCommand7(t *testing.T) {
162+
cmd := getGitCommand()
163+
args := []string{"git", "remote", "set-url", "github", "https://github.com/mjpclab/goNixArgParser.git"}
164+
configArgs := []string{"--dummy", "dummy0"}
165+
166+
result := cmd.Parse(args, configArgs)
167+
168+
cmdPaths := result.GetCommands()
169+
if len(cmdPaths) != 3 {
170+
t.Error(len(cmdPaths))
171+
}
172+
if cmdPaths[0] != "git" {
173+
t.Error(cmdPaths[0])
174+
}
175+
if cmdPaths[1] != "remote" {
176+
t.Error(cmdPaths[1])
177+
}
178+
if cmdPaths[2] != "set-url" {
179+
t.Error(cmdPaths[2])
180+
}
181+
182+
dummy, _ := result.GetString("dummy")
183+
if dummy != "dummy0" {
184+
t.Error(dummy)
185+
}
186+
}

src/goNixArgParser/flag.go

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
package goNixArgParser
22

3-
func NewFlag(name string, prefixMatchLen int, canMerge, canFollowAssign, canConcatAssign bool, assignSigns []string) *Flag {
3+
func NewFlag(name string, prefixMatchLen int, canMerge, canFollowAssign, canConcatAssign bool) *Flag {
44
return &Flag{
55
Name: name,
66
prefixMatchLen: prefixMatchLen,
77
canMerge: canMerge,
88
canFollowAssign: canFollowAssign,
99
canConcatAssign: canConcatAssign,
10-
assignSigns: assignSigns,
1110
}
1211
}
1312

@@ -17,12 +16,7 @@ func NewSimpleFlag(name string) *Flag {
1716
canMerge := isSingleChar
1817
canConcatAssign := isSingleChar
1918

20-
assignSigns := make([]string, 0, 1)
21-
if !isSingleChar {
22-
assignSigns = append(assignSigns, "=")
23-
}
24-
25-
return NewFlag(name, 0, canMerge, true, canConcatAssign, assignSigns)
19+
return NewFlag(name, 0, canMerge, true, canConcatAssign)
2620
}
2721

2822
func NewSimpleFlags(names []string) []*Flag {

0 commit comments

Comments
 (0)