From 424ae202cd2d25fec20f7cca36e02ea6c819587c Mon Sep 17 00:00:00 2001 From: Roberto Hidalgo Date: Tue, 17 Jan 2023 22:20:46 -0600 Subject: [PATCH] permit exception handling and help fuckery --- internal/registry/cobra.go | 4 +--- internal/registry/registry.go | 19 +++++++++++------ main.go | 5 +++++ pkg/command/command.go | 7 +----- pkg/command/value.go | 4 +--- pkg/env/env.go | 1 - pkg/errors/errors.go | 40 ----------------------------------- pkg/errors/handler.go | 19 +++++------------ pkg/runtime/runtime_test.go | 1 - 9 files changed, 25 insertions(+), 75 deletions(-) diff --git a/internal/registry/cobra.go b/internal/registry/cobra.go index 2eee2b3..0c4ab88 100644 --- a/internal/registry/cobra.go +++ b/internal/registry/cobra.go @@ -27,9 +27,7 @@ func newCobraRoot(root *command.Command) *cobra.Command { SilenceErrors: true, ValidArgs: []string{""}, Args: func(cmd *cobra.Command, args []string) error { - err := cobra.OnlyValidArgs(cmd, args) - if err != nil { - + if err := cobra.OnlyValidArgs(cmd, args); err != nil { suggestions := []string{} bold := color.New(color.Bold) for _, l := range cmd.SuggestionsFor(args[len(args)-1]) { diff --git a/internal/registry/registry.go b/internal/registry/registry.go index c3f2a2f..3605a52 100644 --- a/internal/registry/registry.go +++ b/internal/registry/registry.go @@ -20,6 +20,8 @@ import ( // ContextKeyRuntimeIndex is the string key used to store context in a cobra Command. const ContextKeyRuntimeIndex = "x-chinampa-runtime-index" +var ErrorHandler = errors.HandleCobraExit + var log = logrus.WithField("chinampa", "registry") var registry = &CommandRegistry{ @@ -66,7 +68,6 @@ func Execute(version string) error { ccRoot.Annotations["version"] = version ccRoot.CompletionOptions.HiddenDefaultCmd = true ccRoot.PersistentFlags().AddFlagSet(cmdRoot.FlagSet()) - ccRoot.SetHelpCommand(commands.Help) ccRoot.AddCommand(commands.Version) ccRoot.AddCommand(commands.GenerateCompletions) @@ -91,6 +92,11 @@ func Execute(version string) error { query := []string{cp} found := false + if len(query) == 1 && query[0] == "help" { + container = commands.Help + continue + } + for _, sub := range container.Commands() { if sub.Name() == cp { container = sub @@ -132,6 +138,9 @@ func Execute(version string) error { ValidArgs: []string{""}, RunE: func(cc *cobra.Command, args []string) error { if len(args) == 0 { + if cc.Name() == "help" { + return cc.Help() + } return errors.NotFound{Msg: "No subcommand provided", Group: []string{}} } os.Exit(statuscode.NotFound) @@ -157,6 +166,7 @@ func Execute(version string) error { cmd.Path = append(cmdRoot.Path, cmd.Path...) } cmdRoot.SetCobra(ccRoot) + ccRoot.SetHelpCommand(commands.Help) current, remaining, err := ccRoot.Find(os.Args[1:]) if err != nil { @@ -169,11 +179,6 @@ func Execute(version string) error { current = sub } log.Debugf("exec: calling %s", current.CommandPath()) - err = current.Execute() - if err != nil { - log.Debugf("exec: error calling %s, %s", current.CommandPath(), err) - errors.HandleCobraExit(current, err) - } - return err + return ErrorHandler(current, current.Execute()) } diff --git a/main.go b/main.go index 4817ef1..23aa310 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "git.rob.mx/nidito/chinampa/internal/registry" "git.rob.mx/nidito/chinampa/pkg/command" "git.rob.mx/nidito/chinampa/pkg/runtime" + "github.com/spf13/cobra" ) func Register(cmds ...*command.Command) { @@ -21,6 +22,10 @@ type Config struct { Description string } +func SetErrorHandler(handlerFunc func(cmd *cobra.Command, err error) error) { + registry.ErrorHandler = handlerFunc +} + func Execute(config Config) error { runtime.Executable = config.Name command.Root.Summary = config.Summary diff --git a/pkg/command/command.go b/pkg/command/command.go index 916ecc5..e5a7d7b 100644 --- a/pkg/command/command.go +++ b/pkg/command/command.go @@ -7,7 +7,6 @@ import ( "strconv" "strings" - "git.rob.mx/nidito/chinampa/pkg/errors" "git.rob.mx/nidito/chinampa/pkg/runtime" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -145,11 +144,7 @@ func (cmd *Command) Run(cc *cobra.Command, args []string) error { return err } - err := cmd.Action(cmd) - if err != nil { - errors.HandleCobraExit(cmd.Cobra, err) - } - return err + return cmd.Action(cmd) } func (cmd *Command) SetCobra(cc *cobra.Command) { diff --git a/pkg/command/value.go b/pkg/command/value.go index 8bcd226..1bd0a4f 100644 --- a/pkg/command/value.go +++ b/pkg/command/value.go @@ -122,7 +122,6 @@ func (vs *ValueSource) Resolve(currentValue string) (values []string, flag cobra err = ctx.Err() return } - case vs.Command != nil: if vs.command == nil { return nil, cobra.ShellCompDirectiveError, fmt.Errorf("bug: command is nil") @@ -168,7 +167,7 @@ func (vs *ValueSource) Resolve(currentValue string) (values []string, flag cobra return nil, flag, err } default: - return nil, flag, fmt.Errorf("Empty value source") + return nil, flag, fmt.Errorf("empty value source") } vs.computed = &values @@ -242,7 +241,6 @@ func (vs *ValueSource) UnmarshalYAML(node *yaml.Node) error { } if t, ok := intermediate["timeout"]; ok { - if err := t.Decode(&vs.Timeout); err != nil { logrus.Errorf("could not decode timeout: %s", err) return err diff --git a/pkg/env/env.go b/pkg/env/env.go index cd7c4ae..f9f4e5a 100644 --- a/pkg/env/env.go +++ b/pkg/env/env.go @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 package env -// Environment Variables. var HelpUnstyled = "HELP_STYLE_PLAIN" var HelpStyle = "HELP_STYLE" var Verbose = "VERBOSE" diff --git a/pkg/errors/errors.go b/pkg/errors/errors.go index 6283962..f21013b 100644 --- a/pkg/errors/errors.go +++ b/pkg/errors/errors.go @@ -2,8 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 package errors -import "fmt" - type NotFound struct { Msg string Group []string @@ -13,24 +11,6 @@ type BadArguments struct { Msg string } -type NotExecutable struct { - Msg string -} - -type ConfigError struct { - Err error - Config string -} - -type EnvironmentError struct { - Err error -} - -type SubCommandExit struct { - Err error - ExitCode int -} - func (err NotFound) Error() string { return err.Msg } @@ -38,23 +18,3 @@ func (err NotFound) Error() string { func (err BadArguments) Error() string { return err.Msg } - -func (err NotExecutable) Error() string { - return err.Msg -} - -func (err SubCommandExit) Error() string { - if err.Err != nil { - return err.Err.Error() - } - - return "" -} - -func (err ConfigError) Error() string { - return fmt.Sprintf("Invalid configuration %s: %v", err.Config, err.Err) -} - -func (err EnvironmentError) Error() string { - return fmt.Sprintf("Invalid MILPA_ environment: %v", err.Err) -} diff --git a/pkg/errors/handler.go b/pkg/errors/handler.go index 6243151..cce6b3a 100644 --- a/pkg/errors/handler.go +++ b/pkg/errors/handler.go @@ -22,20 +22,17 @@ func showHelp(cmd *cobra.Command) { } } -func HandleCobraExit(cmd *cobra.Command, err error) { +func HandleCobraExit(cmd *cobra.Command, err error) error { if err == nil { - ok, err := cmd.Flags().GetBool(_c.HelpCommandName) + ok, err := cmd.PersistentFlags().GetBool(_c.HelpCommandName) if cmd.Name() == _c.HelpCommandName || err == nil && ok { os.Exit(statuscode.RenderHelp) } - os.Exit(42) + os.Exit(statuscode.Ok) } - switch tErr := err.(type) { - case SubCommandExit: - logrus.Debugf("Sub-command failed with: %s", err.Error()) - os.Exit(tErr.ExitCode) + switch err.(type) { case BadArguments: showHelp(cmd) logrus.Error(err) @@ -44,13 +41,6 @@ func HandleCobraExit(cmd *cobra.Command, err error) { showHelp(cmd) logrus.Error(err) os.Exit(statuscode.NotFound) - case ConfigError: - showHelp(cmd) - logrus.Error(err) - os.Exit(statuscode.ConfigError) - case EnvironmentError: - logrus.Error(err) - os.Exit(statuscode.ConfigError) default: if strings.HasPrefix(err.Error(), "unknown command") { showHelp(cmd) @@ -64,4 +54,5 @@ func HandleCobraExit(cmd *cobra.Command, err error) { logrus.Errorf("Unknown error: %s", err) os.Exit(2) + return err } diff --git a/pkg/runtime/runtime_test.go b/pkg/runtime/runtime_test.go index 7148714..ad90f4d 100644 --- a/pkg/runtime/runtime_test.go +++ b/pkg/runtime/runtime_test.go @@ -132,7 +132,6 @@ func TestSilent(t *testing.T) { t.Fail() } }) - } func TestEnvironmentMapEnabled(t *testing.T) {