目录
项目介绍
参考资料:https://www.cnblogs.com/welhzh/p/8962489.html
开发环境
安装和使用cobra
安装cobra
打开vsc的终端,转到gopath路径(我的是 C:\Users\LLL\go)里面,输入命令安装cobra:
go get -v github.com/spf13/cobra/cobra
https://blog.csdn.net/snowin1994/article/details/88358836
下载过程中发生了以下错误:
参考了老师所给教程和另一个博客中所给的提示,先到$GOPATH/src/golang.org/x目录下用 git clone 下载 sys 和 text 项目
具体指令为:
mkdir $GOPATH/src/golang.org/x //创建文件夹
cd $GOPATH/src/golang.org/x //转至该文件夹
git clone https://github.com/golang/text
git clone https://github.com/golang/sys
改错
发现windows下环境变量有问题,
所以将后两个命令改为
mkdir C:\Users\LLL\go/src/golang.org/x
cd C:\Users\LLL\go/src/golang.org/x
之后便可按原命令go get -v github.com/spf13/cobra/cobra下载。
下载成功后使用命令生成cobra可执行文件
go install github.com/spf13/cobra/cobra
此时,就以安装成功了,查看bin文件夹,可在下面发现已经生成cobra.exe:
Cobra 的使用
创建一个处理命令 agenda register -uTestUser 或 agenda register --user=TestUser 的小程序。
首先进入src文件夹,用cobra init新建一个demo(cobra只能够在gopath的目录下使用):
cobra init demo --pkg-name=demo
进入生成的demo文件夹,使用命令来增加register命令:
cobra add register
之后便产生了需要的文件:
修改register.go
阅读【main.go】和【root.go】、【register.go】三个文件可得知,然后我们可以通过修改【register.go】来添加相应的操作:
- init() 函数:
- Run 匿名回调函数:
测试命令
使用以下命令测试:
go run main.go register --user=TestUser
register called by TestUser??
出现register被调用的输出,结果正确:
Agenda 开发项目
Agenda项目目录
cmd :存放命令实现代码
entity :存放 User 对象读写与处理逻辑
data : 存储User信息和生成log
service:存放命令实现代码所需借用的功能函数
loghelper:存放实现log的相关代码
deepcopy:存放复制功能代码
实现指令
要求
实现2条指令即可,不需要协作。
之前已实现register用户注册指令,这里实现的是login和logout指令。
-
用户注册
注册新用户时,用户需设置一个唯一的用户名和一个密码。另外,还需登记邮箱及电话信息。
如果注册时提供的用户名已由其他用户使用,应反馈一个适当的出错信息;成功注册后,亦应反馈一个成功注册的信息。 -
用户登录
用户使用用户名和密码登录 Agenda 系统。
用户名和密码同时正确则登录成功并反馈一个成功登录的信息。否则,登录失败并反馈一个失败登录的信息。 -
用户登出
已登录的用户登出系统后,只能使用用户注册和用户登录功能。
添加命令
使用命令
cobra add login
cobra add logout
用户注册
绑定参数:
register a new user, a unique username, a password, an email and a phone required
Usage:
Agenda register [flags]
Flags:
-c, --contact string phone number
-e, --email string email address
-h, --help help for register
-p, --password string password
-u, --username string username
register.go如下:
package entity
import (
"os"
"io"
"bufio"
"path/filepath"
"errors"
"log"
"encoding/json"
"demo/loghelper"
"demo/deepcopy"
)
type UserFilter func (*User) bool
var userinfoPath = "/src/demo/data/userinfo"
var curUserPath = "/src/demo/data/curuser.txt"
var curUserName *string
var dirty bool
var uData []User
var errLog *log.Logger
func init() {
errLog = loghelp.Error
dirty = false
userinfoPath = filepath.Join(loghelp.GoPath, userinfoPath)
curUserPath = filepath.Join(loghelp.GoPath, curUserPath)
if err := readFromFile(); err != nil {
errLog.Println("readFromFile fail: ",err)
}
}
func Sync() error {
if err := writeToFile(); err != nil {
errLog.Println("writeToFile fail: ",err)
return err
}
return nil
}
func CreateUser(v *User) {
uData = append(uData, deepcopy.Copy(*v).(User))
dirty = true
}
func QueryUser(filter UserFilter) []User{
var user []User
for _, v := range uData {
if filter(&v) {
user = append(user,v)
}
}
return user
}
func SetCurUser(u *User) {
if u == nil {
curUserName = nil
return
}
if curUserName == nil {
p := u.Name
curUserName = &p
} else {
*curUserName = u.Name
}
}
//return current user
func GetCurUser() (User, error) {
if curUserName == nil {
return User{}, errors.New("Current user doesn't exist")
}
for _, v := range uData {
if v.Name == *curUserName {
return v, nil
}
}
return User{}, errors.New("Current user doesn't exist")
}
func Logout() error {
curUserName = nil
return Sync()
}
func readFromFile() error {
var e []error
str, err1 := readString(curUserPath)
if err1 != nil {
e = append(e, err1)
}
curUserName = str
if err := readUser(); err != nil {
e = append(e, err)
}
//if err := readMet(); err != nil {
// e = append(e, err)
//}
if len(e) == 0 {
return nil
}
er := e[0]
for i := 1; i < len(e); i++ {
er = errors.New(er.Error() + e[i].Error())
}
return er
}
// writeToFile : write file content from memory
// @return if fail, error will be returned
func writeToFile() error {
var e []error
if err := writeString(curUserPath, curUserName); err != nil {
e = append(e, err)
}
if dirty {
if err := writeJSON(userinfoPath, uData); err != nil {
e = append(e, err)
}
//if err := writeJSON(metinfoPath, mData); err != nil {
// e = append(e, err)
//}
}
if len(e) == 0 {
return nil
}
er := e[0]
for i := 1; i < len(e); i++ {
er = errors.New(er.Error() + e[i].Error())
}
return er
}
func readUser() error {
file, err := os.Open(userinfoPath);
if err != nil {
errLog.Println("Open File Fail:", userinfoPath, err)
return err
}
defer file.Close()
dec := json.NewDecoder(file)
switch err := dec.Decode(&uData); err {
case nil, io.EOF:
return nil
default:
errLog.Println("Decode User Fail:", err)
return err
}
}
/*
func readMet() error {
file, err := os.Open(metinfoPath);
if err != nil {
errLog.Println("Open File Fail:", metinfoPath, err)
return err
}
defer file.Close()
dec := json.NewDecoder(file)
switch err := dec.Decode(&mData); err {
case nil, io.EOF:
return nil
default:
errLog.Println("Decode Met Fail:", err)
return err
}
}
*/
func writeJSON(fpath string, data interface{}) error {
file, err := os.Create(fpath);
if err != nil {
return err
}
defer file.Close()
enc := json.NewEncoder(file)
if err := enc.Encode(&data); err != nil {
errLog.Println("writeJSON:", err)
return err
}
return nil
}
func writeString(path string, data *string) error {
file, err := os.Create(path)
if err != nil {
loghelp.Error.Println("Create file error:", path)
return err
}
defer file.Close()
writer := bufio.NewWriter(file)
if data != nil {
if _, err := writer.WriteString(*data); err != nil {
loghelp.Error.Println("Write file fail:", path)
return err
}
}
if err := writer.Flush(); err != nil {
loghelp.Error.Println("Flush file fail:", path)
return err
}
return nil
}
func readString(path string) (*string, error) {
file, err := os.Open(path)
if err != nil {
loghelp.Error.Println("Open file error:", path)
return nil, err
}
defer file.Close()
reader := bufio.NewReader(file)
str, err := reader.ReadString('\n');
if err != nil && err != io.EOF {
loghelp.Error.Println("Read file fail:", path)
return nil, err
}
return &str, nil
}
用户登录
用命令login -u -p来实现用户登录功能。
login.go如下:
/*
Copyright ? 2019 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"
"demo/service"
"github.com/spf13/cobra"
)
var (
username *string
password *string
)
// loginCmd represents the login command
var loginCmd = &cobra.Command{
Use: "login",
Short: "For User To Login",
Run: func(cmd *cobra.Command, args []string) {
tmpu, _ := cmd.Flags().GetString("username")
tmppw, _ := cmd.Flags().GetString("password")
if tmpu == "" || tmppw == "" {
fmt.Println("Input the username[-u],password[-p]")
return;
}
if _, flag := service.GetCurUser(); flag == true {
fmt.Println("Please logout firstly")
return
}
if tf := service.UserLogin(tmpu,tmppw); tf == true {
fmt.Println("Login Successfully!")
} else {
fmt.Println("Login Fail: wront username or password")
}
return
},
}
func init() {
rootCmd.AddCommand(loginCmd)
loginCmd.Flags().StringP("username","u","","agenda account username")
loginCmd.Flags().StringP("password","p","","agenda account password")
}
用户登出
logout.go如下:
/*
Copyright ? 2019 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"
"demo/service"
"github.com/spf13/cobra"
)
// logoutCmd represents the logout command
var logoutCmd = &cobra.Command{
Use: "logout",
Short: "For User To Logout",
Run: func(cmd *cobra.Command, args []string) {
if err := service.UserLogout(); err != true {
fmt.Println("Error happened, please check the error log")
} else {
fmt.Println("Logout Successfully!")
}
},
}
func init() {
rootCmd.AddCommand(logoutCmd)
}
service中的函数
service.go如下:
package service
import (
"demo/entity"
"demo/loghelper"
"log"
)
var curuserinfo = "/src/demo/data/curuser.txt"
var errLog *log.Logger
type User entity.User
func init() {
errLog = loghelp.Error
}
func GetCurUser() (entity.User, bool) {
if cu, err := entity.GetCurUser(); err != nil {
return cu, false
} else {
return cu, true
}
}
//Regist
func UserRegister(username string, password string, email string, phone string) (bool, error) {
user := entity.QueryUser(func (u *entity.User) bool {
return u.Name == username
})
if len(user) == 1 {
errLog.Println("User Register: username already exists")
return false, nil
}
entity.CreateUser(&entity.User{username,password,email,phone})
if err := entity.Sync(); err != nil {
return true, err
}
return true, nil
}
//Login
func UserLogin(username, password string) bool {
user := entity.QueryUser(func (u *entity.User) bool {
if u.Name == username && u.Password == password {
return true
}
return false
})
if len(user) == 0 {
errLog.Println("Login: User not exist")
return false
}
entity.SetCurUser(&user[0])
if err := entity.Sync(); err != nil {
errLog.Println("Login: error happened when set curuser")
return false
}
return true
}
//Logout
func UserLogout() bool {
if err := entity.Logout(); err != nil {
return false
} else {
return true
}
}
运行结果
创建新用户:
当创建新用户时用了重复的用户名时报错:
用户登录:
重复登录报错:
用户密码错误报错:
登出:
完整代码
请见我的GitHub