#Golang でCLI Tool を作る時にはCobraを使いがち

概要

今年も大量のツールのようなものを作った.Golangで実装する場合にはkubectlfaas-cli を参考にパクるとなんとなくいい感じのツールが作れます.

packageの紹介

spf13/cobra

フラグ処理やサブコマンド,ヘルプメッセージ,インテリジェントな提案,アプリケーション用に自動的に生成されたbashオートコンプリートなど,CLI ツールに必要なことはカバーできてしまいます. kubectlfaas-cli にも実際に使われています.
Cobraの構造の理想は以下のような実装です.

  ▾ appName/
    ▾ cmd/
        add.go
        your.go
        commands.go
        here.go
      main.go

一つのファイルにまとめてしまうこともできます. Fizzbuzz をサンプルに追加したもの以下です.

package main

import (
        "fmt"
        "github.com/spf13/cobra"
        "strconv"
        "strings"
)

func fizzbuzz(max int) {
        for i := 0; i <= max; i++ {
                fizz := i%3 == 0
                buzz := i%5 == 0
                switch {
                case fizz && buzz:
                        fmt.Println("fizzbuzz")
                case fizz && !buzz:
                        fmt.Println("fizz")
                case !fizz && buzz:
                        fmt.Println("buzz")
                default:
                        fmt.Println(i)
                }
        }
}

func main() {
        var echoTimes int

        var cmdPrint = &cobra.Command{
                Use:   "print [string to print]",
                Short: "Print anything to the screen",
                Long: `print is for printing anything back to the screen.
For many years people have printed back to the screen.`,
                Args: cobra.MinimumNArgs(1),
                Run: func(cmd *cobra.Command, args []string) {
                        fmt.Println("Print: " + strings.Join(args, " "))
                },
        }

        var cmdEcho = &cobra.Command{
                Use:   "echo [string to echo]",
                Short: "Echo anything to the screen",
                Long: `echo is for echoing anything back.
Echo works a lot like print, except it has a child command.`,
                Args: cobra.MinimumNArgs(1),
                Run: func(cmd *cobra.Command, args []string) {
                        fmt.Println("Print: " + strings.Join(args, " "))
                },
        }

        var cmdTimes = &cobra.Command{
                Use:   "times [# times] [string to echo]",
                Short: "Echo anything to the screen more times",
                Long: `echo things multiple times back to the user by providing
a count and a string.`,
                Args: cobra.MinimumNArgs(1),
                Run: func(cmd *cobra.Command, args []string) {
                        for i := 0; i < echoTimes; i++ {
                                fmt.Println("Echo: " + strings.Join(args, " "))
                        }
                },
        }

        var cmdFizbuzz = &cobra.Command{
                Use:   "fizzbuzz [int]",
                Short: "return Fizzbuzz",
                Long: `echo things multiple times back to the user by providing
a count and a string.`,
                Args: cobra.MinimumNArgs(1),
                Run: func(cmd *cobra.Command, args []string) {
                        var m int
                        m, _ = strconv.Atoi(args[0])
                        fizzbuzz(m)
                },
        }

        cmdTimes.Flags().IntVarP(&echoTimes, "times", "t", 1, "times to echo the input")

        var rootCmd = &cobra.Command{Use: "app"}
        rootCmd.AddCommand(cmdPrint, cmdEcho, cmdFizbuzz)
        cmdEcho.AddCommand(cmdTimes)
        rootCmd.Execute()
}

使ってみる

$ ./appName -help                                                                                                                                                                                                               
Error: unknown shorthand flag: 'e' in -elp
Usage:
  app [command]

Available Commands:
  echo        Echo anything to the screen
  fizzbuzz    return Fizzbuzz
  help        Help about any command
  print       Print anything to the screen

$ ./appName fizzbuzz 15                                                                                                                                                                                                         
fizzbuzz
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz

spf13/viper

yaml, toml などの設定ファイル・環境変数・フラグなどの設定値を透過的に扱えるようにするライブラリ. めちゃくちゃに便利

spf13/pflag

置き換え実装 cobraの中身はこれ

morikuni/aec

出力に色を付ける.

最後に

私がCLIツールを作るときはCobraに全面的に従うことが多いのですし困ったことはありません. もしかしたらもっと素晴らしい方法があるかもしれませんが....