hzDocs

命令:在配置文件中定义别名清单

loading alias commands from a config file

DynCommand From Config

cmdr 也允许你从配置树的特定位置载入数据并据此构造子命令。

实际上,这是可以自行实现的。尽管 cmdr 内置了一套类似于 git alias 的功能,但你完全可以重新实现自定义的机制。

实例:cmdr-tests/examples/concise

hedzr/cmdr-tests 的示例程序 dyncmd-cfg 在子命令 jump 上实现了动态加载外部脚本为子命令的功能。

这并不影响你按照常规方案为 jump 增加固定的子命令 to

./examples/dyncmd-cfg/main.go
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, cancel := context.WithCancel(context.Background())
	defer cancel()
 
	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)
	}
}

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

它们将会被在运行时动态载入为 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

这一行为导致更少的冲突可能性,但不影响帮助屏显示与命令匹配。

额外的话题

How is this guide?

Edit on GitHub

Last updated on

On this page