golang开发命令行工具-cobra

包地址:go get -u github.com/spf13/cobra/cobra

go mod init blog
go get -u github.com/spf13/cobra/cobra

具体写一个例子, 设计一个命令叫 blog, 有四个子命令

blog new [post-name] :创建一篇新的blog
blog list   :列出当前有哪些文章
blog delete [post-name]: 删除某一篇文章
blog edit [post-name]:编辑某一篇文章
> cobra init -h
Initialize (cobra init) will create a new application, with a license
and the appropriate structure for a Cobra-based CLI application.

  * If a name is provided, a directory with that name will be created in the current directory;
  * If no name is provided, the current directory will be assumed;

Usage:
  cobra init [name] [flags]

Aliases:
  init, initialize, initialise, create

Flags:
  -h, --help              help for init
      --pkg-name string   fully qualified pkg name

Global Flags:
  -a, --author string    author name for copyright attribution (default "YOUR NAME")
      --config string    config file (default is $HOME/.cobra.yaml)
  -l, --license string   name of license for the project
      --viper            use Viper for configuration (default true)

创建应用

> cobra init --pkg-name blog -a raoxiaoya -l mit
Your Cobra application is ready at
D:\dev\php\magook\trunk\server\golang\project\blog

会生成目录

./cmd
./cmd/root.go
./go.mod
./go.sum
./LICENSE
./main.go

编译运行

> go build main.go
> main.exe -h
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.

有三个概念,commandflagargs ,例如:

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字段。

如果需要子命令,就需要在init 里,给 rootCmd.AddCommand() 其他的 command,其他的子命令通常也会单独用一个文件编写,并且有一个全局变量,让 rootCmd 可以 add 它

cobra add new
cobra add delete
cobra add list
cobra add edit

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.
	
Usage:
  blog new [filename]
Args:
  filename  your new filename`,
	Args: func(cmd *cobra.Command, args []string) error {
		// 参数校验,如果返回 errror则不会执行Run方法
		if len(args) != 1 {
			return errors.New("requires an argument")
		}
		return nil
	},
	Run: func(cmd *cobra.Command, args []string) {
		floder := "posts/"
		fileName := floder + args[0]

		if _, err := os.Stat(floder); os.IsNotExist(err) {
			err := os.Mkdir(floder, 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 {
		}
	},
}
func init() {
	rootCmd.AddCommand(newCmd)
	// 自定义 Usage 说明,此处将模版设置为空(需要有个空格),那么只会展示 Long 中的定义
	newCmd.SetUsageTemplate(" ")
}

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)
        }
    },
}

rootCmd 中设置

SilenceUsage:  true,
SilenceErrors: true,
CompletionOptions: cobra.CompletionOptions{HiddenDefaultCmd: true},

测试

go build main.go
main.exe list
main.exe new blog1.md
main.exe new blog2.md
main.exe new blog3.md
main.exe list
main.exe delete blog1.md
main.exe list

你可能感兴趣的:(golang,golang)