mirror of https://github.com/spf13/cobra.git
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,15 +2,15 @@ package cobra
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = fmt.Println
|
var _ = fmt.Println
|
||||||
|
@ -25,6 +25,22 @@ var globalFlag1 bool
|
||||||
var flagEcho, rootcalled bool
|
var flagEcho, rootcalled bool
|
||||||
var versionUsed int
|
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 strtwoParentHelp = "help message for parent flag strtwo"
|
||||||
const strtwoChildHelp = "help message for child 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) {
|
func TestPersistentFlags(t *testing.T) {
|
||||||
fullSetupTest("echo -s something -p more here")
|
fullSetupTest("echo -s something -p more here")
|
||||||
|
|
||||||
|
|
28
command.go
28
command.go
|
@ -115,6 +115,16 @@ type Command struct {
|
||||||
SuggestionsMinimumDistance int
|
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
|
// os.Args[1:] by default, if desired, can be overridden
|
||||||
// particularly useful when testing.
|
// particularly useful when testing.
|
||||||
func (c *Command) SetArgs(a []string) {
|
func (c *Command) SetArgs(a []string) {
|
||||||
|
@ -637,8 +647,22 @@ func (c *Command) Execute() (err error) {
|
||||||
cmd.HelpFunc()(cmd, args)
|
cmd.HelpFunc()(cmd, args)
|
||||||
return nil
|
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
|
return
|
||||||
|
|
Loading…
Reference in New Issue