mirror of
https://github.com/spf13/cobra
synced 2024-11-16 10:47:09 +00:00
Silence some usage and error logging in Execute
`RunE` was introduced on `Command` to support centralized error handling. The errors returned from `RunE` is, however, still logged by Cobra, and there is no easy way to toogle the usage logging on a case-by-case basis (other than the brutal `os.Exit(-1)`. This commit introduces two small interfaces that enables end users to signal the behavior they want from Cobra in this area.
This commit is contained in:
parent
8b2293c741
commit
f03a2c5110
2 changed files with 102 additions and 4 deletions
|
@ -2,15 +2,15 @@ package cobra
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/spf13/pflag"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"text/template"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
var _ = fmt.Println
|
||||
|
@ -25,6 +25,22 @@ var globalFlag1 bool
|
|||
var flagEcho, rootcalled bool
|
||||
var versionUsed int
|
||||
|
||||
type silentErr int
|
||||
|
||||
func (silentErr) Error() string { return "<nil>" }
|
||||
func (silentErr) ShouldLogError() bool { return false }
|
||||
func (silentErr) ShouldLogUsage() bool { return false }
|
||||
|
||||
type noErrorLogging int
|
||||
|
||||
func (noErrorLogging) Error() string { return "<nil>" }
|
||||
func (noErrorLogging) ShouldLogError() bool { return false }
|
||||
|
||||
type noUsageLogging int
|
||||
|
||||
func (noUsageLogging) Error() string { return "<nil>" }
|
||||
func (noUsageLogging) ShouldLogUsage() bool { return false }
|
||||
|
||||
const strtwoParentHelp = "help message for parent flag strtwo"
|
||||
const strtwoChildHelp = "help message for child flag strtwo"
|
||||
|
||||
|
@ -582,6 +598,64 @@ func TestSubcommandArgEvaluation(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSilentError(t *testing.T) {
|
||||
rootCmd := initializeWithRootCmd()
|
||||
|
||||
tests := []struct {
|
||||
cmd *Command
|
||||
logError bool
|
||||
logUsage bool
|
||||
}{
|
||||
{
|
||||
&Command{
|
||||
Use: "silent",
|
||||
RunE: func(cmd *Command, args []string) error {
|
||||
return silentErr(1)
|
||||
}}, false, false},
|
||||
{
|
||||
&Command{
|
||||
Use: "nousage",
|
||||
RunE: func(cmd *Command, args []string) error {
|
||||
return noUsageLogging(2)
|
||||
}}, true, false},
|
||||
{
|
||||
&Command{
|
||||
Use: "noerror",
|
||||
RunE: func(cmd *Command, args []string) error {
|
||||
return noErrorLogging(3)
|
||||
}}, false, true},
|
||||
{
|
||||
&Command{
|
||||
Use: "regular",
|
||||
RunE: func(cmd *Command, args []string) error {
|
||||
return errors.New("Failed")
|
||||
}}, true, true},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
rootCmd.AddCommand(tc.cmd)
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
result := fullTester(rootCmd, tc.cmd.Use)
|
||||
if result.Error == nil {
|
||||
t.Fatalf("[%d] Err was nil", i)
|
||||
}
|
||||
hasError := strings.Contains(result.Output, "Error:")
|
||||
hasUsage := strings.Contains(result.Output, "Usage:")
|
||||
|
||||
if hasError != tc.logError {
|
||||
t.Errorf("[%d] Error was logged: %s", i, result.Output)
|
||||
}
|
||||
|
||||
if hasUsage != tc.logUsage {
|
||||
t.Errorf("[%d] Usage was logged: %s", i, result.Output)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestPersistentFlags(t *testing.T) {
|
||||
fullSetupTest("echo -s something -p more here")
|
||||
|
||||
|
|
28
command.go
28
command.go
|
@ -115,6 +115,16 @@ type Command struct {
|
|||
SuggestionsMinimumDistance int
|
||||
}
|
||||
|
||||
// LogError can be implemented to toggle error logging when error is returned from RunE.
|
||||
type LogError interface {
|
||||
ShouldLogError() bool
|
||||
}
|
||||
|
||||
// LogUsage can be implemented to toggle usage logging when error is returned from RunE.
|
||||
type LogUsage interface {
|
||||
ShouldLogUsage() bool
|
||||
}
|
||||
|
||||
// os.Args[1:] by default, if desired, can be overridden
|
||||
// particularly useful when testing.
|
||||
func (c *Command) SetArgs(a []string) {
|
||||
|
@ -637,8 +647,22 @@ func (c *Command) Execute() (err error) {
|
|||
cmd.HelpFunc()(cmd, args)
|
||||
return nil
|
||||
}
|
||||
c.Println(cmd.UsageString())
|
||||
c.Println("Error:", err.Error())
|
||||
|
||||
logError := true
|
||||
logUsage := true
|
||||
|
||||
if le, ok := err.(LogError); ok {
|
||||
logError = le.ShouldLogError()
|
||||
}
|
||||
if lu, ok := err.(LogUsage); ok {
|
||||
logUsage = lu.ShouldLogUsage()
|
||||
}
|
||||
if logUsage {
|
||||
c.Println(cmd.UsageString())
|
||||
}
|
||||
if logError {
|
||||
c.Println("Error:", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
|
|
Loading…
Reference in a new issue