Edited at

spf13/cobraで作ったCLIツールのbash/zsh補完スクリプトを自動生成する


はじめに

GoでCLIツール作るのにフレームワークとして spf13/cobra が便利なのでよく使ってます。

そんなcobraですが、よく見るとbash/zsh補完スクリプトの自動生成が意外と簡単にできることに気づいたので、やり方を共有しておきます。


環境

手元の環境は以下のとおりです。


  • macOS 10.14

  • zsh 5.3

  • bash 3.2

  • Go 1.12

  • cobra 0.05


補完スクリプトを生成するコマンドを生やす

completionというサブコマンドを生やして、その下にさらにbashとzshコマンドを生やします。

イメージとしてはこんなかんじ。ここではコマンド名を hoge とします。

hoge completion bash

hoge completion zsh

コードはこんなかんじ。

package cmd

import (
"os"

"github.com/spf13/cobra"
)

func init() {
RootCmd.AddCommand(newCompletionCmd())
}

func newCompletionCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "completion",
Short: "Generates shell completion scripts",
Run: func(cmd *cobra.Command, args []string) {
cmd.Help()
},
}

cmd.AddCommand(
newCompletionBashCmd(),
newCompletionZshCmd(),
)

return cmd
}

func newCompletionBashCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "bash",
Short: "Generates bash completion scripts",
Run: func(cmd *cobra.Command, args []string) {
RootCmd.GenBashCompletion(os.Stdout)
},
}

return cmd
}

func newCompletionZshCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "zsh",
Short: "Generates zsh completion scripts",
Run: func(cmd *cobra.Command, args []string) {
RootCmd.GenZshCompletion(os.Stdout)
},
}

return cmd
}


補完スクリプトを読み込む

生成されるスクリプト自体は、とりあえず標準出力に垂れ流してあるので、zshならfpathが通ってる適当なところに保存します。

Homebrewでzsh-completionsを使ってる場合、 /usr/local/share/zsh/site-functions/_hoge に保存しておけば自動で読み込まれます。

$ hoge completion zsh > /usr/local/share/zsh/site-functions/_hoge

普段zsh使ってるのでbashはあんまり良くわかってませんが、Homebrewのbash-completionを使ってる場合は、 /usr/local/etc/bash_completion.d/hoge に置いておけば良さそうです。


HomebrewのFormulaで自動インストールする

CLIツール自体を既にHomebrewで配布している場合は、バイナリのインストール時に自動で補完スクリプトも仕込んであるとうれしいですね。

あらかじめリポジトリにコミットしてあるファイルを配布するだけなら、 単純に zsh_completion.install とかでいけるっぽいのです。が、動的に生成したファイルを登録する方法がわからず、ちょっと悩みました。

そういえば kubectl もcobraだったなと思い出し、 kubectlのformula を参考に、こんなかんじにしておけば良さそうです。

class Hoge < Formula

desc "Hoge"
homepage "https://github.com/minamijoyo/hoge"
url "https://github.com/minamijoyo/hoge/releases/download/v0.0.1/hoge_v0.0.1_darwin_amd64.tar.gz"
version "0.0.1"
sha256 "xxxxxx"

def install
bin.install "hoge"
output = Utils.popen_read("#{bin}/hoge completion bash")
(bash_completion/"hoge").write output
output = Utils.popen_read("#{bin}/hoge completion zsh")
(zsh_completion/"_hoge").write output
end
end


おわりに

cobraのドキュメントを見ると、もうちょっとカスタマイズできるっぽいのですが、まだいろいろ発展途上のようです。

Generating Zsh Completion for your cobra.Command

ただTabでサブコマンドや引数の補完が出るだけでも十分快適です。

わりと簡単に実装できてコスパがよいので、cobraで自作のCLIツール作ってる人は補完できるようにしてみるとよいんではなかろうか。