-
-
Notifications
You must be signed in to change notification settings - Fork 9
/
main.go
204 lines (175 loc) · 5.88 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
package main
// normally tiny app
import (
"context"
"io"
"log"
"os"
"strings"
"sync"
"gopkg.in/hedzr/errors.v3"
"github.com/hedzr/cmdr/v2"
"github.com/hedzr/cmdr/v2/cli"
"github.com/hedzr/cmdr/v2/pkg/dir"
"github.com/hedzr/cmdr/v2/pkg/logz"
"github.com/hedzr/is"
logzorig "github.com/hedzr/logg/slog"
"github.com/hedzr/store"
)
func main() {
ctx := context.Background()
app := prepareApp(
cmdr.WithStore(store.New()), // use an option store explicitly, or a dummy store by default
// cmdr.WithExternalLoaders(
// local.NewConfigFileLoader(), // import "github.com/hedzr/cmdr-loaders/local" to get in advanced external loading features
// local.NewEnvVarLoader(),
// ),
cmdr.WithTasksBeforeRun(func(ctx context.Context, cmd cli.Cmd, runner cli.Runner, extras ...any) (err error) {
logz.DebugContext(ctx, "command running...", "cmd", cmd, "runner", runner, "extras", extras)
return
}), // cmdr.WithTasksBeforeParse(), cmdr.WithTasksBeforeRun(), cmdr.WithTasksAfterRun
// true for debug in developing time, it'll disable onAction on each Cmd.
// for productive mode, comment this line.
// The envvars FORCE_DEFAULT_ACTION & FORCE_RUN can override this.
cmdr.WithForceDefaultAction(true),
cmdr.WithSortInHelpScreen(true), // default it's false
cmdr.WithDontGroupInHelpScreen(false), // default it's false
cmdr.WithAutoEnvBindings(true),
)
// // simple run the parser of app and trigger the matched command's action
// _ = app.Run(
// cmdr.WithForceDefaultAction(false), // true for debug in developing time
// )
if err := app.Run(ctx); err != nil {
logz.ErrorContext(ctx, "Application Error:", "err", err) // stacktrace if in debug mode/build
os.Exit(app.SuggestRetCode())
}
}
func prepareApp(opts ...cli.Opt) (app cli.App) {
app = cmdr.New(opts...).
Info("tiny-app", "0.3.1").
Author("The Example Authors") // .Description(``).Header(``).Footer(``)
// another way to disable `cmdr.WithForceDefaultAction(true)` is using
// env-var FORCE_RUN=1 (builtin already).
app.Flg("no-default").
Description("disable force default action").
OnMatched(func(f *cli.Flag, position int, hitState *cli.MatchState) (err error) {
if b, ok := hitState.Value.(bool); ok {
f.Set().Set("app.force-default-action", b) // disable/enable the final state about 'force default action'
}
return
}).
Build()
app.Cmd("jump").
Description("jump command").
Examples(`jump example`). // {{.AppName}}, {{.AppVersion}}, {{.DadCommands}}, {{.Commands}}, ...
Deprecated(`v1.1.0`).
// Group(cli.UnsortedGroup).
Hidden(false, false).
OnEvaluateSubCommands(onEvalJumpSubCommands).
With(func(b cli.CommandBuilder) {
b.Cmd("to").
Description("to command").
Examples(``).
Deprecated(`v0.1.1`).
// Group(cli.UnsortedGroup).
Hidden(false).
OnAction(func(ctx context.Context, cmd cli.Cmd, args []string) (err error) {
// cmd.Set() == cmdr.Store(), cmd.Store() == cmdr.Store()
cmd.Set().Set("app.demo.working", dir.GetCurrentDir())
println()
println(cmd.Set().WithPrefix("app.demo").MustString("working"))
cs := cmdr.Store().WithPrefix("jump.to")
if cs.MustBool("full") {
println()
println(cmd.Set().Dump())
}
cs2 := cmd.Store()
if cs2.MustBool("full") != cs.MustBool("full") {
logz.Panic("a bug found")
}
app.SetSuggestRetCode(1) // ret code must be in 0-255
return // handling command action here
}).
With(func(b cli.CommandBuilder) {
b.Flg("full", "f").
Default(false).
Description("full command").
// Group(cli.UnsortedGroup).
Build()
})
})
app.Flg("dry-run", "n").
Default(false).
Description("run all but without committing").
Group(cli.UnsortedGroup).
Build()
app.Flg("wet-run", "w").
Default(false).
Description("run all but with committing").
Build() // no matter even if you're adding the duplicated one.
app.Cmd("wrong").
Description("a wrong command to return error for testing").
// cmdline `FORCE_RUN=1 go run ./tiny wrong -d 8s` to verify this command to see the returned application error.
OnAction(func(ctx context.Context, cmd cli.Cmd, args []string) (err error) {
dur := cmd.Store().MustDuration("duration")
println("the duration is:", dur.String())
ec := errors.New()
defer ec.Defer(&err) // store the collected errors in native err and return it
ec.Attach(io.ErrClosedPipe, errors.New("something's wrong"), os.ErrPermission)
// see the application error by running `go run ./tiny/tiny/main.go wrong`.
return
}).
With(func(b cli.CommandBuilder) {
b.Flg("duration", "d").
Default("5s").
Description("a duration var").
Build()
})
return
}
var onceDev sync.Once
var devMode bool
func init() {
// onceDev is a redundant operation, but we still keep it to
// fit for defensive programming style.
onceDev.Do(func() {
log.SetFlags(log.LstdFlags | log.Lmsgprefix | log.LUTC | log.Lshortfile | log.Lmicroseconds)
log.SetPrefix("")
if dir.FileExists(".dev-mode") {
devMode = true
} else if dir.FileExists("go.mod") {
data, err := os.ReadFile("go.mod")
if err != nil {
return
}
content := string(data)
// dev := true
if strings.Contains(content, "github.com/hedzr/cmdr/v2/pkg/") {
devMode = false
}
// I am tiny-app in cmdr/v2, I will be launched in dev-mode always
if strings.Contains(content, "module github.com/hedzr/cmdr/v2") {
devMode = true
}
}
if devMode {
is.SetDebugMode(true)
logz.SetLevel(logzorig.DebugLevel)
logz.Debug(".dev-mode file detected, entering Debug Mode...")
}
if is.DebugBuild() {
is.SetDebugMode(true)
logz.SetLevel(logzorig.DebugLevel)
}
if is.VerboseBuild() {
is.SetVerboseMode(true)
if logz.GetLevel() < logzorig.InfoLevel {
logz.SetLevel(logzorig.InfoLevel)
}
if logz.GetLevel() < logzorig.TraceLevel {
logz.SetLevel(logzorig.TraceLevel)
}
}
})
}