feat: flag action

This commit is contained in:
Wendell Sun 2022-02-15 23:49:41 +08:00 committed by Dan Buch
parent a2c3729797
commit e2e14ec6ef
Signed by: meatballhat
GPG Key ID: A12F782281063434
19 changed files with 234 additions and 0 deletions

26
app.go
View File

@ -340,6 +340,10 @@ func (a *App) RunContext(ctx context.Context, arguments []string) (err error) {
}
}
if err = runFlagActions(cCtx, a.Flags); err != nil {
return err
}
var c *Command
args := cCtx.Args()
if args.Present() {
@ -521,6 +525,10 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
}
}
if err = runFlagActions(cCtx, a.Flags); err != nil {
return err
}
args := cCtx.Args()
if args.Present() {
name := args.First()
@ -644,6 +652,24 @@ func (a *App) argsWithDefaultCommand(oldArgs Args) Args {
return oldArgs
}
func runFlagActions(c *Context, fs []Flag) error {
for _, f := range fs {
isSet := false
for _, name := range f.Names() {
if c.IsSet(name) {
isSet = true
break
}
}
if isSet {
if err := f.RunAction(c); err != nil {
return err
}
}
}
return nil
}
// Author represents someone who has contributed to a cli project.
type Author struct {
Name string // The Authors name

View File

@ -2357,6 +2357,10 @@ func (c *customBoolFlag) Apply(set *flag.FlagSet) error {
return nil
}
func (c *customBoolFlag) RunAction(*Context) error {
return nil
}
func (c *customBoolFlag) IsSet() bool {
return false
}
@ -2596,3 +2600,66 @@ func TestSetupInitializesOnlyNilWriters(t *testing.T) {
t.Errorf("expected a.Writer to be os.Stdout")
}
}
func TestFlagAction(t *testing.T) {
r := []string{}
actionFunc := func(c *Context, s string) error {
r = append(r, s)
return nil
}
app := &App{
Name: "command",
Writer: io.Discard,
Flags: []Flag{&StringFlag{Name: "flag", Action: actionFunc}},
Commands: []*Command{
{
Name: "command1",
Flags: []Flag{&StringFlag{Name: "flag1", Aliases: []string{"f1"}, Action: actionFunc}},
Subcommands: []*Command{
{
Name: "command2",
Flags: []Flag{&StringFlag{Name: "flag2", Action: actionFunc}},
},
},
},
},
}
tests := []struct {
args []string
exp []string
}{
{
args: []string{"command", "--flag=f"},
exp: []string{"f"},
},
{
args: []string{"command", "command1", "-f1=f1", "command2"},
exp: []string{"f1"},
},
{
args: []string{"command", "command1", "-f1=f1", "command2", "--flag2=f2"},
exp: []string{"f1", "f2"},
},
{
args: []string{"command", "--flag=f", "command1", "-flag1=f1"},
exp: []string{"f", "f1"},
},
{
args: []string{"command", "--flag=f", "command1", "-f1=f1"},
exp: []string{"f", "f1"},
},
{
args: []string{"command", "--flag=f", "command1", "-f1=f1", "command2", "--flag2=f2"},
exp: []string{"f", "f1", "f2"},
},
}
for _, test := range tests {
r = []string{}
err := app.Run(test.args)
expect(t, err, nil)
expect(t, r, test.exp)
}
}

View File

@ -165,6 +165,10 @@ func (c *Command) Run(ctx *Context) (err error) {
}
}
if err = runFlagActions(cCtx, c.Flags); err != nil {
return err
}
if c.Action == nil {
c.Action = helpSubcommand.Action
}

View File

@ -122,6 +122,8 @@ type Flag interface {
// GetValue returns the flags value as string representation and an empty
// string if the flag takes no value at all.
GetValue() string
RunAction(*Context) error
}
// Countable is an interface to enable detection of flag values which support

View File

@ -72,6 +72,15 @@ func (f *BoolFlag) GetDefaultText() string {
return fmt.Sprintf("%v", f.Value)
}
// RunAction executes flag action if set
func (f *BoolFlag) RunAction(c *Context) error {
if f.Action != nil {
return f.Action(c, c.Bool(f.Name))
}
return nil
}
// Apply populates the flag given the flag set and environment
func (f *BoolFlag) Apply(set *flag.FlagSet) error {
if val, source, found := flagFromEnvOrFile(f.EnvVars, f.FilePath); found {

View File

@ -42,6 +42,15 @@ func (f *DurationFlag) Get(ctx *Context) time.Duration {
return ctx.Duration(f.Name)
}
// RunAction executes flag action if set
func (f *DurationFlag) RunAction(c *Context) error {
if f.Action != nil {
return f.Action(c, c.Duration(f.Name))
}
return nil
}
// Duration looks up the value of a local DurationFlag, returns
// 0 if not found
func (cCtx *Context) Duration(name string) time.Duration {

View File

@ -42,6 +42,15 @@ func (f *Float64Flag) Get(ctx *Context) float64 {
return ctx.Float64(f.Name)
}
// RunAction executes flag action if set
func (f *Float64Flag) RunAction(c *Context) error {
if f.Action != nil {
return f.Action(c, c.Float64(f.Name))
}
return nil
}
// Float64 looks up the value of a local Float64Flag, returns
// 0 if not found
func (cCtx *Context) Float64(name string) float64 {

View File

@ -153,6 +153,15 @@ func (f *Float64SliceFlag) stringify() string {
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
}
// RunAction executes flag action if set
func (f *Float64SliceFlag) RunAction(c *Context) error {
if f.Action != nil {
return f.Action(c, c.Float64Slice(f.Name))
}
return nil
}
// Float64Slice looks up the value of a local Float64SliceFlag, returns
// nil if not found
func (cCtx *Context) Float64Slice(name string) []float64 {

View File

@ -45,6 +45,15 @@ func (f *GenericFlag) Get(ctx *Context) interface{} {
return ctx.Generic(f.Name)
}
// RunAction executes flag action if set
func (f *GenericFlag) RunAction(c *Context) error {
if f.Action != nil {
return f.Action(c, c.Generic(f.Name))
}
return nil
}
// Generic looks up the value of a local GenericFlag, returns
// nil if not found
func (cCtx *Context) Generic(name string) interface{} {

View File

@ -43,6 +43,15 @@ func (f *IntFlag) Get(ctx *Context) int {
return ctx.Int(f.Name)
}
// RunAction executes flag action if set
func (f *IntFlag) RunAction(c *Context) error {
if f.Action != nil {
return f.Action(c, c.Int(f.Name))
}
return nil
}
// Int looks up the value of a local IntFlag, returns
// 0 if not found
func (cCtx *Context) Int(name string) int {

View File

@ -42,6 +42,15 @@ func (f *Int64Flag) Get(ctx *Context) int64 {
return ctx.Int64(f.Name)
}
// RunAction executes flag action if set
func (f *Int64Flag) RunAction(c *Context) error {
if f.Action != nil {
return f.Action(c, c.Int64(f.Name))
}
return nil
}
// Int64 looks up the value of a local Int64Flag, returns
// 0 if not found
func (cCtx *Context) Int64(name string) int64 {

View File

@ -151,6 +151,15 @@ func (f *Int64SliceFlag) stringify() string {
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
}
// RunAction executes flag action if set
func (f *Int64SliceFlag) RunAction(c *Context) error {
if f.Action != nil {
return f.Action(c, c.Int64Slice(f.Name))
}
return nil
}
// Int64Slice looks up the value of a local Int64SliceFlag, returns
// nil if not found
func (cCtx *Context) Int64Slice(name string) []int64 {

View File

@ -162,6 +162,15 @@ func (f *IntSliceFlag) stringify() string {
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
}
// RunAction executes flag action if set
func (f *IntSliceFlag) RunAction(c *Context) error {
if f.Action != nil {
return f.Action(c, c.IntSlice(f.Name))
}
return nil
}
// IntSlice looks up the value of a local IntSliceFlag, returns
// nil if not found
func (cCtx *Context) IntSlice(name string) []int {

View File

@ -47,6 +47,15 @@ func (f *PathFlag) Get(ctx *Context) string {
return ctx.Path(f.Name)
}
// RunAction executes flag action if set
func (f *PathFlag) RunAction(c *Context) error {
if f.Action != nil {
return f.Action(c, c.Path(f.Name))
}
return nil
}
// Path looks up the value of a local PathFlag, returns
// "" if not found
func (cCtx *Context) Path(name string) string {

View File

@ -45,6 +45,15 @@ func (f *StringFlag) Get(ctx *Context) string {
return ctx.String(f.Name)
}
// RunAction executes flag action if set
func (f *StringFlag) RunAction(c *Context) error {
if f.Action != nil {
return f.Action(c, c.String(f.Name))
}
return nil
}
// String looks up the value of a local StringFlag, returns
// "" if not found
func (cCtx *Context) String(name string) string {

View File

@ -143,6 +143,15 @@ func (f *StringSliceFlag) stringify() string {
return stringifySliceFlag(f.Usage, f.Names(), defaultVals)
}
// RunAction executes flag action if set
func (f *StringSliceFlag) RunAction(c *Context) error {
if f.Action != nil {
return f.Action(c, c.StringSlice(f.Name))
}
return nil
}
// StringSlice looks up the value of a local StringSliceFlag, returns
// nil if not found
func (cCtx *Context) StringSlice(name string) []string {

View File

@ -120,6 +120,15 @@ func (f *TimestampFlag) Get(ctx *Context) *time.Time {
return ctx.Timestamp(f.Name)
}
// RunAction executes flag action if set
func (f *TimestampFlag) RunAction(c *Context) error {
if f.Action != nil {
return f.Action(c, c.Timestamp(f.Name))
}
return nil
}
// Timestamp gets the timestamp from a flag name
func (cCtx *Context) Timestamp(name string) *time.Time {
if fs := cCtx.lookupFlagSet(name); fs != nil {

View File

@ -42,6 +42,15 @@ func (f *UintFlag) Get(ctx *Context) uint {
return ctx.Uint(f.Name)
}
// RunAction executes flag action if set
func (f *UintFlag) RunAction(c *Context) error {
if f.Action != nil {
return f.Action(c, c.Uint(f.Name))
}
return nil
}
// Uint looks up the value of a local UintFlag, returns
// 0 if not found
func (cCtx *Context) Uint(name string) uint {

View File

@ -42,6 +42,15 @@ func (f *Uint64Flag) Get(ctx *Context) uint64 {
return ctx.Uint64(f.Name)
}
// RunAction executes flag action if set
func (f *Uint64Flag) RunAction(c *Context) error {
if f.Action != nil {
return f.Action(c, c.Uint64(f.Name))
}
return nil
}
// Uint64 looks up the value of a local Uint64Flag, returns
// 0 if not found
func (cCtx *Context) Uint64(name string) uint64 {