これは Go Advent Calendar 2018の11日目の記事です。
去年はgolangでTwitterクライアント「tt」を作りました。その tt は今でも気軽にツイートするときに使用しています。最近あまりメンテをしていないので近いうちに機能を追加していきたいところです。
今回もコマンドラインツールを作りました。esaのコマンドラインツール myesa です。
myesa
esaのコマンドラインツール myesa はesaのドキュメントの検索と作成、更新が出来るコマンドラインツールです。
tt と同様 go get と go install でインストールできます。インストール後は myesarc.json を$HOME 直下に作ります。次のようなjsonファイルを作成します。
{ "ACCESS_TOKEN" : "access token", "TEAM" : "team name" }
検索
myesa でドキュメントを検索してみます。 myesa search test と打ち込みます。
$ myesa search test https://example.esa.io/posts/1021 2018-12-10T18:37:20+09:00 Others/nasumノート/testtest https://example.esa.io/posts/1004 2018-12-06T13:14:06+09:00 Others/nasumノート/test (1) https://example.esa.io/posts/1003 2018-12-06T13:13:03+09:00 Others/nasumノート/test
記事のタイトルに test がついている記事が検索されます。今は記事のタイトルを検索対象にしていますがこれだけだとちょっと検索の機能としては微妙なのでもう少し修正したいところです。
表示
記事を表示してみます。 myesa show /カテゴリ/記事名 と打ち込みます。
$ myesa show Others/nasumノート/testtest
## hogehoge
fugafuga
記事のテキストがマークダウンで表示されます。
記事の作成・更新
記事を作成してみます。 myesa edit /カテゴリ名/記事名 と打ち込みます。実行するとデフォルトのエディタが起動しテキストを編集できます。マークダウンでテキストを作成したあとエディタを終了すると記事が作成されます。
$ myesa edit Others/nasumノート/testtest
https://scouty.esa.io/posts/1021
終了した後は記事のURLが出力されます。
編集に関しても同様に myesa edit /カテゴリ名/記事名 と打ち込むことで記事をesaから取得し編集できます。
使用したライブラリ等
使用したライブラリは以下です。
- https://github.com/spf13/cobra
- https://github.com/upamune/go-esa
- https://github.com/fatih/color
- https://github.com/spf13/viper
golang製のAPIライブラリは go-esa が使いやすいです。あまりメンテはされていないのですがesaのAPI自体それほど変わっていないため問題なく使用することが出来ます。
ほかの cobra color viper コマンドラインツールを作る際の鉄板ライブラリです。この3つと他のAPIライブラリを使えばコマンドラインでクライアントが簡単に作れます。
工夫したところ
記事の編集
esaから記事を取得し編集する時、一時ファイルを作成しそこに一度テキストを流し込んでから編集するようにしています。
func execEditor(editor string, body string) string {
file, err := os.OpenFile("__tmp__", os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
log.Fatal(err)
return ""
}
if body != "" {
fmt.Fprintln(file, body)
}
defer os.Remove(file.Name())
cmdstr := fmt.Sprintf("%s __tmp__", editor)
cmd := exec.Command("/bin/bash", "-c", cmdstr)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err = cmd.Run()
if err != nil {
log.Fatal(err)
return ""
}
data, err := ioutil.ReadFile("./__tmp__")
if err != nil {
log.Fatal(err)
return ""
}
return string(data)
}
一時ファイルは記事編集後に削除しています。
ここのあたり工夫したと書きましたが正直いけていない気がしていて、一時ファイルなど作らずにうまいことやる方法があるんじゃないかと思ったりしています。力及ばずごり押しで作っています。git commit --amend のような動作イメージだったのですが動きだけ見ればうまくいった感じです。
esaの記事を名前で取得
esaのAPIで、記事はidを指定すれば特定の記事を取得できるのですが、カテゴリとタイトル指定では取れません。今回のコマンドラインツールでは記事を検索した結果を使って記事の編集を行いたかったので、カテゴリとタイトルで記事を取得できる必要がありました。
なので記事の検索機能をうまく使って特定します。esaの検索クエリには in と name でカテゴリとタイトルを指定することが出来ます。
次のコマンドで記事を取得し編集することが出来ます。
$ myesa edit Others/nasumノート/testtest
Others/nasumノート/testtest は Others/nasumノート/ testtest にパースされ、in:Others/nasumノート/ name:testtestで検索されます。これでも前方一致の検索なので特定の1記事にはならないのですが、必要には足りると判断していったんこのままにしています。
まとめ
まだ実装や挙動がこなれていないのですが、必要最低限の動作はするように出来ました。
まだやりたいことはいっぱいあります。さしあたって検索から記事の編集までインタラクティブに出来るようにしたり、dockerのコマンドのように出力のフォーマットをオプションで指定できるようにしたいですね。
何かまずそうなことがあればプルリクなどしてもらえるとありがたいです。