じゃあ、おうちで学べる

思考を呼び覚ます このコードに、君は抗えるか。

Go言語のCLI作成ツールであるcobra のシェル補完の生成があまりにも簡単

概要

Goでコマンドラインツールを作成する場合の選択肢としてspf13/cobraがあると思いますが、遂にv1.2.0 がリリースされました👏👏👏。大きな機能追加として completion が追加され、大枠の使い方とシェル補完の生成についてこのブログではやっていくメモ書きになってます。それ以上に言及しようと思ったのですが完全に体力不足でーす。

やっていく

install

CLIがあるので利用するさまざまな日本語での入門記事がcobra には存在するので詳しくはその辺を参照してください。ちなみに、公式ドキュメントが最高で公式ドキュメントに誤りがあればコントリビューションのチャンス。

$ go get -u github.com/spf13/cobra

って思ったら雑な備忘録を自分も書いてましたが一切の参考にならん syu-m-5151.hatenablog.com

init

コマンドラインツールの初期化を行う

$ cobra --viper=false init --pkg-name github.com/nwiizo/workspace_2021/blog/cobra_generating_shell_completions

main.go -> cmd.Execute() -> cmd/root.go の rootCmd.Execute() の順番で実行されるのでそれらに準ずるように実装していくのですがその辺も他の最高の入門記事があると思うので参照してください。

package main

import "github.com/nwiizo/workspace_2021/blog/cobra_generating_shell_completions/cmd"

func main() {
    cmd.Execute()

実際に実装する際にはcobra/user_guide.md at master · spf13/cobra · GitHubをやっていきましょう

add fizzbuzz

サブコマンドの追加をしたい時にはcobra add を実行していく。

$ cobra add fizzbuzz
fizzbuzz created at /*****/workspace_2021/blog/cobra_generating_shell_completions

サブコマンドが実装されました。

$ go run main.go fizzbuzz
fizzbuzz called

cmd/fizzbuzz.go が追加されるのでこちらに実装を追加していけば良い。init()->rootCmd.AddCommand(fizzbuzzCmd) は自動生成されるのでfizzbuzzCmdの中身を改修すれば実装できる。そして、実装したのが下記になる。

package cmd

import (
    "fmt"
    "strconv"

    "github.com/spf13/cobra"
)

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

// fizzbuzzCmd represents the fizzbuzz command
var fizzbuzzCmd = &cobra.Command{
    Use:   "fizzbuzz [int]",
    Short: "return Fizzbuzz",
    Long: `return Fizzbuzz

return Fizzbuzz There is no particular reason because it is a suitable sample`,
    Run: func(cmd *cobra.Command, args []string) {
        fmt.Println("fizzbuzz called")
        var m int
        m, _ = strconv.Atoi(args[0])
        fizzbuzz(m)
    },
}

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

補完のためにcompletion fish を行う

補完するためにはgo run main.go で実行するわけにはいかないのでビルドを行う。

go build .

rootCmd.CompletionOptions.*** 以下に設定を入れれば設定の変更を行うことができます。デフォルトではcompletionは有効なのでfish に読み込ませて、実際にコマンドを実行。

$ ./cobra_generating_shell_completions completion fish | source
$ ./cobra_generating_shell_completions [tab]
completion  (generate the autocompletion script for the specified shell)  fizzbuzz  (return Fizzbuzz)  help  (Help about any command)

一瞬で補完させることができ、あまりの素晴らしさに膝から崩れ落ちた。 補完させないようにしたり、その他のもろもろに関してはcobra/shell_completions.md at master · spf13/cobra · GitHubを読んでいけば実装できると思う。 また、これらの補完と配置はMakefileに書いておけば良いかなって思いましたが、7月18日の JTF2021に登壇するからそう思うだけなのか。。。

docs.google.com

最後に

cobraは入門記事が溢れているがツールとして日々アップデートされているので公式を見るのがいいなぁと自分の過去の記事を読みながら思いました。 リリースノートに記載があると思うが変更点や実装などはこの辺を読むと良いのでぜひに〜 github.com