diff --git a/app.go b/app.go index e292be2..3efe6ee 100644 --- a/app.go +++ b/app.go @@ -51,11 +51,7 @@ type AppConfig struct { // App the cli app definition type App struct { // internal use - // - *cmdLine - // - HelpVars - // - Hooks // allow hooks: "init", "before", "after", "error" - core - // for manager commands + // for manage commands commandBase AppConfig @@ -102,7 +98,7 @@ func New(fns ...func(app *App)) *App { // // Or with a config func // NewApp(func(a *App) { // // do something before init .... -// a.Hooks[gcli.events.OnInit] = func () {} +// a.Hooks[events.OnAppInit] = func () {} // }) func NewApp(fns ...func(app *App)) *App { app := &App{ @@ -123,18 +119,6 @@ func NewApp(fns ...func(app *App)) *App { opt.Alignment = AlignLeft }) - // internal core - Logf(VerbCrazy, "create new core on init application") - app.core = core{ - cmdLine: CLI, - // init - Hooks: &Hooks{}, - // gFlags: NewFlags("appOptions").WithConfigFn(func(opt *FlagsConfig) { - // opt.WithoutType = true - // opt.Alignment = AlignLeft - // }), - } - // init commandBase Logf(VerbCrazy, "create new commandBase on init application") // set a default version @@ -197,10 +181,10 @@ func (app *App) initialize() { Logf(VerbCrazy, "initialize the application") // init some vars - if app.core.Hooks == nil { - app.core.Hooks = &Hooks{} + if app.Hooks == nil { + app.Hooks = &Hooks{} } - app.core.AddVars(app.core.innerHelpVars()) + app.initHelpVars() // binding global options app.bindingGlobalOpts() @@ -637,7 +621,7 @@ func (app *App) SetDefaultCommand(name string) { func (app *App) On(name string, handler HookFunc) { Debugf("register application hook: %s", name) - app.core.On(name, handler) + app.Hooks.On(name, handler) } // fire hook on the app. returns False for stop continue run. @@ -645,7 +629,7 @@ func (app *App) fireWithCmd(event string, cmd *Command, data map[string]any) boo Debugf("trigger the application event: %s", event) ctx := newHookCtx(event, cmd, data).WithApp(app) - return app.core.Fire(event, ctx) + return app.Hooks.Fire(event, ctx) } // Fire hook on the app. returns False for stop continue run. @@ -653,7 +637,7 @@ func (app *App) Fire(event string, data map[string]any) bool { Debugf("trigger the application event: %s", event) ctx := newHookCtx(event, nil, data).WithApp(app) - return app.core.Fire(event, ctx) + return app.Hooks.Fire(event, ctx) } /************************************************************* diff --git a/base.go b/base.go index 06dc5be..1c0c0f3 100644 --- a/base.go +++ b/base.go @@ -11,127 +11,10 @@ import ( "github.com/gookit/color" "github.com/gookit/gcli/v3/helper" - "github.com/gookit/goutil/cflag" "github.com/gookit/goutil/maputil" - "github.com/gookit/goutil/mathutil" "github.com/gookit/goutil/structs" - "github.com/gookit/goutil/strutil" ) -// core definition TODO rename to context ?? -type core struct { - color.SimplePrinter - *cmdLine - // Hooks manage. allowed hooks: "init", "before", "after", "error" - *Hooks - // HelpVars help template vars. - helper.HelpVars - // global options flag set - gFlags *Flags - // GOptsBinder you can be custom binding global options - GOptsBinder func(gf *Flags) -} - -// init core -// func (c core) init(cmdName string) { -// c.cmdLine = CLI -// -// c.AddVars(c.innerHelpVars()) -// c.AddVars(map[string]string{ -// "cmd": cmdName, -// // binName with command -// "binWithCmd": c.binName + " " + cmdName, -// // binFile with command -// "fullCmd": c.binFile + " " + cmdName, -// }) -// } - -// parse global options -func (c core) doParseGOpts(args []string) (err error) { - if c.gFlags == nil { // skip on nil - return - } - - err = c.gFlags.Parse(args) - - if err != nil { - if cflag.IsFlagHelpErr(err) { - return nil - } - Logf(VerbWarn, "parse global options err: %s", err.Error()) - } - return -} - -// GlobalFlags get the app GlobalFlags -func (c core) GlobalFlags() *Flags { - return c.gFlags -} - -// RawOsArgs get the raw os.Args -func (c core) RawOsArgs() []string { - return os.Args -} - -// common basic help vars -func (c core) innerHelpVars() map[string]string { - return map[string]string{ - "pid": CLI.PIDString(), - "workDir": CLI.workDir, - "binFile": CLI.binFile, - "binName": CLI.binName, - } -} - -// simple map[string]any struct -// TODO use structs.Data -type mapData struct { - data map[string]any -} - -// Data get all -func (md *mapData) Data() map[string]any { - return md.data -} - -// SetData set all data -func (md *mapData) SetData(data map[string]any) { - md.data = data -} - -// Value get from data -func (md *mapData) Value(key string) any { - return md.data[key] -} - -// GetVal get from data -func (md *mapData) GetVal(key string) any { - return md.data[key] -} - -// StrValue get from data -func (md *mapData) StrValue(key string) string { - return strutil.MustString(md.data[key]) -} - -// IntValue get from data -func (md *mapData) IntValue(key string) int { - return mathutil.MustInt(md.data[key]) -} - -// SetValue to data -func (md *mapData) SetValue(key string, val any) { - if md.data == nil { - md.data = make(map[string]any) - } - md.data[key] = val -} - -// ClearData all data -func (md *mapData) ClearData() { - md.data = nil -} - /************************************************************* * Command Line: command data *************************************************************/ @@ -140,8 +23,20 @@ func (md *mapData) ClearData() { type Context struct { maputil.Data context.Context - // some common info - PID int + // PID value + pid int + // OsName os name. + osName string + // WorkDir the CLI app work dir path. by `os.Getwd()` + workDir string + // BinFile bin script file, by `os.Args[0]`. eg "./path/to/cliapp" + binFile string + // BinDir bin script dir path. eg "./path/to" + binDir string + // BinName bin script filename. eg "cliapp" + binName string + // ArgLine os.Args to string, but no binName. + argLine string } // NewCtx instance @@ -157,25 +52,8 @@ func (ctx *Context) Value(key any) any { return ctx.Data.Get(key.(string)) } -// cmdLine store common data for CLI -type cmdLine struct { - // pid for current application - pid int - // os name. - osName string - // the CLI app work dir path. by `os.Getwd()` - workDir string - // bin script file, by `os.Args[0]`. eg "./path/to/cliapp" - binFile string - // bin script dir path. eg "./path/to" - binDir string - // bin script filename. eg "cliapp" - binName string - // os.Args to string, but no binName. - argLine string -} - -func newCmdLine() *cmdLine { +// Init some common info +func (ctx *Context) Init() { binFile := os.Args[0] workDir, _ := os.Getwd() @@ -184,68 +62,66 @@ func newCmdLine() *cmdLine { // binFile = strings.Replace(CLI.binName, workDir+"\\", "", 1) // } - return &cmdLine{ - pid: os.Getpid(), - // more info - osName: runtime.GOOS, - workDir: workDir, - binDir: filepath.Dir(binFile), - binFile: binFile, - binName: filepath.Base(binFile), - argLine: strings.Join(os.Args[1:], " "), - } + ctx.pid = os.Getpid() + // more info + ctx.osName = runtime.GOOS + ctx.workDir = workDir + ctx.binDir = filepath.Dir(binFile) + ctx.binFile = binFile + ctx.binName = filepath.Base(binFile) + ctx.argLine = strings.Join(os.Args[1:], " ") } // PID get pid -func (c *cmdLine) PID() int { - return c.pid +func (ctx *Context) PID() int { + return ctx.pid } // PIDString get pid as string -func (c *cmdLine) PIDString() string { - return strconv.Itoa(c.pid) +func (ctx *Context) PIDString() string { + return strconv.Itoa(ctx.pid) } // OsName is equals to `runtime.GOOS` -func (c *cmdLine) OsName() string { - return c.osName +func (ctx *Context) OsName() string { + return ctx.osName } // OsArgs is equals to `os.Args` -func (c *cmdLine) OsArgs() []string { +func (ctx *Context) OsArgs() []string { return os.Args } // BinFile get bin script file -func (c *cmdLine) BinFile() string { - return c.binFile +func (ctx *Context) BinFile() string { + return ctx.binFile } // BinName get bin script name -func (c *cmdLine) BinName() string { - return c.binName +func (ctx *Context) BinName() string { + return ctx.binName } // BinDir get bin script dirname -func (c *cmdLine) BinDir() string { - return path.Dir(c.binFile) +func (ctx *Context) BinDir() string { + return path.Dir(ctx.binFile) } // WorkDir get work dirname -func (c *cmdLine) WorkDir() string { - return c.workDir +func (ctx *Context) WorkDir() string { + return ctx.workDir } // ArgLine os.Args to string, but no binName. -func (c *cmdLine) ArgLine() string { - return c.argLine +func (ctx *Context) ArgLine() string { + return ctx.argLine } -func (c *cmdLine) hasHelpKeywords() bool { - if c.argLine == "" { +func (ctx *Context) hasHelpKeywords() bool { + if ctx.argLine == "" { return false } - return strings.HasSuffix(c.argLine, " -h") || strings.HasSuffix(c.argLine, " --help") + return strings.HasSuffix(ctx.argLine, " -h") || strings.HasSuffix(ctx.argLine, " --help") } /************************************************************* @@ -254,7 +130,15 @@ func (c *cmdLine) hasHelpKeywords() bool { // will inject to every Command type commandBase struct { - mapData + // Hooks manage. allowed hooks: "init", "before", "after", "error" + *Hooks + *Context + color.SimplePrinter + // HelpVars help template vars. + helper.HelpVars + // TODO + helpData map[string]any + // Logo ASCII logo setting Logo *Logo // Version app version. like "1.0.1" @@ -287,7 +171,8 @@ type commandBase struct { func newCommandBase() commandBase { return commandBase{ - Logo: &Logo{Style: "info"}, + Hooks: &Hooks{}, + Logo: &Logo{Style: "info"}, // init mapping cmdNames: make(map[string]int), // name2idx: make(map[string]int), @@ -297,9 +182,20 @@ func newCommandBase() commandBase { // cmdAliases: make(maputil.Aliases), cmdAliases: structs.NewAliases(aliasNameCheck), // ExitOnEnd: false, + helpData: make(map[string]any), } } +// init common basic help vars +func (b *commandBase) initHelpVars() { + b.AddVars(map[string]string{ + "pid": b.PIDString(), + "workDir": b.workDir, + "binFile": b.binFile, + "binName": b.binName, + }) +} + // GetCommand get a command by name func (b *commandBase) GetCommand(name string) *Command { return b.commands[name] diff --git a/cmd.go b/cmd.go index d4a4d75..4f26427 100644 --- a/cmd.go +++ b/cmd.go @@ -45,13 +45,7 @@ func (c HandlersChain) Last() RunnerFunc { // Command a CLI command structure type Command struct { - // core is internal use - core - // cmdLine is internal use - // *cmdLine - // HelpVars - // // Hooks can allow setting some hooks func on running. - // Hooks // allowed hooks: "init", "before", "after", "error" + // internal use commandBase // --- provide option and argument parse and binding. @@ -299,14 +293,14 @@ func (c *Command) initialize() { func (c *Command) initCore(cName string) { Logf(VerbCrazy, "init command c.core for the command: %s", cName) - c.core.cmdLine = CLI - if c.core.Hooks == nil { - c.core.Hooks = &Hooks{} + // c.cmdLine = CLI + if c.Hooks == nil { + c.Hooks = &Hooks{} } binWithPath := c.binName + " " + c.Path() - c.AddVars(c.innerHelpVars()) + c.initHelpVars() c.AddVars(map[string]string{ "cmd": cName, // binName with command name @@ -673,9 +667,9 @@ func (c *Command) ShowHelp() { "Desc": c.HelpDesc(), } - if c.NotStandalone() { - vars["GOpts"] = c.GFlags().BuildHelp() - } + // if c.NotStandalone() { + // vars["GOpts"] = c.GFlags().BuildHelp() + // } // render help message str := helper.RenderText(CmdHelpTemplate, vars, template.FuncMap{ @@ -693,23 +687,6 @@ func (c *Command) ShowHelp() { * helper methods *************************************************************/ -// GFlags get global flags -func (c *Command) GFlags() *Flags { - // 如果先注册S子命令到一个命令A中,再将A注册到应用App。此时,S.gFlags 就是空的。 - // If you first register the S subcommand to a command A, then register A to the application App. - // At this time, S.gFlags is empty. - if c.gFlags == nil { - if c.parent == nil { - return nil - } - - // inherit from parent command. - c.core.gFlags = c.parent.GFlags() - } - - return c.gFlags -} - // IsStandalone running func (c *Command) IsStandalone() bool { return c.standalone @@ -740,7 +717,7 @@ func (c *Command) goodName() string { func (c *Command) Fire(event string, data map[string]any) (stop bool) { Debugf("cmd: %s - trigger the event: %s", c.Name, event) - return c.core.Fire(event, newHookCtx(event, c, data)) + return c.Hooks.Fire(event, newHookCtx(event, c, data)) } // On add hook handler for a hook event