Skip to content

Commit

Permalink
refactor: refact the app and cmd event handle logic
Browse files Browse the repository at this point in the history
  • Loading branch information
inhere committed Sep 4, 2022
1 parent 3d6cf1f commit 7206e9c
Show file tree
Hide file tree
Showing 9 changed files with 234 additions and 124 deletions.
6 changes: 4 additions & 2 deletions _examples/cliapp/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/gookit/gcli/v3"
"github.com/gookit/gcli/v3/_examples/cmd"
"github.com/gookit/gcli/v3/builtin"
"github.com/gookit/slog"
// "github.com/gookit/gcli/v3/builtin/filewatcher"
// "github.com/gookit/gcli/v3/builtin/reverseproxy"
)
Expand All @@ -16,14 +17,15 @@ import (
//
// run on windows(cmd, powerShell):
//
// go run ./_examples/cliapp
// go build ./_examples/cliapp && ./cliapp
func main() {
app := gcli.NewApp(func(app *gcli.App) {
app.Version = "3.0.0"
app.Desc = "this is my cli application"
app.On(gcli.EvtAppInit, func(data ...any) bool {
app.On(gcli.EvtAppInit, func(ctx *gcli.HookCtx) bool {
// do something...
// fmt.Println("init app")
slog.Println("init app event", ctx.Name())
return false
})

Expand Down
65 changes: 46 additions & 19 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"text/template"

"github.com/gookit/color"
"github.com/gookit/gcli/v3/events"
"github.com/gookit/gcli/v3/helper"
"github.com/gookit/goutil/cliutil"
"github.com/gookit/goutil/strutil"
Expand All @@ -16,6 +17,12 @@ import (
* CLI application
*************************************************************/

// Commander interface
type Commander interface {
Value(string) (any, bool)
SetValue(string, any)
}

// Handler interface definition
type Handler interface {
// Creator for create new command
Expand All @@ -32,6 +39,12 @@ type Logo struct {
Style string // eg "info"
}

// AppConfig struct
type AppConfig struct {
RunBefore func() bool
RunAfter func() bool
}

// App the cli app definition
type App struct {
// internal use
Expand Down Expand Up @@ -80,13 +93,13 @@ func New(fns ...func(app *App)) *App {
// // Or with a config func
// NewApp(func(a *App) {
// // do something before init ....
// a.Hooks[gcli.EvtInit] = func () {}
// a.Hooks[gcli.events.OnInit] = func () {}
// })
func NewApp(fns ...func(app *App)) *App {
app := &App{
Name: "GCliApp",
Desc: "This is my console application",
// set a default version
// set a default version.
// Version: "1.0.0",
// config
// ExitOnEnd: true,
Expand Down Expand Up @@ -128,7 +141,8 @@ func NotExitOnEnd() func(*App) {
}

// Config the application.
// Notice: must be called before adding a command
//
// Notice: must be called before add command
func (app *App) Config(fn func(a *App)) {
if fn != nil {
fn(app)
Expand Down Expand Up @@ -179,11 +193,11 @@ func (app *App) initialize() {
app.bindingGlobalOpts()

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

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

Expand Down Expand Up @@ -220,7 +234,7 @@ func (app *App) AddCommand(c *Command) {
app.hasSubcommands = true
}

app.Fire(EvtCmdInit, c)
app.fireWithCmd(events.OnCmdInit, c, nil)
}

// AddHandler to the application
Expand Down Expand Up @@ -276,7 +290,10 @@ func (app *App) parseGlobalOpts(args []string) (ok bool) {
}

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

// check global options
if gOpts.showHelp {
Expand Down Expand Up @@ -336,12 +353,13 @@ func (app *App) prepareRun() (code int, name string) {
// name is not empty, but is not command.
if app.inputName == "" {
Logf(VerbDebug, "input the command is not an registered: %s", name)
hookData := map[string]any{"name": name}

// fire events
if stop := app.Fire(EvtAppCmdNotFound, name); stop {
if stop := app.Fire(events.OnAppCmdNotFound, hookData); stop {
return
}
if stop := app.Fire(EvtCmdNotFound, name); stop {
if stop := app.Fire(events.OnCmdNotFound, hookData); stop {
return
}

Expand Down Expand Up @@ -463,7 +481,7 @@ func (app *App) Run(args []string) (code int) {
}

// trigger event
app.Fire(EvtAppPrepareAfter, name)
app.Fire(events.OnAppPrepareAfter, map[string]any{"name": name})

// do run input command
code = app.doRunCmd(name, app.args)
Expand All @@ -486,16 +504,16 @@ func (app *App) RunCmd(name string, args []string) int {

func (app *App) doRunCmd(name string, args []string) (code int) {
cmd := app.GetCommand(name)
app.Fire(EvtAppRunBefore, cmd)

app.fireWithCmd(events.OnAppRunBefore, cmd, map[string]any{"args": args})
Debugf("will run app command '%s' with args: %v", name, args)

// do execute command
if err := cmd.innerDispatch(args); err != nil {
code = ERR
app.Fire(EvtAppRunError, err)
app.Fire(events.OnAppRunError, map[string]any{"err": err})
} else {
app.Fire(EvtAppRunAfter, nil)
app.Fire(events.OnAppRunAfter, nil)
}
return
}
Expand All @@ -507,9 +525,9 @@ func (app *App) doRunFunc(args []string) (code int) {
// do execute command
if err := app.Func(app, args); err != nil {
code = ERR
app.Fire(EvtAppRunError, err)
app.Fire(events.OnAppRunError, map[string]any{"err": err})
} else {
app.Fire(EvtAppRunAfter, nil)
app.Fire(events.OnAppRunAfter, nil)
}
return
}
Expand Down Expand Up @@ -596,11 +614,20 @@ func (app *App) On(name string, handler HookFunc) {
app.core.On(name, handler)
}

// Fire hook on the app
func (app *App) Fire(event string, data any) bool {
// fire hook on the app. returns False for stop continue run.
func (app *App) fireWithCmd(event string, cmd *Command, data map[string]any) bool {
Debugf("trigger the application event: <green>%s</>", event)

ctx := newHookCtx(event, cmd, data).WithApp(app)
return app.core.Fire(event, ctx)
}

// Fire hook on the app. returns False for stop continue run.
func (app *App) Fire(event string, data map[string]any) bool {
Debugf("trigger the application event: <green>%s</>", event)

return app.core.Fire(event, app, data)
ctx := newHookCtx(event, nil, data).WithApp(app)
return app.core.Fire(event, ctx)
}

/*************************************************************
Expand Down
76 changes: 0 additions & 76 deletions base.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,82 +130,6 @@ func (md *mapData) ClearData() {
md.data = nil
}

/*************************************************************
* simple events manage
*************************************************************/

// HookFunc definition.
//
// func arguments:
//
// in app, like: func(app *App, data ...any)
// in cmd, like: func(cmd *Command, data ...any)
//
// type HookFunc func(obj any, data any)
//
// return:
// - True go on handle. default is True
// - False stop goon handle.
type HookFunc func(data ...any) (stop bool)

// HookCtx struct
type HookCtx struct {
mapData
App *App
Cmd *Command

name string
data map[string]any
}

// Name of event
func (hc *HookCtx) Name() string {
return hc.name
}

// Hooks struct. hookManager
type Hooks struct {
// Hooks can set some hooks func on running.
hooks map[string]HookFunc
}

// On register event hook by name
func (h *Hooks) On(name string, handler HookFunc) {
if handler != nil {
if h.hooks == nil {
h.hooks = make(map[string]HookFunc)
}

h.hooks[name] = handler
}
}

// AddOn register on not exists hook.
func (h *Hooks) AddOn(name string, handler HookFunc) {
if _, ok := h.hooks[name]; !ok {
h.On(name, handler)
}
}

// Fire event by name, allow with event data
func (h *Hooks) Fire(event string, data ...any) (stop bool) {
if handler, ok := h.hooks[event]; ok {
return handler(data...)
}
return false
}

// HasHook register
func (h *Hooks) HasHook(event string) bool {
_, ok := h.hooks[event]
return ok
}

// ClearHooks clear hooks data
func (h *Hooks) ClearHooks() {
h.hooks = nil
}

/*************************************************************
* Command Line: command data
*************************************************************/
Expand Down
30 changes: 16 additions & 14 deletions cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"text/template"

"github.com/gookit/color"
"github.com/gookit/gcli/v3/events"
"github.com/gookit/gcli/v3/helper"
"github.com/gookit/goutil/structs"
"github.com/gookit/goutil/strutil"
Expand Down Expand Up @@ -119,6 +120,7 @@ type Command struct {
}

// NewCommand create a new command instance.
//
// Usage:
//
// cmd := NewCommand("my-cmd", "description")
Expand Down Expand Up @@ -289,7 +291,7 @@ func (c *Command) initialize() {
c.Config(c)
}

c.Fire(EvtCmdInit, nil)
c.Fire(events.OnCmdInit, nil)
}

// init core
Expand Down Expand Up @@ -389,8 +391,8 @@ func (c *Command) Run(args []string) (err error) {
c.initialize()

// add default error handler.
if !c.HasHook(EvtCmdRunError) {
c.On(EvtCmdRunError, defaultErrHandler)
if !c.HasHook(events.OnCmdRunError) {
c.On(events.OnCmdRunError, defaultErrHandler)
}

// binding global options
Expand Down Expand Up @@ -432,10 +434,10 @@ func (c *Command) innerDispatch(args []string) (err error) {
return
}

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

c.Fire(EvtCmdOptParsed, args)
c.Fire(events.OnCmdOptParsed, map[string]any{"args": args})
Debugf("cmd: %s - remaining args on options parsed: %v", c.Name, args)

// find sub command
Expand All @@ -455,10 +457,10 @@ func (c *Command) innerDispatch(args []string) (err error) {
// is not a sub command and has no arguments -> error
if !c.HasArguments() {
// fire events
if stop := c.Fire(EvtCmdSubNotFound, name); stop {
if stop := c.Fire(events.OnCmdSubNotFound, map[string]any{"name": name}); stop {
return
}
if stop := c.Fire(EvtCmdNotFound, name); stop {
if stop := c.Fire(events.OnCmdNotFound, map[string]any{"name": name}); stop {
return
}

Expand Down Expand Up @@ -527,12 +529,12 @@ func (c *Command) doExecute(args []string) (err error) {
// collect and binding named argument
Debugf("cmd: %s - collect and binding named argument", c.Name)
if err := c.ParseArgs(args); err != nil {
c.Fire(EvtCmdRunError, err)
c.Fire(events.OnCmdRunError, map[string]any{"err": err})
Logf(VerbCrazy, "binding command '%s' arguments err: <red>%s</>", c.Name, err.Error())
return err
}

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

// do call command handler func
if c.Func == nil {
Expand All @@ -543,9 +545,9 @@ func (c *Command) doExecute(args []string) (err error) {
}

if err != nil {
c.Fire(EvtCmdRunError, err)
c.Fire(events.OnCmdRunError, map[string]any{"err": err})
} else {
c.Fire(EvtCmdRunAfter, nil)
c.Fire(events.OnCmdRunAfter, nil)
}
return
}
Expand Down Expand Up @@ -734,10 +736,10 @@ func (c *Command) goodName() string {
}

// Fire event handler by name
func (c *Command) Fire(event string, data any) (stop bool) {
func (c *Command) Fire(event string, data map[string]any) (stop bool) {
Debugf("cmd: %s - trigger the event: <mga>%s</>", c.Name, event)

return c.core.Fire(event, c, data)
return c.core.Fire(event, newHookCtx(event, c, data))
}

// On add hook handler for a hook event
Expand All @@ -755,7 +757,7 @@ func (c *Command) Copy() *Command {
nc := *c
// reset some fields
nc.Func = nil
nc.Hooks.ClearHooks() // TODO bug, will clear c.Hooks
nc.Hooks.ResetHooks() // TODO bug, will clear c.Hooks
// nc.Flags = flag.FlagSet{}

return &nc
Expand Down
Loading

0 comments on commit 7206e9c

Please sign in to comment.