From 2bd340ba08196ca8c2aeb65fbe2e36d5558e2508 Mon Sep 17 00:00:00 2001 From: jholdstock Date: Fri, 17 May 2024 11:59:03 +0100 Subject: [PATCH] multi: Explicitly handle help requests. Checking for --help as an explicit step before parsing any other configs makes the code more intuitive by removing a convoluted bit of error handling, which happened to be unnecessarily duplicated in three places. Moving it to a function in the internal package makes it reusable by multiple binaries. This also enables the IgnoreUnknown option to be used whilst parsing for help, which ensures the presence of --help will always result in the help message being printed. This fixes a minor inconsistency where the help message would be printed if the flag was placed before an invalid config, but placing it after would cause an invalid config error to be written instead. For example, `vspd --help --fakeflag` vs `vspd --fakeflag --help`. --- cmd/vote-validator/main.go | 15 +++++++-------- cmd/vspd/config.go | 27 +++++++++++---------------- internal/config/flags.go | 19 +++++++++++++++++++ 3 files changed, 37 insertions(+), 24 deletions(-) create mode 100644 internal/config/flags.go diff --git a/cmd/vote-validator/main.go b/cmd/vote-validator/main.go index 2854fb39..e844e2c4 100644 --- a/cmd/vote-validator/main.go +++ b/cmd/vote-validator/main.go @@ -1,4 +1,4 @@ -// Copyright (c) 2022-2023 The Decred developers +// Copyright (c) 2022-2024 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -48,15 +48,14 @@ func main() { } func run() int { - // Load config, display help if requested. + // If command line options are requesting help, write it to stdout and exit. + if config.WriteHelp(&cfg) { + return 0 + } + + // Parse command line options. _, err := flags.Parse(&cfg) if err != nil { - var e *flags.Error - if errors.As(err, &e) { - if e.Type == flags.ErrHelp { - return 0 - } - } return 1 } diff --git a/cmd/vspd/config.go b/cmd/vspd/config.go index a0b5076f..c4438a47 100644 --- a/cmd/vspd/config.go +++ b/cmd/vspd/config.go @@ -1,4 +1,4 @@ -// Copyright (c) 2021-2023 The Decred developers +// Copyright (c) 2021-2024 The Decred developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. @@ -190,20 +190,18 @@ func loadConfig() (*vspdConfig, error) { Designation: defaultDesignation, } - // Pre-parse the command line options to see if an alternative config - // file or the version flag was specified. Any errors aside from the - // help message error can be ignored here since they will be caught by - // the final parse below. + // If command line options are requesting help, write it to stdout and exit. + if config.WriteHelp(&cfg) { + os.Exit(0) + } + + // Pre-parse the command line options to see if an alternative config file, + // home dir, or the version flag were specified. preCfg := cfg - preParser := flags.NewParser(&preCfg, flags.HelpFlag) + preParser := flags.NewParser(&preCfg, flags.None) _, err := preParser.Parse() if err != nil { - var e *flags.Error - if errors.As(err, &e) && e.Type == flags.ErrHelp { - fmt.Fprintln(os.Stdout, err) - os.Exit(0) - } return nil, err } @@ -261,7 +259,7 @@ func loadConfig() (*vspdConfig, error) { } // Load additional config from file. - parser := flags.NewParser(&cfg, flags.Default) + parser := flags.NewParser(&cfg, flags.None) err = flags.NewIniParser(parser).ParseFile(preCfg.ConfigFile) if err != nil { @@ -271,10 +269,7 @@ func loadConfig() (*vspdConfig, error) { // Parse command line options again to ensure they take precedence. _, err = parser.Parse() if err != nil { - var e *flags.Error - if !errors.As(err, &e) || e.Type != flags.ErrHelp { - fmt.Fprintln(os.Stderr, usageMessage) - } + fmt.Fprintln(os.Stderr, usageMessage) return nil, err } diff --git a/internal/config/flags.go b/internal/config/flags.go new file mode 100644 index 00000000..be8e3f32 --- /dev/null +++ b/internal/config/flags.go @@ -0,0 +1,19 @@ +// Copyright (c) 2024 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package config + +import ( + "github.com/jessevdk/go-flags" +) + +// WriteHelp will write the application help to stdout if it has been requested +// via command line options. Only the help option is evaluated, any invalid +// options are ignored. The return value indicates whether the help message was +// printed or not. +func WriteHelp(cfg interface{}) bool { + helpOpts := flags.Options(flags.HelpFlag | flags.PrintErrors | flags.IgnoreUnknown) + _, err := flags.NewParser(cfg, helpOpts).Parse() + return flags.WroteHelp(err) +}