命令:在配置文件中定义别名清单
loading alias commands from a config file
Alias From Config
cmdr 也允许你从配置树的特定位置载入数据并据此构造子命令。
实际上,这是可以自行实现的。尽管 cmdr 内置了一套类似于 git alias 的功能,但你完全可以重新实现自定义的机制。
实例:cmdr-tests/examples/concise
hedzr/cmdr-tests 的示例程序 dyncmd-cfg 在子命令 jump 上实现了动态加载外部脚本为子命令的功能。
这并不影响你按照常规方案为 jump 增加固定的子命令 to:
package main
import (
"context"
"os"
loaders "github.com/hedzr/cmdr-loaders"
"github.com/hedzr/cmdr/v2"
"github.com/hedzr/cmdr/v2/cli"
"github.com/hedzr/cmdr/v2/examples/cmd"
"github.com/hedzr/cmdr/v2/examples/devmode"
"github.com/hedzr/cmdr/v2/pkg/logz"
)
const (
appName = "dyncmd-cfg"
desc = `dyncmd defined in config file`
version = cmdr.Version
author = `The Example Authors`
)
func main() {
ctx := context.Background()
app := loaders.Create(appName, version, author, desc).
With(func(app cli.App) { logz.Debug("in dev mode?", "mode", devmode.InDevelopmentMode()) }).
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).
OnEvaluateSubCommandsFromConfigPath().
// 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()
})
})
}OnEvaluateSubCommandsFromConfigPath() 将会从给定的 Store dottedPath 处载入别名清单。
如果省却了参数,它就会从 app.alias section 读取别名清单,对应于配置文件中的 [alias] 区块。这一特性基本等价于 git alias 方案。
在别名清单中,每个键值对对应于一条子命令。值字符串代表着要执行的 Action:
- 前缀
>代表着将要转发到另一个子命令 - 前缀
!代表着将要执行一个应用程序。"! say hello"等效于语音播报“hello”(仅限于 macOS);而"! bash -c " - 没有任何前缀,代表要执行一条 Shell 命令(例如 echo ok)
执行一个应用程序,意味着你可以启动一个 GUI app。此时将不会分配控制台。
执行一条 Shell 命令,隐含着分配控制台和在 Shell 中进行命令运行。
别名命令清单
cmdr-tests 在 ./ci/etc/dyncmd-cfg 中附加了标准结构的 etc 配置文件表,其中 [alias] 一节定义了别名命令清单。
[alias]
jc = "> jump to"
ls = "! bash -c \"ls -laG\""
l = "ls -laG"
say = "say hello"
# PREFIX MEANINGS:
# '>': leading a RedirectTo cmd, using space-sep'd or dot-sep'd path.
# for examples, "> jump.to" redirect ro 'juml/'to' command.
# '!': leading a program, for example: "say hello" in macOS will play voice 'hello'.
# mostly it's a gui program
# nothing: run a shell command. for example: "ls -la" will list file[logging]
file = "/var/lib/dyncmd-cfg.stdout.log"
rotate = 7 # in days[server]
port = 3000它们将会被在运行时动态载入为 jump 的子命令。
运行时
上面的示例程序的运行时效果如同这样:
$ go run ./examples/dyncmd-cfg jump
dyncmd-cfg v2.1.1 ~ Copyright © 2025 by The Example Authors ~ All Rights Reserved.
Usage:
$ dyncmd-cfg jump [Options...][files...]
Description:
jump command
Examples:
jump example
Commands:
to to command [Since: v0.1.1]
[Alias]
jc jump: [alias]/jc
ls jump: [alias]/ls
Global Flags:
[Misc]
-h, --help,--info,--usage Show this help screen (-?) [Env: HELP] (Default: false)
Type '-h'/'-?' or '--help' to get command help screen.
More: '-D'/'--debug', '-V'/'--version', '-#'/'--build-info', '--no-color'...
$ go run ./examples/tiny/concise jump jc
dir: /Volumes/VolHack/work/godev/cmdr.v2/cmdr.tests
exit status 1
$从帮助屏中可以看到定义在 ./ci/etc/dyncmd-cfg/dyncmd-cfg.toml 中 [alias] 段中的别名命令都被成功地加载了。
而运行 jump jc 将会重定向到新的子命令序列 jump to,
运行 jump ls 则会执行 shell 命令行序列 ls -laG。
实现方法
从基本面上讲,cmdr 内置的 OnEvaluateSubCommandsFromConfig("alias")
是在 pre 阶段的末尾进行配置树扫描,然后逐一构造子命令并添加到所属的父级命令之下。
OnEvaluateSubCommandsFromConfig().由于潜在的冲突的可能,所以 cmdr 为子命令定义一个 alias-XXX 的 Long Title,同时指定该子命令的 name 为 XXX。
这一行为导致更少的冲突可能性,但不影响帮助屏显示与命令匹配。
额外的话题
Howto run a subcmd directly from root
Command
Command: Invokes
Command: Preset Args
Command: Redirect To
Command: Dynamic Cmd
Command: Dynamic Cmd From Config
Command: Event Handlers
What is Next?
How is this guide?
最后更新于