命令
What is Subcommand
示例程序
没有子命令的 CLI app - Covered on wget
像 wget
这样的古典 Unix app,并不提供子命令。它可能带有大量的标志,其中一些标志带有命令性质,会请求 app 使用不同的工作逻辑。
一个非完整的 wget 复刻品,在 cmdr 支持下可以这样编写:
package main
import (
"context"
"os"
"github.com/hedzr/cmdr/v2"
"github.com/hedzr/cmdr/v2/cli"
)
func main() {
ctx := context.Background() // with cancel can be passed thru in your actions
app := prepareApp()
if err := app.Run(ctx); err != nil {
println("Application Error:", err)
os.Exit(app.SuggestRetCode())
}
}
const (
wgetVersion = "1.20"
cStartup = "10.Startup"
cLogging = "20.Logging and input file"
cDownload = "30.Download"
cDirectories = "40.Directories"
cHTTPOptions = "50.HTTP Options"
cHTTPSOptions = "51.HTTPS (SSL/TLS) options"
cHstsOptions = "52.HSTS options"
cFtpOptions = "53.FTP options"
cFtpsOptions = "54.FTPS options"
cWarcOptions = "55.WARC options"
cRecusiveDownload = "60.Recursive download"
cRecusiveAccept = "61.Recursive accept/reject"
)
func prepareApp(opts ...cli.Opt) (app cli.App) {
app = cmdr.New(opts...).
Info("wget", wgetVersion).
Author("The Example Authors").
Header(`GNU Wget 1.20, a non-interactive network retriever.
Usage: wget [OPTION]... [URL]...
Mandatory arguments to long options are mandatory for short options too.`) // .Description(``).Header(``).Footer(``)
app.With(func(app cli.App) {
app.Flg("background", "b", "bg").Description(`go to background after startup`).Group(cStartup).Build()
app.Flg("execute", "e").Description(`execute a '.wgetrc'-style command`).Group(cStartup).Default("").PlaceHolder("COMMAND").Build()
app.Flg("output-file", "o").Description(`log messages to FILE`).Group(cLogging).PlaceHolder("FILE").Default("").Build()
app.Flg("append-output", "a").Description(`append messages to FILE`).Group(cLogging).PlaceHolder("FILE").Default("").Build()
app.Flg("no-verbose", "nv").Description(`turn off verboseness, without being quiet`).Group(cLogging).Default("").Build()
app.Flg("report-speed", "").Description(`output bandwidth as TYPE. TYPE can be bits`).Group(cLogging).Default("").PlaceHolder("TYPE").Build()
app.Flg("input-file", "i").Description(`download URLs found in local or external FILE`).Group(cLogging).Default("").PlaceHolder("FILE").Build()
app.Flg("force-html", "F").Description(`treat input file as HTML`).Group(cLogging).Build()
app.Flg("base", "b").Description(`resolves HTML input-file links (-i -F) relative to URL`).Default("").PlaceHolder("URL").Group(cLogging).Build()
app.Flg("config").Description(`specify config file to use`).Group(cLogging).Default("").PlaceHolder("FILE").Build()
app.Flg("no-config").Description(`do not read any config file`).Group(cLogging).Build()
app.Flg("rejected-log").Description(`log reasons for URL rejection to FILE`).Group(cLogging).Default("").PlaceHolder("FILE").Build()
app.Flg("retry-connrefused", "").Description(`retry even if connection is refused`).Group(cDownload).Build()
app.Flg("retry-on-http-error").Description(`comma-separated list of HTTP errors to retry`).Group(cDownload).Default([]string{}).PlaceHolder("ERRORS").Build()
app.Flg("output-document", "O").Description(`write documents to FILE`).Group(cDownload).Default("").PlaceHolder("FILE").Build()
app.Flg("no-clobber", "nc").Description(`skip downloads that would download to existing files (overwriting them)`).Group(cDownload).Build()
app.Flg("no-netrc").Description(`don't try to obtain credentials from .netrc`).Group(cDownload).Build()
app.Flg("continue", "c").Description(`resume getting a partially-downloaded file`).Group(cDownload).Build()
})
app.OnAction(func(ctx context.Context, cmd cli.Cmd, args []string) (err error) {
println(`wget ran.`)
_, err = cmd.App().DoBuiltinAction(ctx, cli.ActionShowHelpScreen)
return
})
// app.RootBuilder(func(parent cli.CommandBuilder) {
// // parent.Cmd(...)...
// parent.OnAction(...)
// })
return
}
注意对于仅有根命令的 app,直接在 app 对象上应用 OnAction
来指定命令响应回调函数。
如果你已经喜欢上了 CommandBuilder/FlagBuilder 方式来构造命令和标志,在 app 对象上还有一个 RootBuilder 可以为你开启相应的回调代码块:
app.RootBuilder(func(parent cli.CommandBuilder) {
// parent.Cmd(...)...
parent.OnAction(...)
})
这和 app.Cmd("subcmd").With(func(b cli.CommandBuilder){ ... })
相似,只不过 parent
代表的是 app.RootCommand()
,而 b
代表的是新建的子命令 subcmd
。
运行时的帮助屏效果为:
带有多级子命令
额外的话题
How is this guide?
Edit on GitHub
Last updated on