LoginSignup
3
1

More than 5 years have passed since last update.

dockerでも使用されている「spf13/cobra」を用いてCLIを作成してみた

Posted at

今回作成してみたのは新規作成ではなく、過去に投稿した「任意の文字列や行をハイライトするツールをGo言語で作成してみた」で作成した、テキストをハイライトするコマンドを「cspf13/cobra」を用いて実装し直したものです。

実装に用いた「cspf13/cobra」は、CLI作成用パッケージです。これは、「docker」などでも用いられているとても便利なパッケージで簡単にCLIを作成することができます。

作成したCLIは指定した文字列を含む行や文字列を色付けしたり、太字や斜体にしたりして、テ
キストを見やすくすることを目的としています。

指定した文字列を含む行をマーキング

line command

行番号を指定してマーキング

number command

作成したCLIは https://github.com/x-color/mkr に置いてありますので、ご自由にお使いください。

以下では、作成時に詰まったフラグのソートや、前回使用した「urfave/cli」よりも楽にできる設定ファイル関連の実装部分などを紹介していきます。

フラグのソート機能のオフ

作成時に少し困ったのは、フラグのソート機能がデフォルトでオンになっている点でした。
これによって、フラグのグループに沿って表示順を決めることができません。

表示順を自分で決めたい場合、このソート機能をオフにする必要があります。
以下のようにすることでオフにすることができます。

// サブコマンドにも継承されるフラグ(グローバルフラグ)のソートを無効にする
cmd.PersistentFlags().SortFlags = false
// 親コマンドから継承されたフラグ(グローバルフラグ)のソートを無効にする
cmd.InheritedFlags().SortFlags = false
// フラグの種類を混同したソートを無効にする
cmd.Flags().SortFlags = false

cmd.Flags().SortFlags = falseがわかりにくいと思いますが、以下の例を見てください。

// 継承するフラグ
cmd.PersistentFlags().StringP("C-global", "C", "", "")
cmd.PersistentFlags().StringP("B-global", "B", "", "")
cmd.PersistentFlags().StringP("A-global", "A", "", "")
// 継承しないフラグ
cmd.Flags().StringP("C-local", "c", "", "")
cmd.Flags().StringP("B-local", "b", "", "")
cmd.Flags().StringP("A-local", "a", "", "")

と用意した際に、

cmd.Flags().SortFlags = true

と設定すると以下のように表示されます。

コマンドのヘルプメッセージ
Flags:
 --A-global
 --A-local
 --B-global
 --B-local
 --C-global
 --C-local

逆に

cmd.Flags().SortFlags = false

と設定すると

コマンドのヘルプメッセージ
Flags:
 --A-global
 --B-global
 --C-global
 --A-local
 --B-local
 --C-local

のように表示されます。
cmd.Flags().SortFlags = falseを設定することで、フラグの種類(継承するフラグかどうかなど)が混合することを防いでくれます。

設定ファイルを用いたフラグの初期値カスタム機能の作成

「spf13/cobra」のREADME内でも書かれていますが、設定ファイル関連のパッケージである「spf13/viper」を用いることでとても簡単に実装することができます。
前に使用したパッケージだと結構苦戦したのですが、今回は用意されている設定ファイル用のパッケージが強力なのでしたいことが楽に実装できました。

// エラー処理などは省略
func readCfgFile(cfgFile string) {
    viper.SetConfigFile(cfgFile)
    viper.ReadInConfig()    
}

以上のコードだけで、cfgFile内のデータを読み取りviperが管理してくれます。
読み取ったデータは、

viper.GetString("data")

などで、読み出すことができます。

コマンドのフラグの初期値を外部の設定ファイルで指定可能にしたい場合は、

// viper内で管理している'data'に紐付いたデータとコマンドの'flag'フラグを紐付ける
viper.BindPFlag("data", cmd.Flags().Lookup("flag"))
data := viper.Get("data")

のようにしておくと、実行時に以下のようになります。

$ cmd
# data = 'cfgFile内で設定された値' (フラグを指定しない場合)

$ cmd --flag test-data
# data = 'test-data' (フラグを指定した場合)

これで、フラグの初期値を外部ファイルでカスタムできるようになります。

参考にしたサイト

コマンド作成全般
- 「spf13/cobra」のREADME
- 「spf13/cobra」のGoDoc
- 「Golangのコマンドライブラリcobraを使って少しうまく実装する

設定ファイルに関して
- 「spf13/viper」のREADME
- 「spf13/viper」のGoDoc

ソートのオンオフに関して
- 「spf13/pflag」のGoDoc

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1