permit exception handling and help fuckery
This commit is contained in:
parent
087a978a8c
commit
424ae202cd
|
@ -27,9 +27,7 @@ func newCobraRoot(root *command.Command) *cobra.Command {
|
||||||
SilenceErrors: true,
|
SilenceErrors: true,
|
||||||
ValidArgs: []string{""},
|
ValidArgs: []string{""},
|
||||||
Args: func(cmd *cobra.Command, args []string) error {
|
Args: func(cmd *cobra.Command, args []string) error {
|
||||||
err := cobra.OnlyValidArgs(cmd, args)
|
if err := cobra.OnlyValidArgs(cmd, args); err != nil {
|
||||||
if err != nil {
|
|
||||||
|
|
||||||
suggestions := []string{}
|
suggestions := []string{}
|
||||||
bold := color.New(color.Bold)
|
bold := color.New(color.Bold)
|
||||||
for _, l := range cmd.SuggestionsFor(args[len(args)-1]) {
|
for _, l := range cmd.SuggestionsFor(args[len(args)-1]) {
|
||||||
|
|
|
@ -20,6 +20,8 @@ import (
|
||||||
// ContextKeyRuntimeIndex is the string key used to store context in a cobra Command.
|
// ContextKeyRuntimeIndex is the string key used to store context in a cobra Command.
|
||||||
const ContextKeyRuntimeIndex = "x-chinampa-runtime-index"
|
const ContextKeyRuntimeIndex = "x-chinampa-runtime-index"
|
||||||
|
|
||||||
|
var ErrorHandler = errors.HandleCobraExit
|
||||||
|
|
||||||
var log = logrus.WithField("chinampa", "registry")
|
var log = logrus.WithField("chinampa", "registry")
|
||||||
|
|
||||||
var registry = &CommandRegistry{
|
var registry = &CommandRegistry{
|
||||||
|
@ -66,7 +68,6 @@ func Execute(version string) error {
|
||||||
ccRoot.Annotations["version"] = version
|
ccRoot.Annotations["version"] = version
|
||||||
ccRoot.CompletionOptions.HiddenDefaultCmd = true
|
ccRoot.CompletionOptions.HiddenDefaultCmd = true
|
||||||
ccRoot.PersistentFlags().AddFlagSet(cmdRoot.FlagSet())
|
ccRoot.PersistentFlags().AddFlagSet(cmdRoot.FlagSet())
|
||||||
ccRoot.SetHelpCommand(commands.Help)
|
|
||||||
ccRoot.AddCommand(commands.Version)
|
ccRoot.AddCommand(commands.Version)
|
||||||
ccRoot.AddCommand(commands.GenerateCompletions)
|
ccRoot.AddCommand(commands.GenerateCompletions)
|
||||||
|
|
||||||
|
@ -91,6 +92,11 @@ func Execute(version string) error {
|
||||||
|
|
||||||
query := []string{cp}
|
query := []string{cp}
|
||||||
found := false
|
found := false
|
||||||
|
if len(query) == 1 && query[0] == "help" {
|
||||||
|
container = commands.Help
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
for _, sub := range container.Commands() {
|
for _, sub := range container.Commands() {
|
||||||
if sub.Name() == cp {
|
if sub.Name() == cp {
|
||||||
container = sub
|
container = sub
|
||||||
|
@ -132,6 +138,9 @@ func Execute(version string) error {
|
||||||
ValidArgs: []string{""},
|
ValidArgs: []string{""},
|
||||||
RunE: func(cc *cobra.Command, args []string) error {
|
RunE: func(cc *cobra.Command, args []string) error {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
|
if cc.Name() == "help" {
|
||||||
|
return cc.Help()
|
||||||
|
}
|
||||||
return errors.NotFound{Msg: "No subcommand provided", Group: []string{}}
|
return errors.NotFound{Msg: "No subcommand provided", Group: []string{}}
|
||||||
}
|
}
|
||||||
os.Exit(statuscode.NotFound)
|
os.Exit(statuscode.NotFound)
|
||||||
|
@ -157,6 +166,7 @@ func Execute(version string) error {
|
||||||
cmd.Path = append(cmdRoot.Path, cmd.Path...)
|
cmd.Path = append(cmdRoot.Path, cmd.Path...)
|
||||||
}
|
}
|
||||||
cmdRoot.SetCobra(ccRoot)
|
cmdRoot.SetCobra(ccRoot)
|
||||||
|
ccRoot.SetHelpCommand(commands.Help)
|
||||||
|
|
||||||
current, remaining, err := ccRoot.Find(os.Args[1:])
|
current, remaining, err := ccRoot.Find(os.Args[1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -169,11 +179,6 @@ func Execute(version string) error {
|
||||||
current = sub
|
current = sub
|
||||||
}
|
}
|
||||||
log.Debugf("exec: calling %s", current.CommandPath())
|
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())
|
||||||
}
|
}
|
||||||
|
|
5
main.go
5
main.go
|
@ -6,6 +6,7 @@ import (
|
||||||
"git.rob.mx/nidito/chinampa/internal/registry"
|
"git.rob.mx/nidito/chinampa/internal/registry"
|
||||||
"git.rob.mx/nidito/chinampa/pkg/command"
|
"git.rob.mx/nidito/chinampa/pkg/command"
|
||||||
"git.rob.mx/nidito/chinampa/pkg/runtime"
|
"git.rob.mx/nidito/chinampa/pkg/runtime"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Register(cmds ...*command.Command) {
|
func Register(cmds ...*command.Command) {
|
||||||
|
@ -21,6 +22,10 @@ type Config struct {
|
||||||
Description string
|
Description string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetErrorHandler(handlerFunc func(cmd *cobra.Command, err error) error) {
|
||||||
|
registry.ErrorHandler = handlerFunc
|
||||||
|
}
|
||||||
|
|
||||||
func Execute(config Config) error {
|
func Execute(config Config) error {
|
||||||
runtime.Executable = config.Name
|
runtime.Executable = config.Name
|
||||||
command.Root.Summary = config.Summary
|
command.Root.Summary = config.Summary
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.rob.mx/nidito/chinampa/pkg/errors"
|
|
||||||
"git.rob.mx/nidito/chinampa/pkg/runtime"
|
"git.rob.mx/nidito/chinampa/pkg/runtime"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
@ -145,11 +144,7 @@ func (cmd *Command) Run(cc *cobra.Command, args []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err := cmd.Action(cmd)
|
return cmd.Action(cmd)
|
||||||
if err != nil {
|
|
||||||
errors.HandleCobraExit(cmd.Cobra, err)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cmd *Command) SetCobra(cc *cobra.Command) {
|
func (cmd *Command) SetCobra(cc *cobra.Command) {
|
||||||
|
|
|
@ -122,7 +122,6 @@ func (vs *ValueSource) Resolve(currentValue string) (values []string, flag cobra
|
||||||
err = ctx.Err()
|
err = ctx.Err()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
case vs.Command != nil:
|
case vs.Command != nil:
|
||||||
if vs.command == nil {
|
if vs.command == nil {
|
||||||
return nil, cobra.ShellCompDirectiveError, fmt.Errorf("bug: command is 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
|
return nil, flag, err
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, flag, fmt.Errorf("Empty value source")
|
return nil, flag, fmt.Errorf("empty value source")
|
||||||
}
|
}
|
||||||
|
|
||||||
vs.computed = &values
|
vs.computed = &values
|
||||||
|
@ -242,7 +241,6 @@ func (vs *ValueSource) UnmarshalYAML(node *yaml.Node) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if t, ok := intermediate["timeout"]; ok {
|
if t, ok := intermediate["timeout"]; ok {
|
||||||
|
|
||||||
if err := t.Decode(&vs.Timeout); err != nil {
|
if err := t.Decode(&vs.Timeout); err != nil {
|
||||||
logrus.Errorf("could not decode timeout: %s", err)
|
logrus.Errorf("could not decode timeout: %s", err)
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
package env
|
package env
|
||||||
|
|
||||||
// Environment Variables.
|
|
||||||
var HelpUnstyled = "HELP_STYLE_PLAIN"
|
var HelpUnstyled = "HELP_STYLE_PLAIN"
|
||||||
var HelpStyle = "HELP_STYLE"
|
var HelpStyle = "HELP_STYLE"
|
||||||
var Verbose = "VERBOSE"
|
var Verbose = "VERBOSE"
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
package errors
|
package errors
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
type NotFound struct {
|
type NotFound struct {
|
||||||
Msg string
|
Msg string
|
||||||
Group []string
|
Group []string
|
||||||
|
@ -13,24 +11,6 @@ type BadArguments struct {
|
||||||
Msg string
|
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 {
|
func (err NotFound) Error() string {
|
||||||
return err.Msg
|
return err.Msg
|
||||||
}
|
}
|
||||||
|
@ -38,23 +18,3 @@ func (err NotFound) Error() string {
|
||||||
func (err BadArguments) Error() string {
|
func (err BadArguments) Error() string {
|
||||||
return err.Msg
|
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)
|
|
||||||
}
|
|
||||||
|
|
|
@ -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 {
|
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 {
|
if cmd.Name() == _c.HelpCommandName || err == nil && ok {
|
||||||
os.Exit(statuscode.RenderHelp)
|
os.Exit(statuscode.RenderHelp)
|
||||||
}
|
}
|
||||||
|
|
||||||
os.Exit(42)
|
os.Exit(statuscode.Ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch tErr := err.(type) {
|
switch err.(type) {
|
||||||
case SubCommandExit:
|
|
||||||
logrus.Debugf("Sub-command failed with: %s", err.Error())
|
|
||||||
os.Exit(tErr.ExitCode)
|
|
||||||
case BadArguments:
|
case BadArguments:
|
||||||
showHelp(cmd)
|
showHelp(cmd)
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
|
@ -44,13 +41,6 @@ func HandleCobraExit(cmd *cobra.Command, err error) {
|
||||||
showHelp(cmd)
|
showHelp(cmd)
|
||||||
logrus.Error(err)
|
logrus.Error(err)
|
||||||
os.Exit(statuscode.NotFound)
|
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:
|
default:
|
||||||
if strings.HasPrefix(err.Error(), "unknown command") {
|
if strings.HasPrefix(err.Error(), "unknown command") {
|
||||||
showHelp(cmd)
|
showHelp(cmd)
|
||||||
|
@ -64,4 +54,5 @@ func HandleCobraExit(cmd *cobra.Command, err error) {
|
||||||
|
|
||||||
logrus.Errorf("Unknown error: %s", err)
|
logrus.Errorf("Unknown error: %s", err)
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,7 +132,6 @@ func TestSilent(t *testing.T) {
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEnvironmentMapEnabled(t *testing.T) {
|
func TestEnvironmentMapEnabled(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue