Skip to content

Commit 41a4d39

Browse files
committed
wip: refactoring app and global options logic
1 parent 78e8fdf commit 41a4d39

File tree

19 files changed

+319
-166
lines changed

19 files changed

+319
-166
lines changed

.github/workflows/go.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
runs-on: ubuntu-latest
1919
strategy:
2020
matrix:
21-
go_version: [1.18, 1.19]
21+
go_version: [1.17, 1.18, 1.19]
2222

2323
steps:
2424
- name: Check out codes

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![Actions Status](https://github.com/gookit/gcli/workflows/action-tests/badge.svg)](https://github.com/gookit/gcli/actions)
55
[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/gookit/gcli)](https://github.com/gookit/gcli)
66
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/4f071e6858fb4117b6c1376c9316d8ef)](https://www.codacy.com/gh/gookit/gcli/dashboard?utm_source=github.com&utm_medium=referral&utm_content=gookit/gcli&utm_campaign=Badge_Grade)
7-
[![GoDoc](https://godoc.org/github.com/gookit/gcli?status.svg)](https://pkg.go.dev/github.com/gookit/gcli/v3)
7+
[![Go Reference](https://pkg.go.dev/badge/github.com/gookit/goutil.svg)](https://pkg.go.dev/github.com/gookit/goutil)
88
[![Go Report Card](https://goreportcard.com/badge/github.com/gookit/gcli)](https://goreportcard.com/report/github.com/gookit/gcli)
99
[![Coverage Status](https://coveralls.io/repos/github/gookit/gcli/badge.svg?branch=master)](https://coveralls.io/github/gookit/gcli?branch=master)
1010

README.zh-CN.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![Actions Status](https://github.com/gookit/gcli/workflows/action-tests/badge.svg)](https://github.com/gookit/gcli/actions)
55
[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/gookit/gcli)](https://github.com/gookit/gcli)
66
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/4f071e6858fb4117b6c1376c9316d8ef)](https://www.codacy.com/gh/gookit/gcli/dashboard?utm_source=github.com&utm_medium=referral&utm_content=gookit/gcli&utm_campaign=Badge_Grade)
7-
[![GoDoc](https://godoc.org/github.com/gookit/gcli?status.svg)](https://pkg.go.dev/github.com/gookit/gcli/v3)
7+
[![Go Reference](https://pkg.go.dev/badge/github.com/gookit/goutil.svg)](https://pkg.go.dev/github.com/gookit/goutil)
88
[![Go Report Card](https://goreportcard.com/badge/github.com/gookit/gcli)](https://goreportcard.com/report/github.com/gookit/gcli)
99
[![Coverage Status](https://coveralls.io/repos/github/gookit/gcli/badge.svg?branch=master)](https://coveralls.io/github/gookit/gcli?branch=master)
1010

_examples/cliapp/main.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
// "github.com/gookit/gcli/v3/builtin/reverseproxy"
1111
)
1212

13+
var customGOpt string
14+
1315
// local run:
1416
//
1517
// go run ./_examples/cliapp
@@ -42,10 +44,8 @@ func main() {
4244
// disable global options
4345
// gcli.GOpts().SetDisable()
4446

45-
var customGOpt string
46-
app.GOptsBinder = func(gf *gcli.Flags) {
47-
// gcli.Logf(gcli.VerbInfo, "custom add and global option flag")
48-
gf.StrVar(&customGOpt, &gcli.FlagMeta{Name: "custom", Desc: "desc message for the option"})
47+
app.BeforeAddOpts = func(opts *gcli.Flags) {
48+
opts.StrVar(&customGOpt, &gcli.FlagMeta{Name: "custom", Desc: "desc message for the option"})
4949
}
5050

5151
// app.Strict = true

any.go

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//go:build !go1.18
2+
// +build !go1.18
3+
4+
package gcli
5+
6+
// alias of interface{}, use for go < 1.18
7+
type any = interface{}

app.go

+53-27
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/gookit/color"
1010
"github.com/gookit/gcli/v3/events"
1111
"github.com/gookit/gcli/v3/helper"
12+
"github.com/gookit/goutil/cflag"
1213
"github.com/gookit/goutil/cliutil"
1314
"github.com/gookit/goutil/strutil"
1415
)
@@ -41,8 +42,10 @@ type Logo struct {
4142

4243
// AppConfig struct
4344
type AppConfig struct {
44-
RunBefore func() bool
45-
RunAfter func() bool
45+
BeforeRun func() bool
46+
AfterRun func() bool
47+
BeforeAddOpts func(opts *Flags)
48+
AfterBindOpts func(app *App) bool
4649
}
4750

4851
// App the cli app definition
@@ -55,6 +58,12 @@ type App struct {
5558
// for manager commands
5659
commandBase
5760

61+
AppConfig
62+
63+
fs *Flags
64+
// app flag options
65+
opts *GlobalOpts
66+
5867
// Name app name
5968
Name string
6069
// Desc app description
@@ -99,6 +108,7 @@ func NewApp(fns ...func(app *App)) *App {
99108
app := &App{
100109
Name: "GCliApp",
101110
Desc: "This is my console application",
111+
opts: newDefaultGlobalOpts(),
102112
// set a default version.
103113
// Version: "1.0.0",
104114
// config
@@ -108,16 +118,21 @@ func NewApp(fns ...func(app *App)) *App {
108118
commandBase: newCommandBase(),
109119
}
110120

121+
app.fs = NewFlags("appOptions").WithConfigFn(func(opt *FlagsConfig) {
122+
opt.WithoutType = true
123+
opt.Alignment = AlignLeft
124+
})
125+
111126
// internal core
112127
Logf(VerbCrazy, "create new core on init application")
113128
app.core = core{
114129
cmdLine: CLI,
115130
// init
116131
Hooks: &Hooks{},
117-
gFlags: NewFlags("app.GOptions").WithConfigFn(func(opt *FlagsConfig) {
118-
opt.WithoutType = true
119-
opt.Alignment = AlignLeft
120-
}),
132+
// gFlags: NewFlags("appOptions").WithConfigFn(func(opt *FlagsConfig) {
133+
// opt.WithoutType = true
134+
// opt.Alignment = AlignLeft
135+
// }),
121136
}
122137

123138
// init commandBase
@@ -153,25 +168,23 @@ func (app *App) Config(fn func(a *App)) {
153168
func (app *App) bindingGlobalOpts() {
154169
Logf(VerbDebug, "will begin binding global options")
155170
// global options flag
156-
// gf := flag.NewFlagSet(app.Args[0], flag.ContinueOnError)
157-
gf := app.GlobalFlags()
171+
fs := app.fs
158172

159173
// binding global options
160-
// bindingCommonGOpts(gf)
161-
gOpts.bindingFlags(gf)
174+
app.opts.bindingFlags(fs)
162175
// add more ...
163-
gf.BoolOpt(&gOpts.showVer, "version", "V", false, "Display app version information")
176+
fs.BoolOpt(&gOpts.ShowVersion, "version", "V", false, "Display app version information")
164177
// This is a internal option
165-
gf.BoolVar(&gOpts.inCompletion, &FlagMeta{
178+
fs.BoolVar(&gOpts.inCompletion, &FlagMeta{
166179
Name: "in-completion",
167180
Desc: "generate completion scripts for bash/zsh",
168181
// hidden it
169182
Hidden: true,
170183
})
171184

172185
// support binding custom global options
173-
if app.GOptsBinder != nil {
174-
app.GOptsBinder(gf)
186+
if app.BeforeAddOpts != nil {
187+
app.BeforeAddOpts(fs)
175188
}
176189
}
177190

@@ -225,7 +238,7 @@ func (app *App) AddCommand(c *Command) {
225238
// init command
226239
c.app = app
227240
// inherit global flags from application
228-
c.core.gFlags = app.gFlags
241+
// c.core.gFlags = app.gFlags
229242

230243
// do add command
231244
app.commandBase.addCommand(app.Name, c)
@@ -275,46 +288,59 @@ func (app *App) AddAliases(name string, aliases ...string) {
275288
// }
276289

277290
/*************************************************************
278-
* run command
291+
* parse global options
279292
*************************************************************/
280293

281-
// parseGlobalOpts parse global options
282-
func (app *App) parseGlobalOpts(args []string) (ok bool) {
294+
// parseAppOpts parse global options
295+
func (app *App) doParseOpts(args []string) error {
296+
err := app.fs.Parse(args)
297+
if err != nil {
298+
if cflag.IsFlagHelpErr(err) {
299+
return nil
300+
}
301+
Logf(VerbWarn, "parse global options err: <red>%s</>", err.Error())
302+
}
303+
304+
return err
305+
}
306+
307+
// parseAppOpts parse global options
308+
func (app *App) parseAppOpts(args []string) (ok bool) {
283309
Logf(VerbDebug, "will begin parse application options")
284310

285311
// parse global options
286-
err := app.core.doParseGOpts(args)
312+
err := app.doParseOpts(args)
287313
if err != nil { // has error.
288314
color.Error.Tips(err.Error())
289315
return
290316
}
291317

292-
app.args = app.gFlags.FSetArgs()
318+
app.args = app.fs.FSetArgs()
293319
if app.Fire(events.OnGOptionsParsed, map[string]any{"args": app.args}) {
294320
Logf(VerbDebug, "stop continue on the event %s return True", events.OnGOptionsParsed)
295321
return
296322
}
297323

298324
// check global options
299-
if gOpts.showHelp {
325+
if app.opts.ShowHelp {
300326
app.showApplicationHelp()
301327
return
302328
}
303329

304-
if gOpts.showVer {
330+
if app.opts.ShowVersion {
305331
app.showVersionInfo()
306332
return
307333
}
308334

309335
// disable color
310-
if gOpts.NoColor {
336+
if app.opts.NoColor {
311337
color.Enable = false
312338
}
313339

314-
Debugf("global option parsed, verbose level: <mgb>%s</>", gOpts.verbose.String())
340+
Debugf("global option parsed, Verbose level: <mgb>%s</>", app.opts.Verbose.String())
315341

316342
// TODO show auto-completion for bash/zsh
317-
if gOpts.inCompletion {
343+
if app.opts.inCompletion {
318344
app.showAutoCompletion(app.args)
319345
return
320346
}
@@ -468,7 +494,7 @@ func (app *App) Run(args []string) (code int) {
468494
Debugf("will begin run cli application. args: %v", args)
469495

470496
// parse global flags
471-
if false == app.parseGlobalOpts(args) {
497+
if false == app.parseAppOpts(args) {
472498
return app.exitOnEnd(code)
473499
}
474500

@@ -684,7 +710,7 @@ func (app *App) showApplicationHelp() {
684710
// render help text template
685711
s := helper.RenderText(AppHelpTemplate, map[string]any{
686712
"Cs": app.commands,
687-
"GOpts": app.gFlags.String(),
713+
"GOpts": app.fs.String(),
688714
// app version
689715
"Version": app.Version,
690716
"HasSubs": app.hasSubcommands,

base.go

+24-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package gcli
22

33
import (
4+
"context"
45
"os"
56
"path"
67
"path/filepath"
@@ -11,6 +12,7 @@ import (
1112
"github.com/gookit/color"
1213
"github.com/gookit/gcli/v3/helper"
1314
"github.com/gookit/goutil/cflag"
15+
"github.com/gookit/goutil/maputil"
1416
"github.com/gookit/goutil/mathutil"
1517
"github.com/gookit/goutil/structs"
1618
"github.com/gookit/goutil/strutil"
@@ -134,6 +136,27 @@ func (md *mapData) ClearData() {
134136
* Command Line: command data
135137
*************************************************************/
136138

139+
// Context struct
140+
type Context struct {
141+
maputil.Data
142+
context.Context
143+
// some common info
144+
PID int
145+
}
146+
147+
// NewCtx instance
148+
func NewCtx() *Context {
149+
return &Context{
150+
Data: make(maputil.Data),
151+
Context: context.Background(),
152+
}
153+
}
154+
155+
// Value get by key
156+
func (ctx *Context) Value(key any) any {
157+
return ctx.Data.Get(key.(string))
158+
}
159+
137160
// cmdLine store common data for CLI
138161
type cmdLine struct {
139162
// pid for current application
@@ -273,7 +296,7 @@ func newCommandBase() commandBase {
273296
nameMaxWidth: 12,
274297
// cmdAliases: make(maputil.Aliases),
275298
cmdAliases: structs.NewAliases(aliasNameCheck),
276-
ExitOnEnd: true,
299+
// ExitOnEnd: false,
277300
}
278301
}
279302

typevars.go builtin/typevars.go

+1-63
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
package gcli
1+
package builtin
22

33
import (
44
"fmt"
55
"strconv"
6-
"strings"
76

87
"github.com/gookit/goutil/strutil"
98
)
@@ -134,64 +133,3 @@ func (s *String) Split(sep string) []string {
134133
func (s *String) Ints(sep string) []int {
135134
return strutil.Ints(string(*s), sep)
136135
}
137-
138-
/*************************************************************************
139-
* verbose level
140-
*************************************************************************/
141-
142-
// VerbLevel type.
143-
type VerbLevel uint
144-
145-
// Int verbose level to int.
146-
func (vl *VerbLevel) Int() int {
147-
return int(*vl)
148-
}
149-
150-
// String verbose level to string.
151-
func (vl *VerbLevel) String() string {
152-
return fmt.Sprintf("%d=%s", *vl, vl.Name())
153-
}
154-
155-
// Upper verbose level to string.
156-
func (vl *VerbLevel) Upper() string {
157-
return strings.ToUpper(vl.Name())
158-
}
159-
160-
// Name verbose level to string.
161-
func (vl *VerbLevel) Name() string {
162-
switch *vl {
163-
case VerbQuiet:
164-
return "quiet"
165-
case VerbError:
166-
return "error"
167-
case VerbWarn:
168-
return "warn"
169-
case VerbInfo:
170-
return "info"
171-
case VerbDebug:
172-
return "debug"
173-
case VerbCrazy:
174-
return "crazy"
175-
}
176-
return "unknown"
177-
}
178-
179-
// Set value from option binding.
180-
func (vl *VerbLevel) Set(value string) error {
181-
// int: level value.
182-
if iv, err := strconv.Atoi(value); err == nil {
183-
if iv > int(VerbCrazy) {
184-
*vl = VerbCrazy
185-
} else if iv < 0 { // fallback to default level.
186-
*vl = DefaultVerb
187-
} else { // 0 - 5
188-
*vl = VerbLevel(iv)
189-
}
190-
191-
return nil
192-
}
193-
194-
// string: level name.
195-
*vl = name2verbLevel(value)
196-
return nil
197-
}

0 commit comments

Comments
 (0)