中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么在Golang中使用Cobra創建CLI應用

發布時間:2022-01-04 17:12:48 來源:億速云 閱讀:126 作者:iii 欄目:開發技術

本篇內容主要講解“怎么在Golang中使用Cobra創建CLI應用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么在Golang中使用Cobra創建CLI應用”吧!

對于開發人員來說平時可能就需要使用到很多 CLI 工具,比如 npm、node、go、python、docker、kubectl 等等,因為這些工具非常小巧、沒有依賴性、非常適合系統管理或者一些自動化任務等等。

我們這里選擇使用 Golang 里面非常有名的Cobra庫來進行 CLI 工具的開發。Cobra 是一個功能強大的現代化 CLI 應用程序庫,有很多知名的 Go 項目使用 Cobra 進行構建,比如:Kubernetes、Docker、Hugo 等等

概念

Cobra 是構建在命令、參數和標識符之上的:

  • Commands表示執行動作

  • Args就是執行參數

  • Flags是這些動作的標識符

基本的執行命令如下所示:

$ APPNAME Command Args --Flags
# 或者
$ APPNAME Command --Flags Args

比如我們平時使用的一些命令行工具:

git clone URL -bare
go get -u URL
npm install package –save
kubectl get pods -n kube-system -l app=cobra

示例

下面我們來看下 Cobra 的使用,這里我們使用的 go1.13.3 版本,使用 Go Modules 來進行包管理,如果對這部分知識點不熟悉的,可以查看前面我們的文章Go Modules 基本使用(視頻)了解。

新建一個名為my-calc的目錄作為項目目錄,然后初始化 modules:

$ mkdir my-calc && cd my-calc
# 如果 go modules 默認沒有開啟,需要執行 export GO111MODULE=on 開啟
$ go mod init my-calc
go: creating new go.mod: module my-calc

初始化完成后可以看到項目根目錄下面多了一個go.mod的文件,現在我們還沒有安裝cobra庫,執行下面的命令進行安裝:

# 強烈推薦配置該環境變量
$ export GOPROXY=https://goproxy.cn
$ go get -u github.com/spf13/cobra/cobra

安裝成功后,現在我們可以使用cobra init命令來初始化 CLI 應用的腳手架:

$ cobra init --pkg-name my-calc
Your Cobra applicaton is ready at
/Users/ych/devs/workspace/youdianzhishi/course/my-calc

需要注意的是新版本的 cobra 庫需要提供一個--pkg-name參數來進行初始化,也就是指定上面我們初始化的模塊名稱即可。上面的 init 命令就會創建出一個最基本的 CLI 應用項目:

$ tree .
.
├── LICENSE
├── cmd
│   └── root.go
├── go.mod
├── go.sum
└── main.go

1 directory, 5 files

其中main.go是 CLI 應用的入口,在main.go里面調用好了cmd/root.go下面的Execute函數:

// main.go
package main

import "my-calc/cmd"

func main() {
	cmd.Execute()
}

然后我們再來看下cmd/root.go文件。

rootCmd

root(根)命令是 CLI 工具的最基本的命令,比如對于我們前面使用的go get URL,其中go就是 root 命令,而get就是go這個根命令的子命令,而在root.go中就直接使用了 cobra 命令來初始化rootCmd結構,CLI 中的其他所有命令都將是rootCmd這個根命令的子命令了。

這里我們將cmd/root.go里面的rootCmd變量內部的注釋去掉,并在Run函數里面加上一句fmt.Println("Hello Cobra CLI")

var rootCmd = &cobra.Command{
	Use:   "my-calc",
	Short: "A brief description of your application",
	Long: `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.`,
	Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("Hello Cobra CLI")
    },
}

這個時候我們在項目根目錄下面執行如下命令進行構建:

$ go build -o my-calc

該命令會在項目根目錄下生成一個名為my-calc的二進制文件,直接執行這個二進制文件可以看到如下所示的輸出信息:

$ ./my-calc
Hello Cobra CLI

init

我們知道init函數是 Golang 中初始化包的時候第一個調用的函數。在cmd/root.go中我們可以看到init函數中調用了cobra.OnInitialize(initConfig),也就是每當執行或者調用命令的時候,它都會先執行init函數中的所有函數,然后再執行execute方法。該初始化可用于加載配置文件或用于構造函數等等,這完全依賴于我們應用的實際情況。

在初始化函數里面cobra.OnInitialize(initConfig)調用了initConfig這個函數,所有,當rootCmd的執行方法RUN: func運行的時候,rootCmd根命令就會首先運行initConfig函數,當所有的初始化函數執行完成后,才會執行rootCmdRUN: func執行函數。

我們可以在initConfig函數里面添加一些 Debug 信息:

func initConfig() {
    fmt.Println("I'm inside initConfig function in cmd/root.go")
    ...
}

然后同樣重新構建一次再執行:

$ go build -o my-calc
$ ./my-calc
I'm inside initConfig function in cmd/root.go
Hello Cobra CLI

可以看到是首先運行的是initConfig函數里面的信息,然后才是真正的執行函數里面的內容。

為了搞清楚整個 CLI 執行的流程,我們在main.go里面也添加一些 Debug 信息:

// cmd/root.go
func init() {
    fmt.Println("I'm inside init function in cmd/root.go")
    cobra.OnInitialize(initConfig)
    ...
}

func initConfig() {
    fmt.Println("I'm inside initConfig function in cmd/root.go")
    ...
}

// main.go
func main() {
     fmt.Println("I'm inside main function in main.go")
     cmd.Execute()
}

然后同樣重新構建一次再執行:

$ go build -o my-calc
$ ./my-calc
I'm inside init function in cmd/root.go
I'm inside main function in main.go
I'm inside initConfig function in cmd/root.go
Hello Cobra CLI

根據上面的日志信息我們就可以了解到 CLI 命令的流程了。

init函數最后處理的就是flags了,Flags就類似于命令的標識符,我們可以把他們看成是某種條件操作,在 Cobra 中提供了兩種類型的標識符:Persistent FlagsLocal Flags

  • Persistent Flags: 該標志可用于為其分配的命令以及該命令的所有子命令。

  • Local Flags: 該標志只能用于分配給它的命令。

initConfig

該函數主要用于在 home 目錄下面設置一個名為.my-calc的配置文件,如果該文件存在則會使用這個配置文件。

// cmd/root.go
// initConfig 讀取配置文件和環境變量
func initConfig() {
	if cfgFile != "" {
        // 使用 flag 標志中傳遞的配置文件
		viper.SetConfigFile(cfgFile)
	} else {
		// 獲取 Home 目錄
		home, err := homedir.Dir()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		// 在 Home 目錄下面查找名為 ".my-calc" 的配置文件
		viper.AddConfigPath(home)
		viper.SetConfigName(".my-calc")
	}
    // 讀取匹配的環境變量
	viper.AutomaticEnv()
	// 如果有配置文件,則讀取它
	if err := viper.ReadInConfig(); err == nil {
		fmt.Println("Using config file:", viper.ConfigFileUsed())
	}
}

viper是一個非常優秀的用于解決配置文件的 Golang 庫,它可以從 JSON、TOML、YAML、HCL、envfile 以及 Java properties 配置文件中讀取信息,功能非常強大,而且不僅僅是讀取配置這么簡單,了解更多相關信息可以查看 Git 倉庫相關介紹:https://github.com/spf13/viper。

現在我們可以去掉前面我們添加的一些打印語句,我們已經創建了一個my-calc命令作為rootCmd命令,執行該根命令會打印Hello Cobra CLI信息,接下來為我們的 CLI 應用添加一些其他的命令。

添加數據

在項目根目錄下面創建一個名為add的命令,Cobra添加一個新的命令的方式為:cobra add <commandName>,所以我們這里直接這樣執行:

$ cobra add add
add created at /Users/ych/devs/workspace/youdianzhishi/course/my-calc
$ tree .
.
├── LICENSE
├── cmd
│   ├── add.go
│   └── root.go
├── go.mod
├── go.sum
├── main.go
└── my-calc

1 directory, 7 files

現在我們可以看到cmd/root.go文件中新增了一個add.go的文件,我們仔細觀察可以發現該文件和cmd/root.go比較類似。首先是聲明了一個名為addCmd的結構體變量,類型為*cobra.Command指針類型,*cobra.Command有一個RUN函數,帶有*cobra.Command指針和一個字符串切片參數。

然后在init函數中進行初始化,初始化后,將其添加到rootCmd根命令中rootCmd.AddCommand(addCmd),所以我們可以把addCmd看成是rootCmd的子命令。

同樣現在重新構建應用再執行:

$ go build -o my-calc
$ ./my-calc
Hello Cobra CLI
$ ./my-calc add
add called

可以看到add命令可以正常運行了,接下來我們來讓改命令支持添加一些數字,我們知道在RUN函數中是用戶字符串 slice 來作為參數的,所以要支持添加數字,我們首先需要將字符串轉換為 int 類型,返回返回計算結果。在cmd/add.go文件中添加一個名為intAdd的函數,定義如下所示:

// cmd/add.go
func intAdd(args []string) {
	var sum int
	// 循環 args 參數,循環的第一個值為 args 的索引,這里我們不需要,所以用 _ 忽略掉
	for _, ival := range args {
		// 將 string 轉換成 int 類型
		temp, err := strconv.Atoi(ival)
		if err != nil {
			panic(err)
		}
		sum = sum + temp
	}
	fmt.Printf("Addition of numbers %s is %d\n", args, sum)
}

然后在addCmd變量中,更新RUN函數,移除默認的打印信息,調用上面聲明的addInt函數:

// addCmd
Run: func(cmd *cobra.Command, args []string) {
    intAdd(args)
},

然后重新構建應用執行如下所示的命令:

$ go build -o my-calc
$ ./my-calc
Hello Cobra CLI
# 注意參數之間的空格
$ ./my-calc add 1 2 3
Addition of numbers [1 2 3] is 6

由于RUN函數中的args參數是一個字符串切片,所以我們可以傳遞任意數量的參數,但是確有一個缺陷,就是只能進行整數計算,不能計算小數,比如我們執行如下的計算就會直接 panic 了:

$ ./my-calc add 1 2 3.5
panic: strconv.Atoi: parsing "3.5": invalid syntax

goroutine 1 [running]:
my-calc/cmd.intAdd(0xc0000a5890, 0x3, 0x3)
......

因為在intAdd函數里面,我們只是將字符串轉換成了 int,而不是 float32/64 類型,所以我們可以為addCmd命令添加一個flag標識符,通過該標識符來幫助 CLI 確定它是 int 計算還是 float 計算。

cmd/add.go文件的init函數內部,我們創建一個 Bool 類型的本地標識符,命名成float,簡寫成f,默認值為 false。這個默認值是非常重要的,意思就是即使沒有在命令行中調用 flag 標識符,該標識符的值就將為 false。

// cmd/add.go
func init() {
	rootCmd.AddCommand(addCmd)
	addCmd.Flags().BoolP("float", "f", false, "Add Floating Numbers")
}

然后創建一個floatAdd的函數:

func floatAdd(args []string) {
	var sum float64
	for _, fval := range args {
		// 將字符串轉換成 float64 類型
		temp, err := strconv.ParseFloat(fval, 64)
		if err != nil {
			panic(err)
		}
		sum = sum + temp
	}
	fmt.Printf("Sum of floating numbers %s is %f\n", args, sum)
}

該函數和上面的intAdd函數幾乎是相同的,除了是將字符串轉換成 float64 類型。然后在addCmdRUN函數中,我們根據傳入的標識符來判斷到底應該是調用intAdd還是floatAdd,如果傳遞了--float或者-f標志,就將會調用floatAdd函數。

// cmd/add.go
// addCmd
Run: func(cmd *cobra.Command, args []string) {
    // 獲取 float 標識符的值,默認為 false
    fstatus, _ := cmd.Flags().GetBool("float")
    if fstatus { // 如果為 true,則調用 floatAdd 函數
        floatAdd(args)
    } else {
        intAdd(args)
    }
},

現在重新編譯構建 CLI 應用,按照如下方式執行:

$ go build -o my-calc
$ ./my-calc add 1 2 3
Addition of numbers [1 2 3] is 6
$ ./my-calc add 1 2 3.5 -f
Sum of floating numbers [1 2 3.5] is 6.500000
$./my-calc add 1 2 3.5 --float
Sum of floating numbers [1 2 3.5] is 6.500000

然后接下來我們在給addCmd添加一些子命令來擴展它。

添加偶數

同樣在項目根目錄下執行如下命令添加一個名為even的命令:

$ cobra add even
even created at /Users/ych/devs/workspace/youdianzhishi/course/my-calc

和上面一樣會在root目錄下面新增一個名為even.go的文件,修改該文件中的init函數,將rootCmd修改為addCmd,因為我們是為addCmd添加子命令:

// cmd/even.go
func init() {
	addCmd.AddCommand(evenCmd)
}

然后更新evenCmd結構體參數的RUN函數:

// cmd/even.go
Run: func(cmd *cobra.Command, args []string) {
    var evenSum int
    for _, ival := range args {
        temp, _ := strconv.Atoi(ival)
        if temp%2 == 0 {
            evenSum = evenSum + temp
        }
    }
    fmt.Printf("The even addition of %s is %d\n", args, evenSum)
},

首先將字符串轉換成整數,然后判斷如果是偶數才進行累加。然后重新編譯構建應用:

$ go build -o my-calc
$ ./my-calc add even 1 2 3 4 5 6
The even addition of [1 2 3 4 5 6] is 12

my-calc是我們的根命令,addrootCmd的子命令,even優勢addCmd的子命令,所以按照上面的方式調用。可以用同樣的方式再去添加一個奇數相加的子命令。

到此,相信大家對“怎么在Golang中使用Cobra創建CLI應用”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宁武县| 合江县| 丹江口市| 广宗县| 诏安县| 申扎县| 临清市| 盐津县| 隆林| 华亭县| 崇州市| 诏安县| 阿尔山市| 都兰县| 湄潭县| 嵊州市| 雷山县| 遂川县| 永寿县| 浙江省| 麟游县| 娱乐| 新绛县| 句容市| 贡嘎县| 琼结县| 扶风县| 阿拉尔市| 英超| 蓝田县| 安化县| 江永县| 长汀县| 太仆寺旗| 河间市| 拜城县| 新津县| 内乡县| 枞阳县| 伽师县| 永春县|