1. 程式人生 > >Golang:Cobra安裝與使用

Golang:Cobra安裝與使用

引子

最近在做一個基於Golang的CLI程式,索性便將自己探索出來的經驗寫下與諸位分享,如果更好的方法也希望大家能告知,共同進步

Cobra安裝

大部分教程都是直接告訴我們,我們只需要在有go的環境下,輸入

$ go get -v github.com/spf13/cobra/cobra

便可以順順利利的安裝。然而,現實與理想還是有差距的。許多同學都因為某些被牆的連結而停在了某一步驟。解決方法當然是有的。
請在 $GOPATH/src/golang.org/x 目錄下用 git clone 下載 sys 和 text 專案,然後使用 go install github.com/spf13/cobra/cobra

, 安裝後在 $GOBIN 下出現了cobra 可執行程式。如果你沒有配置 $GOBIN,那麼可以在$GOPATH/bin 下找到 cobra的可執行軟體。(這個方法適用於大部分出現類似問題的第三方包下載)

Cobra使用

生成專案檔案

cobra程式只能在GOPATH之下使用,所以首先你需要進入到GOPATH的src目錄之下,在該目錄下,輸入:

$GOPATH/src/$ cobra init demo

在你的當前目錄下,應該已經生成了一個demo資料夾:

demo
├── cmd
│   └── root.go
├── LICENSE
└── main.go

上述便是該資料夾的結構,我們可以進去該資料夾,執行:

$ go run main.go

應該會列印如下結果:

A longer description that spans multiple lines and likely contains examples and usage of using your application. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.

至此,我們的cobra專案便已經生成完畢

新增子命令

這裡我們先講述如何新增子命令,再說明如何新增引數。
實際操作其實cobra都能幫你完成,假設我們現在需要新增一個test引數,在專案資料夾下命令列輸入

../src/demo$ cobra add test

執行完成後,現在我們的demo結構應該是:

.
├── cmd
│   ├── root.go
│   └── test.go
├── LICENSE
└── main.go

可以看到,在cmd目錄下,已經生成了一個與我們命令同名的go檔案,你也許已經猜測到,與該命令有關的操作也正是在此處實現。現在執行這個子命令

$ go run main.go test

命令列將會列印輸出test called
那麼現在又有一個問題,如果我們想新增子命令下的子命令呢?
現在讓我們開啟test.go,你應該看到如下的檔案內容:

// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
    "fmt"

    "github.com/spf13/cobra"
)

// testCmd represents the test command
var testCmd = &cobra.Command{
    Use:   "test",
    Short: "A brief description of your command",
    Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("test called")
    },
}

func init() {
    RootCmd.AddCommand(testCmd)

    // Here you will define your flags and configuration settings.

    // Cobra supports Persistent Flags which will work for this command
    // and all subcommands, e.g.:
    // testCmd.PersistentFlags().String("foo", "", "A help for foo")

    // Cobra supports local flags which will only run when this command
    // is called directly, e.g.:
    // testCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

你會發現,在init中有一句 RootCmd.AddCommand(testCmd) 這個RootCmd是什麼?開啟root.go,你會發現RootCmd其實就是我們的根命令。我相信機智的同學已經猜出來我們新增子命令的子命令的方法了。現在讓我們在cmd目錄下新建testson.go檔案,把test.go的內容複製進去,並修改為如下內容:

// Copyright © 2017 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
    "fmt"

    "github.com/spf13/cobra"
)

// testCmd represents the test command
var testsonCmd = &cobra.Command{
    Use:   "testson",
    Short: "A brief description of your command",
    Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("testson called")
    },
}

func init() {
    testCmd.AddCommand(testsonCmd)

    // Here you will define your flags and configuration settings.

    // Cobra supports Persistent Flags which will work for this command
    // and all subcommands, e.g.:
    // testCmd.PersistentFlags().String("foo", "", "A help for foo")

    // Cobra supports local flags which will only run when this command
    // is called directly, e.g.:
    // testCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

現在在命令列執行:

go run main.go test testson

當你看到testson called,恭喜你,子命令新增成功!否則你應當檢查你的程式碼是否有誤。

新增引數

我相信從init函式中的註釋中,你已經得到了足夠多的資訊來自己操作新增flag,但我還是想要囉嗦兩句。首先是persistent引數,當你的引數作為persistent flag存在時,如註釋所言,在其所有的子命令之下該引數都是可見的。而local flag則只能在該命令呼叫時執行。可以做一個簡單的測試,在test.go的init函式中,新增如下內容:

testCmd.PersistentFlags().String("foo", "", "A help for foo")
testCmd.Flags().String("foolocal", "", "A help for foo")

現在在命令列 go run main.go test -h 得到如下結果:

../src/demo$ go run main.go test -h
A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.

Usage:
  demo test [flags]
  demo test [command]

Available Commands:
  testson     A brief description of your command

Flags:
      --foo string        A help for foo
      --foolocal string   A help for foo
  -h, --help              help for test

Global Flags:
      --config string   config file (default is $HOME/.demo.yaml)

Use "demo test [command] --help" for more information about a command.

接著讓我們再執行 go run main.go test testson -h

../src/demo$ go run main.go test testson -h
A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.

Usage:
  demo test testson [flags]

Flags:
  -h, --help   help for testson

Global Flags:
      --config string   config file (default is $HOME/.demo.yaml)
      --foo string      A help for foo

可以發現在Gloabal Flags的變化。test作為root的子命令,仍然可以使用root的persistent flag-> config(可以檢視root.go),而testson作為test的子命令,不僅可以使用test的persistent flag-> fool, 也可以使用test父命令的persistent flag。從而我們可以直觀的看出persistent的作用範圍是該命令之後的所有子命令。接下來你可能會問,那flag支援什麼型別引數?答案是,請檢視官方文件
請注意,cmd.Flags().String()與 cmd.Flags().StringP()是不一樣的。假如我們在test.go的init下增加如下兩行:

testCmd.Flags().String("f", "", "test")
testCmd.Flags().StringP("aaa", "a", "", "test")

前者呼叫需要如下形式:

go run main.go test --f

後者有如下兩種形式呼叫:

go run main.go test --aaa
go run main.go test -a

另外可以額外告知你如何使用slice作為引數,如[]string:

testCmd.Flags().StringSliceP("arr","r", nil, "test arr")

呼叫該引數的方法為:

go run main.go test -r "a,b,c"

請不要鍵入多餘空格(除非確實需要鍵入),也不要使用空格替代逗號作為分割符

獲取引數值

在知道了如何設定引數後,我們的下一步當然便是需要在執行時獲取該引數的值。現在讓我們把注意力放到test.go的此部分:

var testCmd = &cobra.Command{
    Use:   "test",
    Short: "A brief description of your command",
    Long: `A longer description that spans multiple lines and likely contains examples
and usage of using your command. For example:

Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("test called")
    },
}

在給你講述如何獲取引數值之前,我希望你能先學習cobra.Command結構,相信我,這樣並不會浪費你的時間。如果你只希望知道如何獲取引數值,那麼也可以在以後再學習。
讓我們把注意力重新放到上面的程式碼上。我們也很容易可以猜測到Use,Short,Long三個引數的作用,這裡便不做闡述(你可以參照新增子命令的子命令的部分的輸出)。顯而易見,我們應該在Run這裡來獲取引數並執行我們的命令功能。獲取引數其實也並不複雜。以testCmd.Flags().StringP("aaa", "a", "", "test")此為例,我們可以在Run函式裡新增:

str := testCmd.Flags().GetString("aaa")

這樣便可以獲取到該引數的值了,其餘型別引數獲取也是同理。如 testCmd.Flags().GetStringSlice("arr"),規律並不難見。

End

至此,你已經有了利用cobra構建一個cli程式的基本能力了。當然,更為複雜的方法在這裡並沒有介紹(因為我沒用到:)),你可以通過官方文件(推薦)或者他人文件來學習更為複雜的應用。