Merge pull request #840 from marwan-at-work/ctx

add context.Context to cli.Context
This commit is contained in:
Audrius Butkevicius 2019-08-06 21:09:20 +01:00 committed by GitHub
commit 43bfe0068b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 2 deletions

View File

@ -236,7 +236,7 @@ func ExampleApp_Run_shellComplete() {
os.Args = []string{"greet", fmt.Sprintf("--%s", genCompName())} os.Args = []string{"greet", fmt.Sprintf("--%s", genCompName())}
app := &App{ app := &App{
Name: "greet", Name: "greet",
EnableShellCompletion: true, EnableShellCompletion: true,
Commands: []*Command{ Commands: []*Command{
{ {
@ -525,6 +525,8 @@ func TestApp_ParseSliceFlags(t *testing.T) {
}, },
}, },
} }
var _ = parsedOption
var _ = firstArg
app.Run([]string{"", "cmd", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4", "my-arg"}) app.Run([]string{"", "cmd", "-p", "22", "-p", "80", "-ip", "8.8.8.8", "-ip", "8.8.4.4", "my-arg"})

View File

@ -1,11 +1,14 @@
package cli package cli
import ( import (
"context"
"errors" "errors"
"flag" "flag"
"os" "os"
"os/signal"
"reflect" "reflect"
"strings" "strings"
"syscall"
) )
// Context is a type that is passed through to // Context is a type that is passed through to
@ -13,6 +16,7 @@ import (
// can be used to retrieve context-specific args and // can be used to retrieve context-specific args and
// parsed command-line options. // parsed command-line options.
type Context struct { type Context struct {
context.Context
App *App App *App
Command *Command Command *Command
shellComplete bool shellComplete bool
@ -24,10 +28,20 @@ type Context struct {
// NewContext creates a new context. For use in when invoking an App or Command action. // NewContext creates a new context. For use in when invoking an App or Command action.
func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
c := &Context{App: app, flagSet: set, parentContext: parentCtx} c := &Context{App: app, flagSet: set, parentContext: parentCtx}
if parentCtx != nil { if parentCtx != nil {
c.Context = parentCtx.Context
c.shellComplete = parentCtx.shellComplete c.shellComplete = parentCtx.shellComplete
} }
if c.Context == nil {
ctx, cancel := context.WithCancel(context.Background())
go func() {
defer cancel()
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
<-sigs
}()
c.Context = ctx
}
return c return c
} }

View File

@ -1,6 +1,7 @@
package cli package cli
import ( import (
"context"
"flag" "flag"
"sort" "sort"
"testing" "testing"
@ -262,3 +263,33 @@ func TestContext_lookupFlagSet(t *testing.T) {
t.Fail() t.Fail()
} }
} }
func TestNonNilContext(t *testing.T) {
ctx := NewContext(nil, nil, nil)
if ctx.Context == nil {
t.Fatal("expected a non nil context when no parent is present")
}
}
// TestContextPropagation tests that
// *cli.Context always has a valid
// context.Context
func TestContextPropagation(t *testing.T) {
parent := NewContext(nil, nil, nil)
parent.Context = context.WithValue(context.Background(), "key", "val")
ctx := NewContext(nil, nil, parent)
val := ctx.Value("key")
if val == nil {
t.Fatal("expected a parent context to be inherited but got nil")
}
valstr, _ := val.(string)
if valstr != "val" {
t.Fatalf("expected the context value to be %q but got %q", "val", valstr)
}
parent = NewContext(nil, nil, nil)
parent.Context = nil
ctx = NewContext(nil, nil, parent)
if ctx.Context == nil {
t.Fatal("expected context to not be nil even if the parent's context is nil")
}
}