@@ -76,6 +76,9 @@ func RunnerOf(cmds []Command, cfg Config) *Runner {
76
76
}
77
77
78
78
func (r * Runner ) init () error {
79
+ if len (r .cmds ) == 0 {
80
+ return errors .New ("no cmds provided" )
81
+ }
79
82
if r .cfg .AppName == "" {
80
83
r .cfg .AppName = os .Args [0 ]
81
84
}
@@ -105,7 +108,6 @@ func (r *Runner) init() error {
105
108
cmds := r .cmds
106
109
r .rootCmd = Command {
107
110
Name : "root" ,
108
- Do : func (context.Context , []string ) error { return nil },
109
111
subcommands : cmds ,
110
112
}
111
113
if err := validateCommand (r .rootCmd ); err != nil {
@@ -136,6 +138,7 @@ func (r *Runner) init() error {
136
138
})
137
139
138
140
r .rootCmd .subcommands = cmds
141
+ r .rootCmd .Do = rootDo (r .cfg , cmds )
139
142
140
143
return nil
141
144
}
@@ -145,7 +148,10 @@ func validateCommand(cmd Command) error {
145
148
146
149
switch {
147
150
case cmd .Do == nil && len (cmds ) == 0 :
148
- return fmt .Errorf ("command %q function cannot be nil" , cmd .Name )
151
+ return fmt .Errorf ("command %q function cannot be nil or must have subcommands" , cmd .Name )
152
+
153
+ case cmd .Do != nil && len (cmds ) != 0 :
154
+ return fmt .Errorf ("command %q function cannot be set and have subcommands" , cmd .Name )
149
155
150
156
case cmd .Name == "help" || cmd .Name == "version" :
151
157
return fmt .Errorf ("command %q is reserved" , cmd .Name )
@@ -178,28 +184,48 @@ func (r *Runner) Run() error {
178
184
if r .errInit != nil {
179
185
return fmt .Errorf ("acmd: cannot init runner: %w" , r .errInit )
180
186
}
181
- if err := run ( r . ctx , r . cfg , r . rootCmd . subcommands , r .args ); err != nil {
187
+ if err := r . rootCmd . Do ( r . ctx , r .args ); err != nil {
182
188
return fmt .Errorf ("acmd: cannot run command: %w" , err )
183
189
}
184
190
return nil
185
191
}
186
192
187
- func run (ctx context.Context , cfg Config , cmds []Command , args []string ) error {
188
- if len (args ) == 0 {
189
- return errors .New ("no args provided" )
190
- }
191
- selected , params := args [0 ], args [1 :]
192
-
193
- for _ , c := range cmds {
194
- if c .Name == selected {
195
- return c .Do (ctx , params )
193
+ func rootDo (cfg Config , cmds []Command ) func (ctx context.Context , args []string ) error {
194
+ return func (ctx context.Context , args []string ) error {
195
+ if len (args ) == 0 {
196
+ return errors .New ("no args provided" )
196
197
}
197
- }
198
198
199
- if suggestion := suggestCommand (selected , cmds ); suggestion != "" {
200
- fmt .Fprintf (cfg .Output , "%q is not a subcommand, did you mean %q?\n " , selected , suggestion )
199
+ cmds , args := cmds , args
200
+ for {
201
+ selected , params := args [0 ], args [1 :]
202
+
203
+ var found bool
204
+ for _ , c := range cmds {
205
+ if c .Name != selected {
206
+ continue
207
+ }
208
+
209
+ // go deeper into subcommands
210
+ if c .Do == nil {
211
+ if len (params ) == 0 {
212
+ return errors .New ("no args for subcmd provided" )
213
+ }
214
+ cmds , args = c .subcommands , params
215
+ found = true
216
+ break
217
+ }
218
+ return c .Do (ctx , params )
219
+ }
220
+
221
+ if ! found {
222
+ if suggestion := suggestCommand (selected , cmds ); suggestion != "" {
223
+ fmt .Fprintf (cfg .Output , "%q is not a subcommand, did you mean %q?\n " , selected , suggestion )
224
+ }
225
+ return fmt .Errorf ("no such command %q" , selected )
226
+ }
227
+ }
201
228
}
202
- return fmt .Errorf ("no such command %q" , selected )
203
229
}
204
230
205
231
// suggestCommand for not found earlier command.
0 commit comments