Comments先日、SPMというコマンドラインツールをリリースしましたが、golangでコマンドラインツールを作成する上で便利だったツールや考え方等を備忘として残します。Partyのライブラリを利用せずとも標準のflagパッケージで処理を書けますが、色々と面倒なのでurfave/cliのパッケージを利用しました。このパッケージは以下のように、簡単にサブコマンドやフラグを定義できます。app.Run(args)非常に使いやすいライブラリなのですが、エラーハンドリングはやや柔軟性に劣る印象です。ライブラリの使い方としては、Actionの関数の戻り値にerrorを入れれば良いのですが、その場合、HandleExitCoderが呼び出され、fmt.Fprintfで標準エラー出力にエラーメッセージを出力するとともに、os.Exitされてしまいます。コマンドラインでの挙動を柔軟にしたい場合は、cliのインスタンスをラップし、独自にエラー変数を用意して、それを返す方が良さそうです。errはAction内でセット}YAMLのロード設定のロードでYAMLを利用する際はgopkg.in/yaml.v2を使います。使い方はxmlやjsonのUnmarshalと同じく、structを定義してマッピングします。PartyのSirupsen/logrusを使いました。os.Stderrlogger.Info("aaabbb")}のような使い方でもOK。前者の方法は一つのチャネルにしかロギングできませんが、後者の方法であれば複数のloggerインスタンスを作成できるため、複数のチャネル(例えばstdoutとstderr)にロギングすることができます。実際には、このloggerを直接使うのではなくラップした独自のloggerを定義して利用した方が変更に強い実装になりそうです。テストDIの話と同様に、入出力のストリームを置き換えできるようなインターフェースにしておくとテストが楽です。CLIの場合は入力のストリームはコマンドライン引数であり、出力ストリームは標準出力になります。これらをテスト時には文字列の配列、Bufferに置き換えることになります。SPMだとロガーのデフォルトはStdout、Stderrにしており、テスト時はbytes.Bufferに書き込むようにしています。StdoutはFileの型なので、コマンド利用時とテスト時の両方に適用できる型として、io.Writerのインターフェースを指定していることに注意してください。errStream}またテストはstretcher/testifyのライブラリを利用するとアサーションが楽です。