服务计算 | agenda CLI工具开发

作业网址:CLI 命令行实用程序开发实战 - Agenda
代码传送门:https://github.com/zz9629/go/tree/master/agenda

文章目录

  • 1.概述
    • 任务目标
    • 参考文档
  • 2. 准备Cobra
    • 2.1安装 cobra
    • 2.2 Cobra使用
      • 2.2.1 生成agenda项目
      • 2.2.2 添加agenda工具命令
    • 2.3 cobra工作原理
      • 2.3.1 cobra中的重要概念
      • 2.3.2 参数解释
      • 2.3.3 为 Command 添加选项(flags)
      • 2.3.4 命令行参数(arguments)
      • 2.3.5 run模块
      • 2.3.6 帮助信息(help command)
  • 3. agenda
    • 3.1 agenda命令介绍
    • 3.2 项目结构
    • 3.3 register命令实现
    • 3.4 其他指令
      • 3.41 login
      • 3.42 logout
      • 3.43 userquery
      • 3.44 ru
    • 3 .5 entity/userInfoOp.go
    • 3.6 日志处理
  • 4. 项目测试
  • 5. 参考资料

1.概述

命令行实用程序并不是都象 cat、more、grep 是简单命令。go 项目管理程序,类似 java 项目管理 maven、Nodejs 项目管理程序 npm、git 命令行客户端、 docker 与 kubernetes 容器管理工具等等都是采用了较复杂的命令行。即一个实用程序同时支持多个子命令,每个子命令有各自独立的参数,命令之间可能存在共享的代码或逻辑,同时随着产品的发展,这些命令可能发生功能变化、添加新命令等。因此,符合 OCP 原则 的设计是至关重要的编程需求。

任务目标

熟悉 go 命令行工具管理项目
综合使用 go 的函数、数据结构与接口,编写一个简单命令行应用 agenda
使用面向对象的思想设计程序,使得程序具有良好的结构命令,并能方便修改、扩展新的命令,不会影响其他命令的代码
项目部署在 Github 上,合适多人协作,特别是代码归并
支持日志(原则上不使用debug调试程序)

参考文档

官方文档 推荐
golang命令行库cobra的使用 中文翻译

2. 准备Cobra

Cobra既是一个用来创建强大的现代CLI命令行的golang库,也是一个生成程序应用和命令行文件的程序。此命令行工具基于cobra开发.

2.1安装 cobra

直接执行以下命令,可能安装不成功:(因为cobra用到的一些依赖包被墙了)

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

服务计算 | agenda CLI工具开发_第1张图片
所以可以首先安装其依赖包: 在$GOPATH/src/golang.org/x目录下(如果没有,则自行创建)用git clone下载sys和text项目。或者直接去网站下载,这个比较快:
服务计算 | agenda CLI工具开发_第2张图片
然后手动解压到指定目录:
服务计算 | agenda CLI工具开发_第3张图片

最后再到$GOPATH/bin目录下获得可执行文件。还是之前的命令:

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

bin文件夹下成功生成exe可执行文件:
服务计算 | agenda CLI工具开发_第4张图片然后输入cobra即可,如下:
服务计算 | agenda CLI工具开发_第5张图片

2.2 Cobra使用

2.2.1 生成agenda项目

新版cobra需要带–pkg-name参数
新建一个工作路径为$GOPATH/src/zz
进入此目录,使用命令

	λ cobra init agenda --pkg-name=zz/agenda

会生成一个叫zz/agenda的项目
在这里插入图片描述
文件夹结构如下:
服务计算 | agenda CLI工具开发_第6张图片

2.2.2 添加agenda工具命令

除了生成应用程序框架,还可以通过 cobra add 命令生成子命令的代码文件。
在agenda的目录下,添加子命令register,就是

λ cobra add register

服务计算 | agenda CLI工具开发_第7张图片
这条命令生成了 agenda程序中 register 子命令的代码,当然了,还没有什么具体的功能,后面会具体介绍写法。
到现在为止,已经给agenda程序添加了两个command,分别为rootCmd(cobra init 命令默认生成)和registerCmd

2.3 cobra工作原理

下面介绍cobra的工作原理,部分通过刚刚创建的子命令registerCmd介绍。
main.go文件如下:

package main

import "zz/agenda/cmd"
	func main() {
	  cmd.Execute()

root.go根命令,是整个应用命令的入口,通过在main函数中调用rootCmd.Execute()启动,内部实现中监听了所有命令。root.go代码:

var rootCmd = &cobra.Command{
	  Use:   "agenda",
	  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) {
	    // Do Stuff Here
	  },
	}
	func Execute() {
	  if err := rootCmd.Execute(); err != nil {
	    fmt.Println(err)
	    os.Exit(1)
	  }
	}

2.3.1 cobra中的重要概念

cobra 中有个重要的概念,分别是 commandsargumentsflags。其中 commands 代表行为,arguments 就是命令行参数(或者称为位置参数),flags 代表对行为的改变(也就是我们常说的命令行选项)。执行命令行程序时的一般格式为:
[appName] [command] [arguments] --[flag]
比如下面的例子:

# server是 commands,port 是 flag
hugo server --port=1313

# clone 是 commands,URL 是 arguments,brae 是 flag
git clone URL --bare

如果是一个简单的程序(功能单一的程序),使用 commands 的方式可能会很啰嗦,但是像 git、docker 等应用,把这些本就很复杂的功能划分为子命令的形式,会方便使用。
在本程序中,如果要使用子命令register来创建一个用户时,比如输入:

# agenda是程序名,register是commands,-u/-p/-e/-t均是flag,(u的配置为name)
$ agenda register -u=name -p=pass [email protected] -t=8644274

ps:对于命令行参数,有多种输入方式,比如输入用户名的命令行选项-u, 可以是 -uname 或者 -u name 或者 -u=name,三种方式都可以。

2.3.2 参数解释

  • Use: 命令
  • Short: 命令的简短描述。命令表中,会显示此条消息,如输入$ agenda -h
    register this command can register user
    服务计算 | agenda CLI工具开发_第8张图片
  • Long: 命令的详细描述,在帮助命令,如$ [appName] -h或者$ [appName] [command] -h时会显示此程序和此命令的字符串;
    服务计算 | agenda CLI工具开发_第9张图片
  • Run: 命令执行入口,函数主要写在这个模块中。
  • 函数initConfig(): 用来初始化viper配置文件位置,监听变化
  • 函数init(): 定义flag和配置处理

2.3.3 为 Command 添加选项(flags)

选项(flags)用来控制 Command 的具体行为。根据选项的作用范围,可以把选项分为两类:

  • persistent
  • local

对于 persistent 类型的选项,既可以设置给该 Command,又可以设置给该 Command 的子 Command。对于一些全局性的选项,比较适合设置为 persistent 类型,比如控制输出的 verbose 选项:

var Verbose bool
rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose output")

local 类型的选项只能设置给指定的 Command,比如下面定义的 source 选项:

var Source string
rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")

又比如在子命令register.go中,命令register需要新建用户的信息,使用flag进行控制不同的参数。

var registerUser models.User
func init() {
	rootCmd.AddCommand(registerCmd)
	registerCmd.Flags().StringVarP(&registerUser.Username, "username", "u", "", "The User's Username")
	registerCmd.Flags().StringVarP(&registerUser.Password, "password", "p", "", "The User's Password")
	registerCmd.Flags().StringVarP(&registerUser.Email, "email", "e", "", "The User's Email")
	registerCmd.Flags().StringVarP(&registerUser.Telephone, "telephone", "P", "", "The User's telephone")
}

那么用户在使用的时候,可以输入如 $ agenda register -u[name] -p[password] -e[email] -P[tel]创建新用户。
该选项不能指定给 rootCmd 之外的其它 Command。
默认情况下的选项都是可选的,但一些用例要求用户必须设置某些选项,这种情况 cobra 也是支持的,通过 Command 的 MarkFlagRequired 方法标记该选项即可:

var Name Region
rootCmd.Flags().StringVarP(&Region, "region", "r", "", "AWS region (required)")
rootCmd.MarkFlagRequired("region")

此项目中需要用到。
在register命令中,我们需要name和password非空,否则无法创建账户,那么添加两行代码。前面的函数最后的具体代码如下:
服务计算 | agenda CLI工具开发_第10张图片
PS:注意后两行的参数是位置参数username,不是数据结构registerUSer.Username。

2.3.4 命令行参数(arguments)

首先我们来搞清楚命令行参数(arguments)命令行选项(flags/options)的区别。以常见的 ls 命令来说,其命令行的格式为:

ls [OPTION]... [FILE]

其中的 OPTION 对应本文中介绍的 flags,以 - 或 – 开头;而 FILE 则被称为参数(arguments)或位置参数。一般的规则是参数在所有选项的后面,上面的 … 表示可以指定多个选项和多个参数。

cobra 默认提供了一些验证方法:

  • NoArgs - 如果存在任何位置参数,该命令将报错 ArbitraryArgs - 该命令会接受任何位置参数 OnlyValidArgs
  • 如果有任何位置参数不在命令的 ValidArgs 字段中,该命令将报错 MinimumNArgs(int) - 至少要有 N 个位置参数,否则报错 MaximumNArgs(int)
  • 如果位置参数超过 N 个将报错 ExactArgs(int)
  • 必须有 N个位置参数,否则报错 ExactValidArgs(int) 必须有 N 个位置参数,且都在命令的 ValidArgs 字段中,否则报错
  • RangeArgs(min, max) - 如果位置参数的个数不在区间 min 和 max 之中,报错

比如要让 Command cmdTimes 至少有一个位置参数,可以这样初始化它:

var cmdTimes = &cobra.Command{
    Use: …
    Short: …
    Long: …
    Args: cobra.MinimumNArgs(1),
    Run:}

不过这个功能本项目没有用到。

2.3.5 run模块

这个模块就是具体代码,比如在register中,我们需要对已有的用户名和新用户名进行一些比较等等步骤。

2.3.6 帮助信息(help command)

cobra 会自动添加 --help(-h)选项,所以我们可以不必添加该选项而直接使用:
服务计算 | agenda CLI工具开发_第11张图片
cobra 同时还自动添加了 help 子命,默认效果和使用 --help 选项相同。如果为 help 命令传递其它命令作为参数,则会显示对应命令的帮助信息,下面的命令输出 register子命令的帮助信息:
服务计算 | agenda CLI工具开发_第12张图片

3. agenda

3.1 agenda命令介绍

本次实验,我选择实现的命令式register 、login、logout、userquery、ru ,接下来将分别介绍 。

用户注册

  1. 注册新用户时,用户需设置一个唯一的用户名和一个密码。另外,还需登记邮箱及电话信息。
  2. 如果注册时提供的用户名已由其他用户使用,应反馈一个适当的出错信息;成功注册后,亦应反馈一个成功注册的信息。

用户登录

  1. 用户使用用户名和密码登录 Agenda 系统。
  2. 用户名和密码同时正确则登录成功并反馈一个成功登录的信息。否则,登录失败并反馈一个失败登录的信息。

用户登出

  1. 已登录的用户登出系统后,只能使用用户注册和用户登录功能。

用户查询

  1. 已登录的用户可以查看已注册的所有用户的用户名、邮箱及电话信息。

用户删除

  1. 已登录的用户可以删除本用户账户(即销号)。
  2. 操作成功,需反馈一个成功注销的信息;否则,反馈一个失败注销的信息。
    删除成功则退出系统登录状态。删除后,该用户账户不再存在。

3.2 项目结构

agenda
├── cmd                      //各个命令
|  ├── login.go              //登陆
|  ├── logout.go             //登出
|  ├── register.go           //注册一个用户
|  ├── root.go               //主函数
|  ├── ru.go                 //删除某个用户
|  └── userquery.go          //列出所有用户
├── docs                     
|  ├── commandIntro.md       //命令说明文档
|  ├── entity.md             //entity说明文档
|  └── models.md             //model说明文档
├── entity                          
|  └── userInfoOp.go    	 //存放 User 对象读写与处理逻辑
├── LICENSE                  
├── log                      
|  └── logFile.txt           //log 包记录命令执行情况
├── main.go                  
├── models                   
|  ├── logger.go             //日志处理函数
|  └── user.go               //user数据结构
├── README.md                
└── storage                  //user实体存储
   ├── curUser.txt           
   └── users.json            
                     
directory: 6 file: 19        

3.3 register命令实现

以register为例,简单过一下项目的流程。
这个指令比较复杂,我们首先要读取新用户信息,接着遍历所有用户的名字,检查是否与新用户信息冲突。若不冲突则可以注册,否则则返回失败。

  • 读取用户信息使用到的是 agenda/entity包 ,这个包存放 User (和 Meeting) 对象读写与处理逻辑。
  • 用户对象的处理放在 agenda/entity/userInfoOp.go这个代码文件中。(如果有会议的处理,也会单股用meetingInfoOp.go代码文件,这样是增加文件的内聚性和减小各个文件间的耦合性)
  • entity 包会读取文件storage/user.json,这个json文件相当于用户的数据库,所有用户的信息都保存在里面。
  • entity 函数会返回所有用户信息。接着我们就可以在这个数组中遍历所有的用户名,来查询冲突。
  • 主要用到的文件为如下结构:
    agenda
    ├── cmd                    
    |  ├── register.go           //注册一个用户
    |  └── root.go				 
    ├── entity                   //存放对象读写与处理逻辑 
    |  └── userInfoOp.go    	 //User对象                       
    ├── main.go                  
    ├── models                   
    |  └── user.go               //user数据结构             
    └── storage                  //数据实体存储       
       └── users.json            //所有user信息
    
  • users.json 保存所有用户的信息,register.go是通过entity包读写用户集来访问这个文件的,user.json和register.go两个文件并没有直接的接口。

创建register命令后,cmd命令中的register.go初始结构如下:

package cmd
import (
	"fmt"
	"github.com/spf13/cobra"
)
// registerCmd represents the register command
var registerCmd = &cobra.Command{
	Use:   "register",
	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("register called")
	},
}
func init() {
	rootCmd.AddCommand(registerCmd)
}

在这个命令中,添加代码之后如下:

package cmd

import (
	"fmt"
	"os"
	"github.com/spf13/cobra"
	"zz/agenda/entity"
	"zz/agenda/models"
)

var registerUser models.User

// registerCmd represents the register command
var registerCmd = &cobra.Command{
	Use:   "register",
	Short: "This command can register user",
	Long:  `You can use agenda register to sign up one user`,
	Run: func(cmd *cobra.Command, args []string) {
		models.Logger.SetPrefix("[agenda register]")
		users := entity.ReadUserInfoFromFile()
		for _, user := range users {
			if user.Username == registerUser.Username {
				models.Logger.Println(registerUser.Username, "has been registered!")
				fmt.Println(registerUser.Username, "has been registered!")
				os.Exit(0)
			}
		}
		users = append(users, registerUser)
		entity.WriteUserInfoToFile(users)
		models.Logger.Println("Register", registerUser.Username, "successfully!")
		fmt.Println("Register", registerUser.Username, "successfully!")
	},
}

func init() {
	rootCmd.AddCommand(registerCmd)
	registerCmd.Flags().StringVarP(&registerUser.Username, "username", "u", "", "The User's Username")
	registerCmd.Flags().StringVarP(&registerUser.Password, "password", "p", "", "The User's Password")
	registerCmd.Flags().StringVarP(&registerUser.Email, "email", "e", "", "The User's Email")
	registerCmd.Flags().StringVarP(&registerUser.Telephone, "telephone", "P", "", "The User's telephone")
	registerCmd.MarkFlagRequired("username")
	registerCmd.MarkFlagRequired("password")
}

下面介绍一下这个具体代码的补充。
首先这个函数需要一些用户的参数,然后创建一个用户类型存储这些信息,方便之后的比较。

  • 首先是用户的数据结构,因此定义这样一个数据结构,在agenda/models/user.go中。因此在register.go中可以直接使用这个数据结构,我们需要做的仅仅是import这个包即可。
    服务计算 | agenda CLI工具开发_第13张图片
    ps:本来完整的项目需要实现会议,那么会议的数据结构meeting.go也是可以直接打包在models文件夹中的。

  • 有了用户的数据结构之后,就可以在register.go中使用了。
    首先定义一个新的用户registerUser ,类型为models.User

    var registerUser models.User
    
  • 现在需要把命令行中的参数传入registerUser 中。
    原理在flag中已经解释过了,这里不再赘述。因为用户名和密码是必须的,而邮箱和电话号码是选填,因此在后两行需要添加MarkFlagRequired函数。否则的话,可能出现用户名和密码为空的情况。(以防万一,也可以在run模块中对用户名密码的内容进行判断。不过我觉得MarkFlagRequired已经足够了)

    func init() {
    	rootCmd.AddCommand(registerCmd)
    	registerCmd.Flags().StringVarP(&registerUser.Username, "username", "u", "", "The User's Username")
    	registerCmd.Flags().StringVarP(&registerUser.Password, "password", "p", "", "The User's Password")
    	registerCmd.Flags().StringVarP(&registerUser.Email, "email", "e", "", "The User's Email")
    	registerCmd.Flags().StringVarP(&registerUser.Telephone, "telephone", "P", "", "The User's telephone")
    	registerCmd.MarkFlagRequired("username")
    	registerCmd.MarkFlagRequired("password")
    }
    
  • 现在已经有了新用户对象,接下来就是注册用户的操作了。我们需要数据库(所有用户信息)中所有用户的信息,然后判断是否可以加入这个新用户。

    • 如果重名了,直接退出。
    • 否则,扩展用户,并将新用户集写入数据库中。
    • ps:失败或成功,都需要写入日志log并在终端上输出。
      run模块:
    Run: func(cmd *cobra.Command, args []string) {
    		models.Logger.SetPrefix("[agenda register]")//日志前缀
    		users := entity.ReadUserInfoFromFile()		//从数据库中读取用户集
    		for _, user := range users {				//遍历每一个用户
    			if user.Username == registerUser.Username {
    				models.Logger.Println(registerUser.Username, "has been registered!")
    				fmt.Println(registerUser.Username, "has been registered!")
    				os.Exit(0)
    			}
    		}
    		users = append(users, registerUser)		//添加用户
    		entity.WriteUserInfoToFile(users)		//将新的用户集写入数据库
    		models.Logger.Println("Register", registerUser.Username, "successfully!")		//日志记录
    		fmt.Println("Register", registerUser.Username, "successfully!")
    	},				//终端输出
    
  • 用户集的获取与写入均用到了agenda/entity/userInfoOp.go中的read,write函数,这个文件封装了user对象的读写。

  • 日志的路径处理用到了agenda/models/logger.go

这些放在后面讲。

3.4 其他指令

其他指令和register差不多,先添加指令,然后在cmd/[command].go指令代码中修改代码即可,指令如下:

λ cobra add login
λ cobra add logout
λ cobra add userquery
λ cobra add ru

如图:
服务计算 | agenda CLI工具开发_第14张图片
最后在相应的cmd/[command].go指令代码中修改代码即可。

3.41 login

  • login命令的实现比较简单,用户的输入和register一样,不过只需要用户名和密码。
  • 在函数实现中,首先需要查询现在是否已经有用户登陆,无法同时登陆两个账号。
  • 然后再查询用户集,当前用户是否再用户集中,密码是否相同。
  • 如果登陆成功,需要更新当前登陆用户的信息curUser.txt.这也是通过entity包实现的。
package cmd
import (
	"os"
	"fmt"
	"zz/agenda/models"
	"zz/agenda/entity"
	"github.com/spf13/cobra"
)
var loginUser models.User
var loginCmd = &cobra.Command{
	Use:   "login",
	Short: "This command can login user",
	Long: `You can use agenda login to login one user.`,
	Run: func(cmd *cobra.Command, args []string) {
		users := entity.ReadUserInfoFromFile()
		models.Logger.SetPrefix("[agenda login]")

		// 判断是否已经登陆过
		isLoggedIn, user := entity.IsLoggedIn()
		if isLoggedIn == true {
			// 已经登陆
			fmt.Println(user.Username + " has already in")
			os.Exit(0)
		}

		for _, userInfo := range users {
			if userInfo.Username == loginUser.Username && userInfo.Password == loginUser.Password {
				entity.SaveCurUserInfo(userInfo)
				models.Logger.Println("Login", loginUser.Username, "successfully!")
				fmt.Println("Login successfully")
				os.Exit(0)
			} else {
				models.Logger.Println("Login", loginUser.Username, "error!")
				fmt.Println("Username or Password error, please check your input")
				os.Exit(0)
			}
		}
		models.Logger.Println("Login", loginUser.Username, "no such an user!")
		fmt.Println("No such an user")
	},
}
func init() {
	rootCmd.AddCommand(loginCmd)
	loginCmd.Flags().StringVarP(&loginUser.Username, "username", "u", "", "The User's Username")
	loginCmd.Flags().StringVarP(&loginUser.Password, "password", "p", "", "The User's Password")
	loginCmd.MarkFlagRequired("username")
	loginCmd.MarkFlagRequired("password")
}

3.42 logout

logout是最简单的一部分,先判断当前是否有人登陆,如果有的话,清空登陆信息即可,均用到了entity包的函数。

package cmd
import (
	"fmt"
	"zz/agenda/models"
	"zz/agenda/entity"
	"github.com/spf13/cobra"
)
var logoutCmd = &cobra.Command{
	Use:   "logout",
	Short: "This command can logout user",
	Long: `You can use agenda logout to logout user.`,
	Run: func(cmd *cobra.Command, args []string) {
		models.Logger.SetPrefix("[agenda logout]")

		isLoggedIn, user := entity.IsLoggedIn()
		if isLoggedIn == true {			//有用户登陆
			entity.ClearCurUserInfo()	//清空登陆信息
			fmt.Println(user.Username, "log out")
			models.Logger.Println(user.Username, "log out")
		} else {
			fmt.Println("No user login")//没人登录,这个就不计入日志了
		}
	},
}

func init() {
	rootCmd.AddCommand(logoutCmd)
}

3.43 userquery

这个命令实现的逻辑和上面相同。如果当前有人登陆,直接列出所有用户的信息即可。
其中调用entity包查看当前是否有人登陆,以及获得所有用户信息。

package cmd
import (
	"fmt"
	"zz/agenda/models"
	"zz/agenda/entity"
	"github.com/spf13/cobra"
)
var userqueryCmd = &cobra.Command{
	Use:   "userquery",
	Short: "This command can query all user information only for logged in users",
	Long: `You can use agenda userquery to get all user information only for logged in users.`,
	Run: func(cmd *cobra.Command, args []string) {
		models.Logger.SetPrefix("[agenda userquery]")
		isLoggedIn, user := entity.IsLoggedIn()
		if isLoggedIn == true {
			models.Logger.Println("UserQuery", user.Username, "query all users infomation!")
			users := entity.ReadUserInfoFromFile()
			fmt.Println("Name\tPhone\t\tEmail")
			for _, userInfo := range users {
				fmt.Printf("%-8s%-16s%s\n", userInfo.Username, userInfo.Telephone, userInfo.Email)
			}
		} else {
			fmt.Println("Please login")
		}
	},
}
func init() {
	rootCmd.AddCommand(userqueryCmd)
}

3.44 ru

这个命令只针对当前登陆的用户。会清除当前登陆信息,相当于logout;然后删除当前用户。

package cmd
import (
	"fmt"
	"zz/agenda/models"
	"zz/agenda/entity"
	"github.com/spf13/cobra"
)
var ruCmd = &cobra.Command{
	Use:   "ru",
	Short: "This command is used to clear the account for the user who has logged in.",
	Long: `You can use agenda ru to Clear your account information [use with caution]`,
	Run: func(cmd *cobra.Command, args []string) {
		models.Logger.SetPrefix("[agenda remove user]")
		isLoggedIn, user := entity.IsLoggedIn()
		if isLoggedIn == true {
			// delete login info
			entity.ClearCurUserInfo()

			// delete user info
			entity.RemoveUser(user.Username)

			models.Logger.Println(user.Username, "clear account")
			fmt.Println("Remove user ["+ user.Username + "] successfully")
		} else {
			fmt.Println("Please login first")
		}
	},
}
func init() {
	rootCmd.AddCommand(ruCmd)
}

3 .5 entity/userInfoOp.go

  • ReadUserInfoFromFile()

    /**
    	 * @arguments: nil
    	 * @return: []models.User
    	 */
    

    此函数用于从users.json文件中读取所有用户信息。 通过利用文件读操作,包括os、bufio、json-iterator/go等库的使用,我们遍历整个用户信息文件,获取所有用户的models.Meeting切片然后返回。

  • WriteUserInfoToFile()

    /**
     * @arguments: []models.User
     * @return: nil
     */
    

    此函数用于将当前列表中的更新后的所有用户信息重新写入users.json文件中。 通过利用文件写操作,包括os、bufio、json-iterator/go等库的使用,我们可以将所有用户信息编码为json格式的字符串并存储到users.json文件中。

  • SaveCurUserInfo()

    /**
     * @arguments: loginUser models.User
     * @return: nil
     */
    

    此函数用于将当前登陆的用户信息存储到curUser.txt文件中,方便登陆用户信息的存储。

  • ClearCurUserInfo

    /**
     * @arguments: nil
     * @return: nil
     */
    

    当登陆用户登出的时候,我们利用os库Truncate函数来将登录用户信息从curUser.txt文件中删除。

  • IsLoggedIn

    /**
     * @arguments: nil
     * @return: bool, models.User
     */
    

    此函数判断当前是否已经已经有用户登录,并且返回登录用户信息。 我们可以利用此函数来加一些限定,因为未登录的用户不能进行cm、mtcancel等操作。

  • IsUser

    /**
     * @arguments: name string
     * @return: bool
     */
    

    此函数用于判端当前用户名是否为已注册的用户,调用ReadUserInfoFromFile并加以判断即可。可以用于在创建、删除会议时判断用户是否存在;或者注册用户时判断该用户名是否已经被注册等。

  • RemoveUser

    	/**
    	 * @arguments: name string
    	 * @return: nil
    	 */
    

    此函数用于移除用处,主要是方便ru操作。调用ReadUserInfoFromFile获取用户信息,加以处理后再调用WriteUserInfoToFile更新用户信息即可。

3.6 日志处理

4. 项目测试

  • agenda目录中go install之后,可以在任何目录下启动该agenda
λ agenda

服务计算 | agenda CLI工具开发_第15张图片

  • register
λ agenda register -u=zz -p=zz -e=[email protected] -t=8763526
λ agenda register -u=aa -p=aa -e=[email protected] -t=83243526
λ agenda register -u=bb -p=bb -e=[email protected] -t=8312352

服务计算 | agenda CLI工具开发_第16张图片
现在查看agenda/storage/users.json:
服务计算 | agenda CLI工具开发_第17张图片
成功写入新用户信息。

  • login
λ agenda login -uzz -pzz

在这里插入图片描述
查看当前登陆用户信息,curUser.txt
在这里插入图片描述
成功登陆。

  • userquery
λ agenda userquery

服务计算 | agenda CLI工具开发_第18张图片

  • logout
λ agenda logout

在这里插入图片描述
服务计算 | agenda CLI工具开发_第19张图片
curUser.txt为空,成功登出。

  • 这个时候,没有用户登陆,那么是无法获取所有用户信息的。
λ agenda userquery

在这里插入图片描述

  • ru
λ agenda ru

服务计算 | agenda CLI工具开发_第20张图片
现在查看agenda/storage/users.json:
服务计算 | agenda CLI工具开发_第21张图片
已经成功删除zz用户。

测试结束。

5. 参考资料

Golang : cobra 包简介

你可能感兴趣的:(服务计算)