Skip to content

Commit

Permalink
up: update some gflag and app run logic
Browse files Browse the repository at this point in the history
  • Loading branch information
inhere committed Sep 23, 2022
1 parent 931b003 commit 0b253e2
Show file tree
Hide file tree
Showing 14 changed files with 158 additions and 121 deletions.
15 changes: 12 additions & 3 deletions _examples/cliapp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/gookit/gcli/v3"
"github.com/gookit/gcli/v3/_examples/cmd"
"github.com/gookit/gcli/v3/builtin"
"github.com/gookit/gcli/v3/events"
// "github.com/gookit/gcli/v3/builtin/filewatcher"
// "github.com/gookit/gcli/v3/builtin/reverseproxy"
)
Expand Down Expand Up @@ -45,9 +46,17 @@ func main() {
// disable global options
// gcli.GOpts().SetDisable()

app.BeforeAddOpts = func(opts *gcli.Flags) {
opts.StrVar(&customGOpt, &gcli.FlagMeta{Name: "custom", Desc: "desc message for the option"})
}
// app.BeforeAddOpts = func(opts *gcli.Flags) {
// opts.StrVar(&customGOpt, &gcli.FlagMeta{Name: "custom", Desc: "desc message for the option"})
// }

app.On(events.OnAppBindOptsAfter, func(ctx *gcli.HookCtx) (stop bool) {
ctx.App.Flags().StrVar(&customGOpt, &gcli.FlagMeta{
Name: "custom",
Desc: "desc message for the option",
})
return false
})

// app.Strict = true
app.Add(cmd.GitCmd)
Expand Down
112 changes: 71 additions & 41 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ type AppConfig struct {
BeforeRun func() bool
AfterRun func() bool
BeforeAddOpts func(opts *Flags)
AfterBindOpts func(app *App) bool
AfterAddOpts func(app *App) bool
}

// App the cli app definition
Expand All @@ -53,7 +53,7 @@ type App struct {
// for manage commands
base

AppConfig
// AppConfig

fs *Flags
// app flag options
Expand Down Expand Up @@ -131,59 +131,69 @@ func NotExitOnEnd() func(*App) {
// Config the application.
//
// Notice: must be called before add command
func (app *App) Config(fn func(a *App)) {
if fn != nil {
fn(app)
func (app *App) Config(fns ...func(a *App)) {
for _, fn := range fns {
if fn != nil {
fn(app)
}
}
}

// binding global options
func (app *App) bindingGOpts() {
Logf(VerbDebug, "will begin binding app global options")
// global options flag
fs := app.fs

// binding global options
app.opts.bindingFlags(fs)
// add more ...
// This is an internal option
fs.BoolVar(&gOpts.inCompletion, &gflag.FlagMeta{
Name: "in-completion",
Desc: "generate completion scripts for bash/zsh",
// hidden it
Hidden: true,
})

// support binding custom global options
if app.BeforeAddOpts != nil {
app.BeforeAddOpts(fs)
}
}
/*************************************************************
* app initialize
*************************************************************/

// initialize application
// initialize application on: add, run
func (app *App) initialize() {
if app.initialized {
return
}

Logf(VerbCrazy, "initialize the application")
Logf(VerbCrazy, "initialize the cli application")
app.Fire(events.OnAppInitBefore, nil)

// init some info
app.InitCtx()
app.initHelpVars()

// binding global options
app.bindingGOpts()
app.bindAppOpts()

// add default error handler.
if !app.HasHook(events.OnAppRunError) {
app.On(events.OnAppRunError, defaultErrHandler)
}

app.Fire(events.OnAppInit, nil)
app.Fire(events.OnAppInitAfter, nil)
app.initialized = true
}

// binding app options
func (app *App) bindAppOpts() {
Logf(VerbDebug, "will begin binding app global options")
// global options flag
fs := app.fs
app.Fire(events.OnAppBindOptsBefore, nil)
// if app.BeforeAddOpts != nil {
// app.BeforeAddOpts(fs)
// }

// binding global options
app.opts.bindingFlags(fs)
// add more ...
// This is an internal option
fs.BoolVar(&gOpts.inCompletion, &gflag.FlagMeta{
Name: "in-completion",
Desc: "generate completion scripts for bash/zsh",
// hidden it
Hidden: true,
})

// support binding custom global options
app.Fire(events.OnAppBindOptsAfter, nil)
// if app.AfterAddOpts != nil {
// app.AfterAddOpts(app)
// }
}

/*************************************************************
* register commands
*************************************************************/
Expand Down Expand Up @@ -281,16 +291,21 @@ func (app *App) parseAppOpts(args []string) (ok bool) {
}

app.args = app.fs.FSetArgs()
if app.Fire(events.OnGOptionsParsed, map[string]any{"args": app.args}) {
Logf(VerbDebug, "stop continue on the event %s return True", events.OnGOptionsParsed)
evtData := map[string]any{"args": app.args}
if app.Fire(events.OnAppOptsParsed, evtData) {
Logf(VerbDebug, "stop running on the event %s return True", events.OnGlobalOptsParsed)
return
}

if app.Fire(events.OnGlobalOptsParsed, evtData) {
Logf(VerbDebug, "stop running on the event %s return True", events.OnGlobalOptsParsed)
return
}

// check global options
if app.opts.ShowHelp {
return app.showApplicationHelp()
}

if app.opts.ShowVersion {
return app.showVersionInfo()
}
Expand All @@ -300,7 +315,7 @@ func (app *App) parseAppOpts(args []string) (ok bool) {
color.Enable = false
}

Debugf("global option parsed, Verbose level: <mgb>%s</>", app.opts.Verbose.String())
Debugf("app options parsed, Verbose level: <mgb>%s</>", app.opts.Verbose.String())

// TODO show auto-completion for bash/zsh
if app.opts.inCompletion {
Expand All @@ -315,7 +330,11 @@ func (app *App) parseAppOpts(args []string) (ok bool) {
* prepare run
*************************************************************/

// prepare to running, parse args, get command name and command args
// prepare to running
//
// parse args
// check global options
// get command name and command args
func (app *App) prepareRun() (code int, name string) {
// find command name.
name = app.findCommandName()
Expand Down Expand Up @@ -437,13 +456,14 @@ func (app *App) QuickRun() int {
return app.Run(os.Args[1:])
}

// Run the application
// Run the application with input args
//
// Usage:
//
// // run with os.Args
// app.Run(nil)
// app.Run(os.Args[1:])
//
// // custom args
// app.Run([]string{"cmd", "--name", "inhere"})
func (app *App) Run(args []string) (code int) {
Expand All @@ -455,7 +475,7 @@ func (app *App) Run(args []string) (code int) {
args = os.Args[1:] // exclude first arg, it's binFile.
}

Debugf("will begin run cli application. args: %v", args)
Debugf("will begin run application. args: %v", args)

// parse global flags
if false == app.parseAppOpts(args) {
Expand All @@ -480,7 +500,7 @@ func (app *App) Run(args []string) (code int) {
return app.exitOnEnd(code)
}

// RunLine manual run an command by command line string.
// RunLine manual run a command by command line string.
//
// eg: app.RunLine("top --top-opt val0 sub --sub-opt val1 arg0")
func (app *App) RunLine(argsLine string) int {
Expand Down Expand Up @@ -561,6 +581,16 @@ func (app *App) Exec(path string, args []string) error {
* helper methods
*************************************************************/

// Opts get
func (app *App) Opts() *GlobalOpts {
return app.opts
}

// Flags get
func (app *App) Flags() *Flags {
return app.fs
}

// Exit get the app GlobalFlags
func (app *App) Exit(code int) {
if app.ExitFunc == nil {
Expand Down
4 changes: 2 additions & 2 deletions base_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ func TestApp_Hooks_EvtAppInit(t *testing.T) {
assert.Eq(t, "trigger "+events.OnAppInit, buf.String())

buf.Reset()
cli.On(events.OnGOptionsParsed, func(ctx *gcli.HookCtx) bool {
cli.On(events.OnGlobalOptsParsed, func(ctx *gcli.HookCtx) bool {
buf.WriteString("trigger " + ctx.Name() + ", args:" + fmt.Sprintf("%v", ctx.Strings("args")))
return false
})

cli.Run([]string{"simple"})
assert.Eq(t, "trigger "+events.OnGOptionsParsed+", args:[simple]", buf.String())
assert.Eq(t, "trigger "+events.OnGlobalOptsParsed+", args:[simple]", buf.String())
}

func TestApp_Hooks_EvtCmdInit(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ func (c *Command) innerDispatch(args []string) (err error) {
return
}

c.Fire(events.OnGOptionsParsed, map[string]any{"args": args})
c.Fire(events.OnGlobalOptsParsed, map[string]any{"args": args})
}

c.Fire(events.OnCmdOptParsed, map[string]any{"args": args})
Expand Down Expand Up @@ -624,7 +624,7 @@ func (c *Command) goodName() string {
}

if !helper.IsGoodCmdName(name) {
panicf("the command name '%s' is invalid, must match: %s", name, regGoodCmdName)
panicf("the command name '%s' is invalid, must match: %s", name, helper.RegGoodCmdName)
}

// update name
Expand Down
19 changes: 15 additions & 4 deletions events/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,22 @@ package events

// constants for hooks event, there are default allowed event names
const (
OnAppInit = "app.init"
OnAppInitBefore = "app.init.before"
// OnAppInitAfter On app inited
OnAppInitAfter = "app.init.after"
// OnAppStop = "app.stopped"

OnAppBindOptsBefore = "app.bind.opts.before"
OnAppBindOptsAfter = "app.bind.opts.after"

OnAppPrepareAfter = "app.prepare.after"

// OnAppOptsParsed event
//
// Data:
// {args: app-args}
OnAppOptsParsed = "app.opts.parsed"

OnAppRunBefore = "app.run.before"
OnAppRunAfter = "app.run.after"
OnAppRunError = "app.run.error"
Expand Down Expand Up @@ -38,10 +50,9 @@ const (
OnCmdExecAfter = "cmd.exec.after"
OnCmdExecError = "cmd.exec.error"

// OnGOptionsParsed event
// OnGlobalOptsParsed event
//
// Data:
// {args: remain-args}
OnGOptionsParsed = "gcli.gopts.parsed"
// OnStop = "stop"
OnGlobalOptsParsed = "gcli.gopts.parsed"
)
5 changes: 3 additions & 2 deletions gargs.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"strings"

"github.com/gookit/gcli/v3/gflag"
"github.com/gookit/gcli/v3/helper"
"github.com/gookit/goutil/errorx"
"github.com/gookit/goutil/structs"
"github.com/gookit/goutil/strutil"
Expand Down Expand Up @@ -310,8 +311,8 @@ func (a *Argument) goodArgument() string {
panicf("the command argument name cannot be empty")
}

if !goodName.MatchString(name) {
panicf("the argument name '%s' is invalid, must match: %s", name, regGoodName)
if !helper.IsGoodName(name) {
panicf("the argument name '%s' is invalid, must match: %s", name, helper.RegGoodName)
}

a.Name = name
Expand Down
4 changes: 1 addition & 3 deletions gcli.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,9 +134,8 @@ func (g *GlobalOpts) SetDisable() {

func (g *GlobalOpts) bindingFlags(fs *Flags) {
fs.BoolOpt(&g.ShowHelp, "help", "h", false, "Display the help information")

// return ErrHelp on ShowHelp=true
fs.AfterParse = func(_ *Flags) error {
// return ErrHelp on ShowHelp=true
if g.ShowHelp {
return flag.ErrHelp
}
Expand All @@ -154,7 +153,6 @@ func (g *GlobalOpts) bindingFlags(fs *Flags) {
fs.BoolOpt(&g.NoProgress, "no-progress", "np", g.NoProgress, "Disable display progress message")
fs.BoolOpt(&g.ShowVersion, "version", "V", false, "Display app version information")
fs.BoolOpt(&g.NoInteractive, "no-interactive", "ni", g.NoInteractive, "Disable interactive confirmation operation")

// fs.BoolOpt(&g.inShell, "ishell", "", false, "Run in an interactive shell environment(`TODO`)")
}

Expand Down
7 changes: 7 additions & 0 deletions gflag/any.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build !go1.18
// +build !go1.18

package gflag

// alias of interface{}, use for go < 1.18
type any = interface{}

0 comments on commit 0b253e2

Please sign in to comment.