@@ -5,11 +5,11 @@ package main
55
66import (
77 "fmt"
8- "log"
98 "os"
109 "path"
1110 "path/filepath"
1211 "runtime"
12+ "slices"
1313 "strings"
1414
1515 "github.com/urfave/cli/v2"
@@ -199,13 +199,50 @@ func parseConfig(cCtx *cli.Context, globalConfig *types.GlobalConfig, clientConf
199199 if err := system .LoadClientConfig (string (buf ), clientConfig ); err != nil {
200200 return err
201201 }
202+ if ! slices .Contains (validFormats , clientConfig .Client .DefaultFormat ) {
203+ return fmt .Errorf ("invalid client.default_format %q in config: valid options are %s" ,
204+ clientConfig .Client .DefaultFormat , strings .Join (validFormats , ", " ))
205+ }
202206 if err := system .LoadServerConfig (string (buf ), serverConfig ); err != nil {
203207 return err
204208 }
205209
206210 return nil
207211}
208212
213+ // fatalError prints the error to stderr and exits
214+ func fatalError (err error ) {
215+ fmt .Fprintf (os .Stderr , RED + "error: %s" + RESET + "\n " , err ) //nolint:errcheck
216+ system .NotifyServiceFailed (1 )
217+ os .Exit (1 )
218+ }
219+
220+ // setUsageErrorHandlers routes flag parsing errors through the app
221+ // ExitErrHandler so they are printed to stderr instead of the urfave/cli
222+ // default of printing usage errors on stdout
223+ func setUsageErrorHandlers (commands []* cli.Command , helpPath string ) {
224+ for _ , command := range commands {
225+ commandPath := helpPath + " " + command .Name
226+ if command .OnUsageError == nil {
227+ command .OnUsageError = func (_ * cli.Context , err error , _ bool ) error {
228+ return usageError (command .Flags , commandPath , err )
229+ }
230+ }
231+ setUsageErrorHandlers (command .Subcommands , commandPath )
232+ }
233+ }
234+
235+ // usageError adds a did-you-mean suggestion for unknown flags and a --help
236+ // hint to flag parsing errors
237+ func usageError (flags []cli.Flag , helpPath string , err error ) error {
238+ if flagName , ok := strings .CutPrefix (err .Error (), "flag provided but not defined: -" ); ok && cli .SuggestFlag != nil {
239+ if suggestion := cli .SuggestFlag (flags , flagName , false ); suggestion != "" {
240+ return fmt .Errorf ("%w (did you mean %q?)\n run '%s --help' for usage" , err , suggestion , helpPath )
241+ }
242+ }
243+ return fmt .Errorf ("%w\n run '%s --help' for usage" , err , helpPath )
244+ }
245+
209246func main () {
210247 // Start the OS service control handler if launched by the Windows
211248 // service control manager. Must run before any long initialization so
@@ -214,16 +251,17 @@ func main() {
214251
215252 globalConfig , clientConfig , serverConfig , err := system .GetDefaultConfigs ()
216253 if err != nil {
217- log . Fatal (err )
254+ fatalError (err )
218255 }
219256 globalFlags , err := globalFlags (globalConfig , clientConfig )
220257 if err != nil {
221- log . Fatal (err )
258+ fatalError (err )
222259 }
223260 allCommands , err := getAllCommands (clientConfig , serverConfig )
224261 if err != nil {
225- log . Fatal (err )
262+ fatalError (err )
226263 }
264+ setUsageErrorHandlers (allCommands , "openrun" )
227265
228266 app := & cli.App {
229267 Name : "openrun" ,
@@ -249,9 +287,7 @@ func main() {
249287 },
250288 ExitErrHandler : func (c * cli.Context , err error ) {
251289 if err != nil {
252- fmt .Fprintf (cli .ErrWriter , RED + "error: %s\n " + RESET , err ) //nolint:errcheck
253- system .NotifyServiceFailed (1 )
254- os .Exit (1 )
290+ fatalError (err )
255291 }
256292 },
257293 Commands : allCommands ,
@@ -262,14 +298,26 @@ func main() {
262298 os .Exit (0 )
263299 return nil
264300 }
301+ if ctx .Args ().Present () {
302+ // An unknown command should fail instead of showing the help and exiting 0
303+ arg := ctx .Args ().First ()
304+ if cli .SuggestCommand != nil {
305+ if suggestion := cli .SuggestCommand (ctx .App .Commands , arg ); suggestion != "" {
306+ return fmt .Errorf ("unknown command %q. %s\n run 'openrun --help' for usage" , arg , suggestion )
307+ }
308+ }
309+ return fmt .Errorf ("unknown command %q\n run 'openrun --help' for usage" , arg )
310+ }
265311 return cli .ShowAppHelp (ctx )
266312 },
267313 }
268314
315+ app .OnUsageError = func (_ * cli.Context , err error , _ bool ) error {
316+ return usageError (app .Flags , "openrun" , err )
317+ }
318+
269319 if err := app .Run (normalizeInterspersedFlags (app , os .Args )); err != nil {
270- fmt .Fprintf (os .Stderr , "error: %s" , err ) //nolint:errcheck
271- system .NotifyServiceFailed (1 )
272- os .Exit (1 )
320+ fatalError (err )
273321 }
274322}
275323
0 commit comments