hzDocs
hzDocs
文章 / 文档hedzr.com首页

cmdr series

介绍 cmdr

Guide

你的首个 CLI app更适合工程实践的版本
循序渐进
基本概念
命令命令:执行外部程序命令:预设参数命令:重定向命令:动态命令清单命令:在配置文件中定义别名清单命令:事件响应函数标志标志:必须项标志:可翻转组标志:枚举值标志:`Head -1` 风格标志:调用外部工具获得输入标志:自动否定标志:加号 `+` 前缀标志:事件响应函数解析结果内建命令和标志帮助子系统可共享共存的 app 实例辨析顶级函数WithOptsBackstage
如何……
Auto-close the ClosersRead config into structUsing is DetectorsUsing Store

References

What's New
Packages

Others

Examples
Blueprint
产品发布
产品发布之前
介绍 cmdr-cxx

Guide

cmdr supports

Intro

Guide

More features

References

Others

evendeep(-go)

Guide

Usagesdeepcopydeepdiffdeepequal
logg/slog(-go)

Guide

Guide

others

Components
trie-cxx

Guide

Guide

links

On Github

更适合工程实践的版本

项目文件结构组织的最佳实践

适合工程实践的 tiny 示例

在 上一个示例 中展示了从头开始创建基于 cmdr 的 CLI App 的方法。

为了向你阐释 cmdr 提供的编程接口的用法,所以这个例子中遵循逐步推进的原则依次列举了每一个步骤,包括建立 cmdr 的 cli.App 对象,向其添加子命令以及选项,最后运行这个 cli.App 对象。

但实际上还可以使用 Create() 将其进一步简化和正规化。

不仅如此,Create() 返回的 Buidler 支持这样的方式:你可以提供一组分立的子命令,然后通过 Builder 的 WithAdders(...) 接口将它们添加到 app.RootCommand 中。

这种方式的好处是有利于工程管理。

Tip

下面的示例所展示的代码组织方式是被推荐的。

./examples/tiny1/main.go
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)
	}
}
./examples/cmd/all.go
package cmd

import (
	"github.com/hedzr/cmdr/v2/cli"
)

var Commands = []cli.CmdAdder{
	jumpCmd{},
	// wrongCmd{},
}
./examples/cmd/all.go
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?

Components

Components

On Github

How is this guide?

最后更新于

目录

适合工程实践的 tiny 示例
管理配置,和加载外部配置源