Skip to content

Commit

Permalink
Merge branch 'main' into issue_1550
Browse files Browse the repository at this point in the history
  • Loading branch information
hellodudu committed Oct 31, 2022
2 parents b11badc + ae8d932 commit 6f52cd5
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 3 deletions.
10 changes: 10 additions & 0 deletions app.go
Expand Up @@ -8,6 +8,7 @@ import (
"os"
"path/filepath"
"sort"
"strings"
"time"
)

Expand All @@ -20,6 +21,7 @@ var (
errInvalidActionType = NewExitError("ERROR invalid Action type. "+
fmt.Sprintf("Must be `func(*Context`)` or `func(*Context) error). %s", contactSysadmin)+
fmt.Sprintf("See %s", appActionDeprecationURL), 2)
ignoreFlagPrefix = "test." // this is to ignore test flags when adding flags from other packages

SuggestFlag SuggestFlagFunc = suggestFlag
SuggestCommand SuggestCommandFunc = suggestCommand
Expand Down Expand Up @@ -197,6 +199,14 @@ func (a *App) Setup() {
a.ErrWriter = os.Stderr
}

// add global flags added by other packages
flag.VisitAll(func(f *flag.Flag) {
// skip test flags
if !strings.HasPrefix(f.Name, ignoreFlagPrefix) {
a.Flags = append(a.Flags, &extFlag{f})
}
})

var newCommands []*Command

for _, c := range a.Commands {
Expand Down
36 changes: 36 additions & 0 deletions app_test.go
Expand Up @@ -643,6 +643,42 @@ func TestApp_RunDefaultCommandWithFlags(t *testing.T) {
}
}

func TestApp_FlagsFromExtPackage(t *testing.T) {

var someint int
flag.IntVar(&someint, "epflag", 2, "ext package flag usage")

// Based on source code we can reset the global flag parsing this way
defer func() {
flag.CommandLine = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
}()

a := &App{
Flags: []Flag{
&StringFlag{
Name: "carly",
Aliases: []string{"c"},
Required: false,
},
&BoolFlag{
Name: "jimbob",
Aliases: []string{"j"},
Required: false,
Value: true,
},
},
}

err := a.Run([]string{"foo", "-c", "cly", "--epflag", "10"})
if err != nil {
t.Error(err)
}

if someint != 10 {
t.Errorf("Expected 10 got %d for someint", someint)
}
}

func TestApp_Setup_defaultsReader(t *testing.T) {
app := &App{}
app.Setup()
Expand Down
21 changes: 18 additions & 3 deletions errors.go
Expand Up @@ -83,7 +83,7 @@ type ExitCoder interface {

type exitError struct {
exitCode int
message interface{}
err error
}

// NewExitError calls Exit to create a new ExitCoder.
Expand All @@ -101,20 +101,35 @@ func NewExitError(message interface{}, exitCode int) ExitCoder {
// by overriding the ExitErrHandler function on an App or the package-global
// OsExiter function.
func Exit(message interface{}, exitCode int) ExitCoder {
var err error

switch e := message.(type) {
case ErrorFormatter:
err = fmt.Errorf("%+v", message)
case error:
err = e
default:
err = fmt.Errorf("%+v", message)
}

return &exitError{
message: message,
err: err,
exitCode: exitCode,
}
}

func (ee *exitError) Error() string {
return fmt.Sprintf("%v", ee.message)
return ee.err.Error()
}

func (ee *exitError) ExitCode() int {
return ee.exitCode
}

func (ee *exitError) Unwrap() error {
return ee.err
}

// HandleExitCoder handles errors implementing ExitCoder by printing their
// message and calling OsExiter with the given exit code.
//
Expand Down
19 changes: 19 additions & 0 deletions errors_test.go
Expand Up @@ -45,6 +45,25 @@ func TestHandleExitCoder_ExitCoder(t *testing.T) {
expect(t, called, true)
}

func TestHandleExitCoder_ErrorExitCoder(t *testing.T) {
exitCode := 0
called := false

OsExiter = func(rc int) {
if !called {
exitCode = rc
called = true
}
}

defer func() { OsExiter = fakeOsExiter }()

HandleExitCoder(Exit(errors.New("galactic perimeter breach"), 9))

expect(t, exitCode, 9)
expect(t, called, true)
}

func TestHandleExitCoder_MultiErrorWithExitCoder(t *testing.T) {
exitCode := 0
called := false
Expand Down
48 changes: 48 additions & 0 deletions flag_ext.go
@@ -0,0 +1,48 @@
package cli

import "flag"

type extFlag struct {
f *flag.Flag
}

func (e *extFlag) Apply(fs *flag.FlagSet) error {
fs.Var(e.f.Value, e.f.Name, e.f.Usage)
return nil
}

func (e *extFlag) Names() []string {
return []string{e.f.Name}
}

func (e *extFlag) IsSet() bool {
return false
}

func (e *extFlag) String() string {
return FlagStringer(e)
}

func (e *extFlag) IsVisible() bool {
return true
}

func (e *extFlag) TakesValue() bool {
return false
}

func (e *extFlag) GetUsage() string {
return e.f.Usage
}

func (e *extFlag) GetValue() string {
return e.f.Value.String()
}

func (e *extFlag) GetDefaultText() string {
return e.f.DefValue
}

func (e *extFlag) GetEnvVars() []string {
return nil
}

0 comments on commit 6f52cd5

Please sign in to comment.