cmdr 03 - 用流式接口定義命令行參數處理選項

cmdr 03 - 用流式接口定義命令行參數處理選項

基於 v0.2.17git

轉眼已經來到了 cmdr v0.2.17 了,爲了解決此前版本中關於子命令和選項定義語句的太多嵌套的問題,咱們實現了流式調用接口(Fluent APIs)。github

cmdr 是我發佈的一個開源的 golang 命令行參數處理器。它是 golang flags 的替代品。之因此發佈它,是由於已有的 command line UI 三方包沒法知足個人平常要求,迫不得己本身造一個。若是還沒有有了解 cmdr 怎麼使用的,不妨抽空瀏覽個人早前文章,以求得到一些基本概念:golang

稍後我會繼續針對 cmdr 的用法作介紹文章。segmentfault

至於本文呢 ,只是簡單講述一下如何使用 cmdr 的流式接口(Fluent API)來完成定義。api

定義 RootCommand

root := cmdr.Root("aa", "1.0.1").Header("aa - test for cmdr - no version")
rootCmd = root.RootCommand()

第二句是拿到一個 *cmdr.Command 指針,稍後能夠作一下相關的其它操做。函數

此外,rootCmd 做爲函數返回值,也便於被用到向 cmdr.Exec() 作傳遞參數。post

func buildCmds() *cmdr.Command {
    root := ...
    rootCmdr = root.RootCommand()
    ...
    return rootCmdr
}

func main() {
    if err := cmdr.Exec(buildCmds()); err != nil {
        logrus.Fatal(err)
    }
}

定義命令 Command

頂級的命令其實就是 RootCommand 的 子命令,因此:測試

co := root.NewSubCommand().
        Titles("ms", "micro-service").
        Description("", "").
        Group("")

在這裏,你能夠作的定義基本上和 cmdr.Command 結構定義是相匹配的,因此你可使用 OptCmd接口所支持的方法來完成一條命令的定義:ui

// OptCmd to support fluent api of cmdr.
// see also: cmdr.Root().NewSubCommand()/.NewFlag()
OptCmd interface {
    Titles(short, long string, aliases ...string) (opt OptCmd)
    Short(short string) (opt OptCmd)
    Long(long string) (opt OptCmd)
    Aliases(ss ...string) (opt OptCmd)
    Description(oneLine, long string) (opt OptCmd)
    Examples(examples string) (opt OptCmd)
    Group(group string) (opt OptCmd)
    Hidden(hidden bool) (opt OptCmd)
    Deprecated(deprecation string) (opt OptCmd)
    Action(action func(cmd *Command, args []string) (err error)) (opt OptCmd)

    // FlagAdd(flg *Flag) (opt OptCmd)
    // SubCommand(cmd *Command) (opt OptCmd)
    PreAction(pre func(cmd *Command, args []string) (err error)) (opt OptCmd)
    PostAction(post func(cmd *Command, args []string)) (opt OptCmd)
    TailPlaceholder(placeholder string) (opt OptCmd)

    NewFlag(typ OptFlagType) (opt OptFlag)
    NewSubCommand() (opt OptCmd)

    OwnerCommand() (opt OptCmd)
    SetOwner(opt OptCmd)

    RootCommand() *RootCommand
}

定義選項 Flag

對於每條命令,你均可覺得其附着一系列的選項,這是經過 NewFlag 來完成的:命令行

co.NewFlag(cmdr.OptFlagTypeUint).
        Titles("t", "retry").
        Description("", "").
        Group("").
        DefaultValue(3, "RETRY")

相似的,全部 OptFlag 接口支持的方法均可以用在這裏:

// OptFlag to support fluent api of cmdr.
// see also: cmdr.Root().NewSubCommand()/.NewFlag()
OptFlag interface {
    Titles(short, long string, aliases ...string) (opt OptFlag)
    Short(short string) (opt OptFlag)
    Long(long string) (opt OptFlag)
    Aliases(ss ...string) (opt OptFlag)
    Description(oneLine, long string) (opt OptFlag)
    Examples(examples string) (opt OptFlag)
    Group(group string) (opt OptFlag)
    Hidden(hidden bool) (opt OptFlag)
    Deprecated(deprecation string) (opt OptFlag)
    Action(action func(cmd *Command, args []string) (err error)) (opt OptFlag)

    ToggleGroup(group string) (opt OptFlag)
    DefaultValue(val interface{}, placeholder string) (opt OptFlag)
    ExternalTool(envKeyName string) (opt OptFlag)

    OwnerCommand() (opt OptCmd)
    SetOwner(opt OptCmd)

    RootCommand() *RootCommand
}

重複以上步驟

按照遞歸的定義方案,反覆重複,你就能夠獲得一套完整的命令行界面定義了。

我得認可,這個方式避免了傳統方式的結構嵌套問題,可讀性上是要好不少的了。但它的問題也很明顯,你須要在程序啓動時額外消耗一點點 CPU 來完成上述定義指令的執行,相比而言,這比傳統方式略微費事了 a little bit。但我還要認可,這個消耗,人是感覺不出來的。

小結

流式接口並未帶來任何新鮮東西。它只是改善了定義 Command Line UI 的友善性。

cmdr 同時支持兩種方式以支持你的命令行參數定義。

版本計劃和規劃

v0.2.17:在這個版本中,咱們計劃作一系列 gocov 自測工做,以便掃蕩此前功能性推動過程當中的潛在隱患。在某些臨界條件知足的場景下,cmdr 也許會工做的不使人滿意,所以是時候自檢一下下了。

新的版本很快就會發布以覆蓋 v0.2.17 的一系列子版本。

總的來講,如無心外,咱們遵循古老的傳統,奇數版本號代碼着 stable 發佈。若是有,偶數版本屬於臨時性的、又或是試驗性的發佈。

更多狀況下,咱們會在奇數版本號上加之後綴以完成線上測試,例如 v0.2.17-rel01。它們每每是爲了配合開源 CI/CD 而產生的。

若是咱們有實驗性的想法,那麼一般會在 devel 的基礎上展開特殊分支來進行測試。

參考

相關文章
相關標籤/搜索