Sevice Computing服務計算: CLI 命令行實用程序開發實戰Agenda 及 Linux下安裝配置Cobra教程


CLI 命令行實用程序開發實戰Agenda 及 Linux下安裝配置Cobra教程)

1、概述

命令行實用程序並不是都象 cat、more、grep 是簡單命令。go 項目管理程序,類似 java 項目管理 maven、Nodejs 項目管理程序 npm、git 命令行客戶端、 docker 與 kubernetes 容器管理工具等等都是採用了較複雜的命令行。即一個實用程序同時支持多個子命令,每個子命令有各自獨立的參數,命令之間可能存在共享的代碼或邏輯,同時隨着產品的發展,這些命令可能發生功能變化、添加新命令等。因此,符合 OCP 原則 的設計是至關重要的編程需求。

2、安裝配置Cobra

cobra的安裝

首先使用命令 go get -v github.com/spf13/cobra/cobra下載cobra
但是這裏會出提示如下錯誤:

Fetching https://golang.org/x/sys/unix?go-get=1
https fetch failed: Get https://golang.org/x/sys/unix?go-get=1: dial tcp 216.239.37.1:443: i/o timeout

這是熟悉的錯誤,解決辦法是需要安裝golang的項目依賴test和sys。
首先cd到$GOPATH/src/golang.org/x文件夾下,用 git clone下載 sys 和 text 項目,命令如下:

cd $GOPATH/src/golang.org/x
git clone https://github.com/golang/sys
git clone https://github.com/golang/text

可以看到該目錄下出現了sys和text兩個文件夾如下:
在這裏插入圖片描述
然後再重新執行命令 go get -v github.com/spf13/cobra/cobra下載cobra:
在這裏插入圖片描述
在這裏插入圖片描述
然後執行命令go install github.com/spf13/cobra/cobra, 安裝後在 $GOBIN 下出現了 cobra 可執行程序。
在這裏插入圖片描述
輸入命令cobra help也可以看到有幫助文檔的輸出,說明安裝成功。
在這裏插入圖片描述

cobra的初始化

在新建的項目文件夾下使用cobra init --pkg-name agenda命令可以初始化一個新的項目
在這裏插入圖片描述
其中agenda是你自定義的項目名稱,可以自行修改的,成功後初始化的項目結構如下:
在這裏插入圖片描述

cobra添加命令

在項目文件夾下使用Cobra add命令可以爲你的程序添加新的命令,在本次實驗中,我添加的兩條命令分別是register和login那麼這裏添加命令的語句就是:

Cobra add register
Cobra add login

在這裏插入圖片描述
在這裏插入圖片描述在這裏插入圖片描述
在這裏插入圖片描述
可以看到在cmd文件夾下除了最開始的root.go還出現了我們新建的兩條命令的.go文件,然後在這些文件當中進行編寫開發就可以了。

3、開發實踐

需求描述

  • 功能需求: 設計一組命令完成 agenda 的管理,要求包括2條命令:

    用戶註冊

    • 註冊新用戶時,用戶需設置一個唯一的用戶名和一個密碼。另外,還需登記郵箱及電話信息。
    • 如果註冊時提供的用戶名已由其他用戶使用,應反饋一個適當的出錯信息;成功註冊後,亦應反饋一個成功註冊的信息。
    • agenda login -uUserName –password pass

    用戶登錄

    • 用戶使用用戶名和密碼登錄 Agenda 系統。
    • 用戶名和密碼同時正確則登錄成功並反饋一個成功登錄的信息。否則,登錄失敗並反饋一個失敗登錄的信息。
  • 持久化要求:

    • 使用 json 存儲 User 和 Meeting 實體
    • 當前用戶信息存儲在 curUser.txt 中
  • 項目目錄

    • cmd :存放命令實現代碼
    • entity :存放 User 和 Meeting 對象讀寫與處理邏輯
    • 其他目錄 : 自由添加
  • 日誌服務

    • 使用 log 包記錄命令執行情況

代碼分析

register.go

通過init函數獲取用戶輸入的命令行的不同參數,包括用戶名,密碼,郵箱,電話號碼四種string類型的變量。

rootCmd.AddCommand(registerCmd)
	registerCmd.Flags().StringP("user", "u", "Anonymous", "help message for username")
	registerCmd.Flags().StringP("password", "p", "123", "help message for password")
	registerCmd.Flags().StringP("email", "e", "[email protected]", "help message for email")
	registerCmd.Flags().StringP("phone", "f", "13611263068", "help message for phone")

讀取用戶信息後,由於我們讀取用戶信息使用到的是 json 的框架。

JSON (JavaScript對象表示法)是一種簡單的數據交換格式。在語法上,它類似於JavaScript的對象和列表。以文字爲基礎,具有自我描述性且易於讓人閱讀。儘管JSON是JavaScript的一個子集,但JSON是獨立於語言的文本格式,並且採用了類似於C語言家族的一些習慣。JSON與XML最大的不同在於XML是一個完整的標記語言,而JSON不是。JSON由於比XML更小、更快,更易解析,以及瀏覽器的內建快速解析支持,使得其更適用於網絡數據傳輸領域。

Go的JSON包中有如下函數:

// json.go
package main
import (
    "encoding/json"
    "fmt"
)
type Server struct {
    ServerName string
    ServerIP   string
}
type Serverslice struct {
    Servers []Server
}
func main() {
    var s Serverslice
    str := `{"servers":[{"serverName":"Shanghai_VPN","serverIP":"127.0.0.1"},
            {"serverName":"Beijing_VPN","serverIP":"127.0.0.2"}]}`
 
    json.Unmarshal([]byte(str), &s)
    fmt.Println(s)
    fmt.Println(s.Servers[0].ServerIP)
 
}

利用go中的json包我們可以實現將結構體序列化,我們用函數marshal來encode JSON data ,將用戶輸入轉換成json支持的格式以完成對json文件的讀寫操作,具體關於go中json的用法可以參考這篇 博客

Run 匿名回調函數中我們需要遍歷所有用戶的名字,檢查是否與當前的用戶信息衝突。若不衝突則可以註冊,返回註冊信息及註冊成功,否則則返回返回錯誤信息,然後將命令信息記錄在log文件中。以下爲run匿名回調函數:

	Run: func(cmd *cobra.Command, args []string) {
		//實例化
		str := userinfo{
			Name: "",
			Password: "",
			Email: "",
			Phone: "",
		}
		
		username, _:=cmd.Flags().GetString("user")
		password, _:=cmd.Flags().GetString("password")
		email, _:=cmd.Flags().GetString("email")
		phone, _:=cmd.Flags().GetString("phone")
		fmt.Println("register name : "+username)
		fmt.Println("password : "+password)
		fmt.Println("email : "+email)
		fmt.Println("phone : "+phone)
		fmt.Println("Register success!")
		str.Name=username
		str.Password=password
		str.Email=email
		str.Phone=phone
		filename:="./entity/log.log"
		logfile, errr:=os.OpenFile(filename,os.O_RDWR|os.O_APPEND,7)
		if(errr!=nil){
			fmt.Println("openfile fail")
		}
		defer logfile.Close()
		debuglog:=log.New(logfile,"",log.LstdFlags)
	
		//判斷是否已有已註冊同名用戶來判斷註冊是否成功
		if checkuser(username)==true {
			fmt.Println("username exist, create account fail")
			debuglog.Println("register: username "+username+" exist, create account fail")
		} else {
			debuglog.Println("register: username: "+username+" password: "+password+" email: "+email+" phone:"+phone);
			savecuruser(str)
			input := readinfo()
			input.Id=append(input.Id,str)
			data, _:= json.Marshal(input)
			saveinfo(data)
		}
	},
}

在register.go文件中我們還實現了一些功能函數以完成上述邏輯框架,包括保存信息,讀取信息等等,用來讀取整個data.json文件當中的內容以及將用戶新的輸入信息保存到data.json當中。

讀取之後,我們利用checkuser來對全部的信息進行一個遍歷比對,來查詢是否用戶新註冊的用戶名已經存在。

func checkuser(username string) bool{
	input := readinfo()
	l :=len(input.Id)
	for i:=0;i<l;i++ {
		if(input.Id[i].Name==username){
			return true
		}
	}
	return false
}

完整代碼見GitHub。

login.go

login的代碼要簡單很多,以下爲run回調函數,這裏的核心其實就是用戶輸入的用戶名密碼是否存在且是否正確,調用了一個checkpasswd函數返回check值。

Run: func(cmd *cobra.Command, args []string) {
		//fmt.Println("login called")
		username, _:=cmd.Flags().GetString("username")
		password, _:=cmd.Flags().GetString("password")
		check := checkpasswd(username, password)
		filename:="./entity/log.log"
		logfile, errr:=os.OpenFile(filename,os.O_RDWR|os.O_APPEND,7)
		if(errr!=nil){
			fmt.Println("openfile fail")
		}
		defer logfile.Close()
		debuglog:=log.New(logfile,"",log.LstdFlags)
		if check==true {
			fmt.Println("login success")
			debuglog.Println("login: username: "+username+" login success")
		} else {
			fmt.Println("login fail")
			debuglog.Println("login: username: "+username+" login fail")
		}
	},

主要就是進行兩個判斷:一個是判斷用戶是否存在,第二個是判斷密碼是否匹配,以此來進行錯誤反饋。

func checkpasswd(username string, password string) bool{
	input := readinfo()
	l :=len(input.Id)
	for i:=0;i<l;i++ {
		if(input.Id[i].Name==username && input.Id[i].Password==password){
			return true
		}
	}
	return false
}

root.go

root文件參考了這篇博客的內容,詳情請移步參考文檔:Golang: Cobra命令行參數庫的使用
代碼見GitHub。

運行結果測試

測試環境:centos
在這裏插入圖片描述

  • register

成功註冊:
在這裏插入圖片描述
在這裏插入圖片描述
不成功註冊,用戶名重複:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章