更适合工程实践的版本
项目文件结构组织的最佳实践
适合工程实践的 tiny 示例
在 上一个示例 中展示了从头开始创建基于 cmdr 的 CLI App 的方法。
为了向你阐释 cmdr 提供的编程接口的用法,所以这个例子中遵循逐步推进的原则依次列举了每一个步骤,包括建立 cmdr 的 cli.App 对象,向其添加子命令以及选项,最后运行这个 cli.App 对象。
但实际上还可以使用 Create() 将其进一步简化和正规化。
不仅如此,Create() 返回的 Buidler 支持这样的方式:你可以提供一组分立的子命令,然后通过 Builder 的 WithAdders(...) 接口将它们添加到 app.RootCommand 中。
这种方式的好处是有利于工程管理。
Tip
下面的示例所展示的代码组织方式是被推荐的。
package main
import (
"context"
"os"
"github.com/hedzr/cmdr/v2"
"github.com/hedzr/cmdr/v2/examples/cmd"
"github.com/hedzr/cmdr/v2/pkg/logz"
)
const (
appName = "concise"
desc = `concise version of tiny app.`
version = cmdr.Version
author = `The Example Authors`
)
func main() {
app := cmdr.Create(appName, version, author, desc).
WithAdders(cmd.Commands...).
Build()
ctx := context.Background()
if err := app.Run(ctx); err != nil {
logz.ErrorContext(ctx, "Application Error:", "err", err) // stacktrace if in debug mode/build
os.Exit(app.SuggestRetCode())
} else if rc := app.SuggestRetCode(); rc != 0 {
os.Exit(rc)
}
}package cmd
import (
"github.com/hedzr/cmdr/v2/cli"
)
var Commands = []cli.CmdAdder{
jumpCmd{},
// wrongCmd{},
}package cmd
import (
"context"
"github.com/hedzr/cmdr/v2"
"github.com/hedzr/cmdr/v2/cli"
"github.com/hedzr/cmdr/v2/examples/dyncmd"
"github.com/hedzr/cmdr/v2/pkg/dir"
logz "github.com/hedzr/logg/slog"
)
type jumpCmd struct{}
func (jumpCmd) Add(app cli.App) {
app.Cmd("jump").
Description("jump command").
Examples(`jump example`). // {{.AppName}}, {{.AppVersion}}, {{.DadCommands}}, {{.Commands}}, ...
Deprecated(`v1.1.0`).
Group("Test").
// Group(cli.UnsortedGroup).
// Hidden(false).
OnEvaluateSubCommands(dyncmd.OnEvalJumpSubCommands).
// Both With(cb) and Build() to end a building sequence
With(func(b cli.CommandBuilder) {
b.Cmd("to").
Description("to command").
Examples(``).
Deprecated(`v0.1.1`).
OnAction(func(ctx context.Context, cmd cli.Cmd, args []string) (err error) {
// cmd.Set() == cmdr.Set(), cmd.Store() == cmdr.Store(cmd.GetDottedPath())
_, _ = cmd.Set().Set("tiny3.working", dir.GetCurrentDir())
println()
println("dir:", cmd.Set().WithPrefix("tiny3").MustString("working"))
cs := cmd.Set().WithPrefix(cli.CommandsStoreKey, "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").
Build()
})
})
}all.go
jump.go
main.go
在 cmd/ 子包中,你可以分别为每一个命令进行定义。
这些命令被收集在 cmd/all.go 中,然后被 Create(...).WithAdders(cmd.Commands...) 所引用。
这样的好处是组织结构更合理。
但它并不会节省每一条命令的定义代码的用量。
管理配置,和加载外部配置源
接下来的两节将会予以介绍。
提前的介绍是,使用 loaders.Create 替代 cmdr.Create 就能获得集成的外部源加载能力。
What is Next?
How is this guide?
最后更新于