diff --git a/app.go b/app.go index ddbcecc..15d85e9 100644 --- a/app.go +++ b/app.go @@ -120,9 +120,9 @@ func (app *App) bindingGlobalOpts() { bindingCommonGOpts(gf) // add more ... gf.BoolOpt(&gOpts.showVer, "version", "V", false, "Display app version information") - // This is a internal command + // This is a internal option gf.BoolVar(&gOpts.inCompletion, FlagMeta{ - Name: "cmd-completion", + Name: "cmd-completion", // TODO rename to --in-completion Desc: "generate completion scripts for bash/zsh", // hidden it Hidden: true, @@ -140,6 +140,8 @@ func (app *App) initialize() { return } + Logf(VerbCrazy, "initialize the application") + // init some help tpl vars app.core.AddVars(app.core.innerHelpVars()) @@ -226,11 +228,6 @@ func (app *App) addAliases(command string, aliases []string, sync bool) { } } -// Match command by path. eg. ["top", "sub"] -// func (app *App) Match(names []string) *Command { -// return app.commandBase.match(names) -// } - // On add hook handler for a hook event // func (app *App) BeforeInit(name string, handler HookFunc) {} @@ -268,7 +265,7 @@ func (app *App) parseGlobalOpts(args []string) (ok bool) { color.Enable = false } - Debugf("global option parsed, verbose level is %d", gOpts.verbose) + Debugf("global option parsed, verbose level: %d(%s)", gOpts.verbose, gOpts.verbose.String()) app.args = app.GlobalFlags().FSetArgs() // TODO show auto-completion for bash/zsh @@ -507,7 +504,8 @@ func (app *App) fireEvent(event string, data interface{}) { // AppHelpTemplate help template for app(all commands) var AppHelpTemplate = `{{.Desc}} (Version: {{.Version}}) Usage: - {$binName} [Global Options...] {command} [--option ...] [argument ...] + {$binName} [global Options...] COMMAND [--option ...] [argument ...] + {$binName} [global Options...] COMMAND [--option ...] SUB-COMMAND [--option ...] [argument ...] Global Options: {{.GOpts}} diff --git a/define.go b/define.go index 33f3559..dedf7e7 100644 --- a/define.go +++ b/define.go @@ -3,12 +3,52 @@ package gcli import ( "fmt" "strconv" + "strings" ) -// constants for error level 0 - 5 +type verbLevel uint + +// Upper verbose level to string. +func (vl verbLevel) Upper() string { + return strings.ToUpper(vl.String()) +} + +// String verbose level to string. +func (vl verbLevel) String() string { + switch vl { + case VerbQuiet: + return "quiet" + case VerbError: + return "error" + case VerbWarn: + return "warn" + case VerbInfo: + return "info" + case VerbDebug: + return "debug" + case VerbCrazy: + return "crazy" + } + return "unknown" +} + +// Set value from option binding. +func (vl *verbLevel) Set(value string) error { + iv, err := strconv.Atoi(value) + if err == nil { // level value. + *vl = verbLevel(iv) + return nil + } + + // level name. + *vl = name2verbLevel(value) + return nil +} + +// constants for error level (quiet 0 - 5 crazy) const ( - VerbQuiet uint = iota // don't report anything - VerbError // reporting on error + VerbQuiet verbLevel = iota // don't report anything + VerbError // reporting on error, default level. VerbWarn VerbInfo VerbDebug @@ -35,7 +75,7 @@ const maxFunc = 64 // GlobalOpts global flags type GlobalOpts struct { - verbose uint // message report level + verbose verbLevel // message report level NoColor bool showVer bool showHelp bool diff --git a/gcli.go b/gcli.go index 9bc100f..03f3bc9 100644 --- a/gcli.go +++ b/gcli.go @@ -9,6 +9,7 @@ package gcli import ( + "os" "regexp" ) @@ -46,7 +47,8 @@ var ( // global options gOpts = &GlobalOpts{ strictMode: true, - verbose: VerbError, + // init error level. + verbose: VerbError, } // CLI create an default instance @@ -64,6 +66,12 @@ func init() { // if envutil.IsWin() { // CLI.binName = strings.Replace(CLI.binName, workDir+"\\", "", 1) // } + + // set verbose from ENV var. + envVerb := os.Getenv("GCLI_VERBOSE") + if envVerb != "" { + gOpts.verbose = name2verbLevel(envVerb) + } } // InitStdApp create the default cli app. @@ -78,13 +86,13 @@ func StdApp() *App { } // GOpts get the global options -func GOpts() *GlobalOpts { - return gOpts +func GOpts() GlobalOpts { + return *gOpts } // Verbose returns verbose level -func Verbose() uint { - return gOpts.verbose +func VerboseName() string { + return gOpts.verbose.String() } // SetDebugMode level @@ -98,7 +106,7 @@ func SetQuietMode() { } // SetVerbose level -func SetVerbose(verbose uint) { +func SetVerbose(verbose verbLevel) { gOpts.verbose = verbose } @@ -114,7 +122,10 @@ func SetStrictMode(strict bool) { func bindingCommonGOpts(fs *Flags) { // binding global options - fs.UintOpt(&gOpts.verbose, "verbose", "", gOpts.verbose, "Set error reporting level(quiet 0 - 5 crazy)") + // fs.UintOpt(&gOpts.verbose, "verbose", "", gOpts.verbose, "Set error reporting level(quiet 0 - 5 crazy)") + // up: allow use int and string. + fs.VarOpt(&gOpts.verbose, "verbose", "", "Set error reporting level(quiet 0 - 5 crazy)") + fs.BoolOpt(&gOpts.showHelp, "help", "h", false, "Display the help information") fs.BoolOpt(&gOpts.NoColor, "no-color", "", gOpts.NoColor, "Disable color when outputting message") fs.BoolOpt(&gOpts.noProgress, "no-progress", "", gOpts.noProgress, "Disable display progress message") diff --git a/go.mod b/go.mod index d44e8f3..ad6ddcd 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/fsnotify/fsnotify v1.4.9 github.com/gookit/color v1.3.7 github.com/gookit/goutil v0.3.7 - github.com/stretchr/testify v1.6.1 + github.com/stretchr/testify v1.7.0 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect diff --git a/internal/help_tpl.go b/internal/help_tpl.go index 5bf0569..70c79c2 100644 --- a/internal/help_tpl.go +++ b/internal/help_tpl.go @@ -1 +1,3 @@ package internal + +// var AppHelp \ No newline at end of file diff --git a/util.go b/util.go index 45d5b53..c8af066 100644 --- a/util.go +++ b/util.go @@ -14,7 +14,7 @@ import ( * console log *************************************************************/ -var level2name = map[uint]string{ +var level2name = map[verbLevel]string{ VerbError: "ERROR", VerbWarn: "WARN", VerbInfo: "INFO", @@ -22,7 +22,7 @@ var level2name = map[uint]string{ VerbCrazy: "CRAZY", } -var level2color = map[uint]color.Color{ +var level2color = map[verbLevel]color.Color{ VerbError: color.FgRed, VerbWarn: color.FgYellow, VerbInfo: color.FgGreen, @@ -36,22 +36,17 @@ func Debugf(format string, v ...interface{}) { } // Logf print log message -func Logf(level uint, format string, v ...interface{}) { +func Logf(level verbLevel, format string, v ...interface{}) { logf(level, format, v...) } // print log message -func logf(level uint, format string, v ...interface{}) { +func logf(level verbLevel, format string, v ...interface{}) { if gOpts.verbose < level { return } var fnName string - name, has := level2name[level] - if !has { - name, level = "CRAZY", VerbCrazy - } - pc, fName, line, ok := runtime.Caller(2) if !ok { fnName, fName, line = "UNKNOWN", "???.go", 0 @@ -60,6 +55,7 @@ func logf(level uint, format string, v ...interface{}) { fnName = runtime.FuncForPC(pc).Name() } + name := level.Upper() name = level2color[level].Render(name) color.Printf("GCli: [%s] [%s(), %s:%d] %s\n", name, fnName, fName, line, fmt.Sprintf(format, v...)) } @@ -73,6 +69,26 @@ func defaultErrHandler(data ...interface{}) { } } +func name2verbLevel(name string) verbLevel { + switch strings.ToLower(name) { + case "quiet": + return VerbQuiet + case "error": + return VerbError + case "warn": + return VerbWarn + case "info": + return VerbInfo + case "debug": + return VerbDebug + case "crazy": + return VerbCrazy + } + + // default level + return VerbError +} + /************************************************************* * some helper methods *************************************************************/