feat: 帮助信息中文化并把命令分组说明写直白

- 根命令增加简介与常用示例,分组标题由「disk 相关命令」改为用途说明
  (如「磁盘与文件占用:查看哪个目录、哪个文件最占空间」)
- cobra 固定文案改为中文:用法 / 可用的子命令 / 选项、[flags] → [选项]、
  help for xxx → 显示帮助;completion 与 help 也改为中文说明
- disk usage 摘要改为「看哪个目录或文件最占空间」
This commit is contained in:
2026-11-01 08:43:47 +08:00
parent 5d4631c053
commit e244c23b52
3 changed files with 197 additions and 12 deletions
+144 -11
View File
@@ -59,9 +59,18 @@ func (a *App) Execute(args []string) int {
// Root builds the full cobra command tree.
func (a *App) Root() *cobra.Command {
root := &cobra.Command{
Use: "kopsc",
Short: "跨平台命令助手:用统一的意图命令在各平台执行对应命令",
Long: "kopsc 用平台无关的意图命令(如 docker clearsafe),根据操作系统、发行版与已安装的运行时,选择并执行对应的底层命令。",
Use: "kopsc",
Short: "跨平台命令助手:用统一的意图命令在各平台执行对应命令",
Long: `kopsc 用平台无关的意图命令(如 docker clearsafe),根据操作系统、发行版与已安装的运行时,
自动选择并执行对应的底层命令。你只需记住要做什么,不必记住每个平台的写法。
常用示例:
kopsc docker clearsafe 安全清理未使用的容器、网络与悬空镜像
kopsc diagnose web 诊断容器或 Pod 为什么起不来(自动识别 Docker / K8s)
kopsc net ports 列出本机正在监听的端口
kopsc disk usage 看当前目录里谁最占空间
kopsc proc nohup ./server 后台运行并写日志(等价 nohup ./server > server.out 2>&1 &)
kopsc list 列出全部命令及在本平台实际会执行的命令`,
Version: a.Version,
SilenceUsage: true,
SilenceErrors: true,
@@ -72,15 +81,35 @@ func (a *App) Root() *cobra.Command {
root.SetOut(a.Stdout)
root.SetErr(a.Stderr)
root.SetIn(a.Stdin)
localizeCobra(root)
for i := range a.Registry.Commands {
a.addRegistryCommand(root, &a.Registry.Commands[i])
}
root.AddCommand(a.newListCmd(), a.newExplainCmd(), a.newPlatformCmd(), a.newVersionCmd())
localizeBuiltins(root)
localizeHelpFlags(root)
return root
}
// localizeBuiltins gives cobra's generated commands Chinese descriptions.
// cobra creates completion and help lazily, so they are initialised here
// explicitly and then renamed.
func localizeBuiltins(root *cobra.Command) {
root.InitDefaultCompletionCmd()
root.InitDefaultHelpCmd()
if cmd := findChild(root, "completion"); cmd != nil {
cmd.Short = "生成 shell 补全脚本(bash / zsh / fish / powershell)"
cmd.Long = "为 bash、zsh、fish 或 powershell 生成 kopsc 的命令补全脚本。"
}
if cmd := findChild(root, "help"); cmd != nil {
cmd.Short = "查看任意命令的帮助"
cmd.Long = "查看任意命令的帮助,例如 kopsc help disk,效果等同 kopsc disk --help。"
}
}
// addRegistryCommand turns "docker.clearsafe" into `kopsc docker clearsafe`,
// reusing intermediate commands for shared ID prefixes.
func (a *App) addRegistryCommand(root *cobra.Command, cmd *registry.Command) {
@@ -90,14 +119,7 @@ func (a *App) addRegistryCommand(root *cobra.Command, cmd *registry.Command) {
for _, group := range parts[:len(parts)-1] {
child := findChild(parent, group)
if child == nil {
groupName := group
child = &cobra.Command{
Use: groupName,
Short: groupName + " 相关命令",
RunE: func(c *cobra.Command, args []string) error {
return c.Help()
},
}
child = newGroup(group)
parent.AddCommand(child)
}
parent = child
@@ -107,6 +129,117 @@ func (a *App) addRegistryCommand(root *cobra.Command, cmd *registry.Command) {
parent.AddCommand(leaf)
}
// localizeCobra replaces cobra's built-in English strings with Chinese ones.
//
// cobra renders the text itself (its templates use cobra's own functions such
// as rpad), so kopsc swaps the templates for Chinese headings and pre-registers
// the help and version flags: cobra only generates its English descriptions
// ("help for kopsc") for flags it has not seen yet.
func localizeCobra(root *cobra.Command) {
cobra.AddTemplateFunc("kopscOptions", func(line string) string {
return strings.ReplaceAll(line, "[flags]", "[选项]")
})
root.Use = "kopsc"
root.SetUsageTemplate(usageTemplate)
root.SetHelpTemplate(helpTemplate)
root.InitDefaultHelpFlag()
root.InitDefaultVersionFlag()
root.Flags().Lookup("help").Usage = "显示帮助"
if flag := root.Flags().Lookup("version"); flag != nil {
flag.Usage = "显示版本"
}
}
// localizeHelpFlags pre-registers cobra's help flag on every command with a
// Chinese description. It must run after the command tree is complete, since
// cobra only generates the English default for commands it has not seen.
func localizeHelpFlags(root *cobra.Command) {
queue := []*cobra.Command{root}
for len(queue) > 0 {
c := queue[0]
queue = queue[1:]
c.InitDefaultHelpFlag()
if flag := c.Flags().Lookup("help"); flag != nil {
flag.Usage = "显示帮助"
}
queue = append(queue, c.Commands()...)
}
}
// usageTemplate is cobra's default usage layout with Chinese headings.
const usageTemplate = `用法:{{if .Runnable}}
{{.UseLine | kopscOptions}}{{end}}{{if .HasAvailableSubCommands}}
{{.CommandPath}} [命令]{{end}}{{if gt (len .Aliases) 0}}
别名:
{{.NameAndAliases}}{{end}}{{if .HasExample}}
示例:
{{.Example}}{{end}}{{if .HasAvailableSubCommands}}
可用的子命令:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
选项:
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
全局选项:
{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}
更多帮助:
{{.CommandPath}} [命令] --help{{end}}
`
// helpTemplate is cobra's default help layout.
const helpTemplate = `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces}}
{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
// helpTextReplacements rewrites the few English fragments cobra still emits.
var helpTextReplacements = []struct{ old, new string }{
{"[flags]", "[选项]"},
{"help for ", "查看 "},
{"Generate the autocompletion script for the specified shell", "生成 shell 补全脚本(bash / zsh / fish / powershell)"},
{"Help about any command", "查看任意命令的帮助"},
}
// translateHelp applies helpTextReplacements.
func translateHelp(text string) string {
for _, r := range helpTextReplacements {
text = strings.ReplaceAll(text, r.old, r.new)
}
return text
}
// groupDescriptions explains what each command group is for. Without them
// cobra would show "disk 相关命令", which tells a user nothing.
var groupDescriptions = map[string]string{
"docker": "Docker 容器与镜像管理(查看、启停、日志、清理、导出/导入、Compose)",
"disk": "磁盘与文件占用:查看哪个目录、哪个文件最占空间",
"net": "网络与端口:端口被谁占用、本机监听了哪些端口",
"pkg": "系统软件包:刷新包管理器(dnf/apt/apk/brew/winget)的软件源索引",
"proc": "本机进程:在后台运行命令并写日志,关掉终端也不退出",
}
// newGroup builds an intermediate command such as `kopsc disk`.
func newGroup(name string) *cobra.Command {
short, ok := groupDescriptions[name]
if !ok {
short = name + " 相关命令"
}
return &cobra.Command{
Use: name,
Short: short,
Long: short + "。\n\n运行 " + "kopsc " + name + " --help 查看该组的全部子命令。",
RunE: func(c *cobra.Command, args []string) error {
return c.Help()
},
}
}
func findChild(parent *cobra.Command, name string) *cobra.Command {
for _, child := range parent.Commands() {
if child.Name() == name {
+52
View File
@@ -748,3 +748,55 @@ func readCalls(path string) []string {
}
return out
}
func TestRootHelpIsChineseAndExplainsGroups(t *testing.T) {
app, stdout, stderr := testApp(centos("docker"))
if code := app.Execute(nil); code != 0 {
t.Fatalf("exit code = %d, stderr=%s", code, stderr.String())
}
out := stdout.String()
// The framing cobra would otherwise print in English.
for _, want := range []string{"用法:", "可用的子命令:", "选项:", "显示帮助"} {
if !strings.Contains(out, want) {
t.Errorf("root help missing %q:\n%s", want, out)
}
}
for _, unwanted := range []string{"Usage:", "Available Commands:", "Flags:", "help for ", "[flags]", "Help about any command"} {
if strings.Contains(out, unwanted) {
t.Errorf("root help still contains English %q:\n%s", unwanted, out)
}
}
// Every group is described in plain words instead of "<name> 相关命令".
for _, want := range []string{
"磁盘与文件占用",
"网络与端口",
"本机进程",
"系统软件包",
"Docker 容器与镜像管理",
} {
if !strings.Contains(out, want) {
t.Errorf("root help missing group description %q:\n%s", want, out)
}
}
if strings.Contains(out, "相关命令") {
t.Errorf("groups still use the vague \"相关命令\" wording:\n%s", out)
}
}
func TestGroupHelpIsChinese(t *testing.T) {
app, stdout, stderr := testApp(centos("docker"))
if code := app.Execute([]string{"disk"}); code != 0 {
t.Fatalf("exit code = %d, stderr=%s", code, stderr.String())
}
out := stdout.String()
for _, want := range []string{"磁盘与文件占用", "用法:", "可用的子命令:", "显示帮助", "kopsc disk --help"} {
if !strings.Contains(out, want) {
t.Errorf("group help missing %q:\n%s", want, out)
}
}
if strings.Contains(out, "help for ") {
t.Errorf("group help still says \"help for\":\n%s", out)
}
}
+1 -1
View File
@@ -323,7 +323,7 @@ func Builtin() *Registry {
ID: "disk.usage",
Aliases: []string{"disk.du"},
Group: "disk",
Summary: "列出目录下各直接子项的占用空间,按大小降序",
Summary: "看哪个目录或文件最占空间(按大小从大到小排)",
Action: "等价于 du -x --max-depth=1 -h <路径> | sort -hr:统计每个直接子项(文件或目录递归)的占用," +
"不跨越文件系统边界,末尾输出该路径的合计。路径可省略(默认当前目录),也可作位置参数或用 --path 指定;" +
"由于 Windows 没有等价的 du/sort,这里使用 kopsc 内置实现以保证三平台输出一致",