cobra 是 go 语言的一个库,能够用于编写命令行工具。通常咱们能够看到git pull
、docker container start
、apt install
等等这样命令,都能够很容易用corba来实现,另外,go 语言是很容易编译成一个二进制文件,本文将实现一个简略的命令行工具。
具体写一个例子, 设计一个命令叫blog
, 有四个子命令
blog new [post-name] :创立一篇新的blog blog list :列出以后有哪些文章 blog delete [post-name]: 删除某一篇文章 blog edit [post-name]:编辑某一篇文章
打算有以下几个步骤
- 创立模块
- 用cobra的命令行,创立命令行入口
- 用cobra的命令行,创立子命令
- 编写性能逻辑
创立模块
$ go mod init github.com/shalk/bloggo: creating new go.mod: module github.com/shalk/blog
创立命令行入口
说到命令行,可能会想到bash的getopt 或者 java 的jcommand,能够解析各种格调的命令行,然而通常这些命令行都有固定的写法,这个写法个别还记不住要找一个模板参考以下。cobra除了能够解析命令行之外,还提供了命令行,能够生成模板。先装置这个命令行, 并且把库的依赖加到go.mod里
$ go get -u github.com/spf13/cobra/cobra
cobra会装置到$GOPATH\bin
目录下,留神环境变量中把它退出PATH中
$ cobra init --pkg-name github.com/shalk/blog -a shalk -l mitYour Cobra applicaton is ready atD:\code\github.com\shalk\blog
目录构造如下:
./cmd./cmd/root.go./go.mod./go.sum./LICENSE./main.go
编译一下
go build -o blog .
执行一下
$blog -hA longer description that spans multiple lines and likely containsexamples 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 filesto quickly create a Cobra application.
命令行就创立好了,看上去一行代码也不必写,因为随着理解的深刻,前面须要调整生成的代码,还是要理解一下cobra代码的套路。
cobra代码的套路
有三个概念,command、flag和args ,例如:
go get -u test.com/a/b
这里 get 就是commond(这里比拟非凡), -u 就是flag, test.com/a/b 就是args
那么命令行就是有三局部形成,所以须要定义好这个
- 命令本身的一些根本信息,用command示意,具体对象是 cobra.Command
- 命令的一些标致或者选项,用flag示意,具体对象是 flag.FlagSet
- 最初的参数,用args示意,通常是[]string
还有一个概念是子命令,比方get就是go的子命令,这是一个树状构造的关系。
我能够应用go命令,也能够应用 go get命令
例如: root.go,定义了root命令,另外在init外面 定义了flag,如果它自身有具体执行,就填充Run字段。
// rootCmd represents the base command when called without any subcommandsvar rootCmd = &cobra.Command{ Use: "blog", Short: "A brief description of your application", Long: `A longer description that spans multiple lines and likely containsexamples 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 filesto quickly create a Cobra application.`, // Uncomment the following line if your bare application // has an action associated with it: // Run: func(cmd *cobra.Command, args []string) { },}// Execute adds all child commands to the root command and sets flags appropriately.// This is called by main.main(). It only needs to happen once to the rootCmd.func Execute() { if err := rootCmd.Execute(); err != nil { fmt.Println(err) os.Exit(1) }}func init() { cobra.OnInitialize(initConfig) // Here you will define your flags and configuration settings. // Cobra supports persistent flags, which, if defined here, // will be global for your application. rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.blog.yaml)") // Cobra also supports local flags, which will only run // when this action is called directly. rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")}
如果须要子命令,就须要在init 里,给 rootCmd.AddCommand() 其余的command,其余的子命令通常也会独自用一个文件编写,并且有一个全局变量,让rootCmd能够add它
创立子命令
D:\code\github.com\shalk\blog>cobra add newnew created at D:\code\github.com\shalk\blogD:\code\github.com\shalk\blog>cobra add deletedelete created at D:\code\github.com\shalk\blogD:\code\github.com\shalk\blog>cobra add listlist created at D:\code\github.com\shalk\blogD:\code\github.com\shalk\blog>cobra add editedit created at D:\code\github.com\shalk\blog
cmd 目录下减少了 new.go, delete.go,list.go,edit.go
减少性能代码
new.go
var newCmd = &cobra.Command{ Use: "new", Short: "create new post", Long: `create new post `, Args: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { return errors.New("requires a color argument") } return nil }, Run: func(cmd *cobra.Command, args []string) { fileName := "posts/" + args[0] err := os.Mkdir("posts", 644) if err != nil { log.Fatal(err) } _, err = os.Stat( fileName) if os.IsNotExist(err) { file, err := os.Create(fileName) if err != nil { log.Fatal(err) } log.Printf("create file %s", fileName) defer file.Close() } else { } },}
list.go
var listCmd = &cobra.Command{ Use: "list", Short: "list all blog in posts", Long: `list all blog in posts `, Run: func(cmd *cobra.Command, args []string) { _, err := os.Stat("posts") if os.IsNotExist(err) { log.Fatal("posts dir is not exits") } dirs, err := ioutil.ReadDir("posts") if err != nil { log.Fatal("read posts dir fail") } fmt.Println("------------------") for _, dir := range dirs { fmt.Printf(" %s\n", dir.Name() ) } fmt.Println("------------------") fmt.Printf("total: %d blog\n", len(dirs)) },}
delete.go
var deleteCmd = &cobra.Command{ Use: "delete", Short: "delete a post", Long: `delete a post`, Args: func(cmd *cobra.Command, args []string) error { if len(args) != 1 { return errors.New("requires a color argument") } if strings.Contains(args[0],"/") || strings.Contains(args[0],"..") { return errors.New("posts name should not contain / or .. ") } return nil }, Run: func(cmd *cobra.Command, args []string) { fileName := "./posts/" + args[0] stat, err := os.Stat(fileName) if os.IsNotExist(err) { log.Fatalf("post %s is not exist", fileName) } if stat.IsDir() { log.Fatalf("%s is dir ,can not be deleted", fileName) } err = os.Remove(fileName) if err != nil { log.Fatalf("delete %s fail, err %v", fileName, err) } else { log.Printf("delete post %s success", fileName) } },}
edit.go 这个有一点麻烦,因为如果调用一个程序比方vim 关上文件,并且golang程序自身要退出,须要detach。临时放一下(TODO)
编译测试
我是window测试,linux 更简略一点
PS D:\code\github.com\shalk\blog> go build -o blog.exe .PS D:\code\github.com\shalk\blog> .\blog.exe list------------------------------------total: 0 blogPS D:\code\github.com\shalk\blog> .\blog.exe new blog1.md2020/07/26 22:37:15 create file posts/blog1.mdPS D:\code\github.com\shalk\blog> .\blog.exe new blog2.md2020/07/26 22:37:18 create file posts/blog2.mdPS D:\code\github.com\shalk\blog> .\blog.exe new blog3.md2020/07/26 22:37:20 create file posts/blog3.mdPS D:\code\github.com\shalk\blog> .\blog list------------------ blog1.md blog2.md blog3.md------------------total: 3 blogPS D:\code\github.com\shalk\blog> .\blog delete blog1.md2020/07/26 22:37:37 delete post ./posts/blog1.md successPS D:\code\github.com\shalk\blog> .\blog list------------------ blog2.md blog3.md------------------total: 2 blogPS D:\code\github.com\shalk\blog> ls .\posts\ 目录: D:\code\github.com\shalk\blog\postsMode LastWriteTime Length Name---- ------------- ------ -----a---- 2020/7/26 22:37 0 blog2.md-a---- 2020/7/26 22:37 0 blog3.mdPS D:\code\github.com\shalk\blog>
小结
cobra 是一个高效的命令行解析库,利用cobra的脚手架,能够疾速的实现一个命令行工具。如果须要更粗疏的管制,能够参考cobra的官网文档。