docker pullをちょっとだけ楽にするCLIつくりました

## つくったもの

dockerのimageからtagを検索&選択してpullできるCLI

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">Goでつくった人生初のCLIツール <br>(docker pull をちょっとだけ楽にする) <a href="https://t.co/F7qA86Inmp">pic.twitter.com/F7qA86Inmp</a></p>&mdash; kohbis (@kohbis) <a href="https://twitter.com/kohbis/status/1208699098351620097?ref_src=twsrc%5Etfw">December 22, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

※動画の圧縮になれておらず、、画質が悪いです。。

## バージョン等

- Go 1.13.5 
- [spf13/cobra](https://github.com/spf13/cobra) ... CLIアプリケーションのライブラリ。
- [manifoldco/promptui](https://github.com/manifoldco/promptui) ... 対話型プロンプトのライブラリ。
- macOS Catalina 10.15.1
- Docker version 19.03.5


Goの経験は、以前ポストした[Lチカセブン](https://qiita.com/kohbis/items/ff17c8c12fa82ee77707#go)くらいでほぼ触ったことがありません。
「shellなら楽じゃん」と言われそうですが、今回は **Dockerのアドベントカレンダー** 。 
必然的にDockerの開発言語であるGo言語を使うしかありません！

CLIのライブラリは、[urfave/cli](https://github.com/urfave/cli)も情報がたくさんありました。
しかし、今回は **Dockerのアドベントカレンダー** 。 
必然的にDockerに採用されているcobraを使うしかありません！

## ソース

https://github.com/kohbis/dimg

※ 201919/12/22時点では、公式イメージ(library)だけ対応しています。

## ポイント

### タグ一覧取得

curlコマンドだと、下記でタグ一覧が取得できます。
（後述の公式ドキュメント参照）

```terminal
curl -s https://registry.hub.docker.com/v2/repositories/library/alpine/tags/ | jq -r '.results|.[]|.name'
```

返ってくるJSONを、Goの構造体で表すとこうなります。
JSON->Structには、[JSON-to-Go](https://mholt.github.io/json-to-go/)というサイトが、とても便利でした。

```golang
type Tags struct {
	Count    int         `json:"count"`
	Next     string      `json:"next"`
	Previous interface{} `json:"previous"`
	Results  []struct {
		Name     string `json:"name"`
		FullSize int    `json:"full_size"`
		Images   []struct {
			Size         int         `json:"size"`
			Digest       string      `json:"digest"`
			Architecture string      `json:"architecture"`
			Os           string      `json:"os"`
			OsVersion    interface{} `json:"os_version"`
			OsFeatures   string      `json:"os_features"`
			Variant      interface{} `json:"variant"`
			Features     string      `json:"features"`
		} `json:"images"`
		ID                  int         `json:"id"`
		Repository          int         `json:"repository"`
		Creator             int         `json:"creator"`
		LastUpdater         int         `json:"last_updater"`
		LastUpdaterUsername string      `json:"last_updater_username"`
		ImageID             interface{} `json:"image_id"`
		V2                  bool        `json:"v2"`
		LastUpdated         time.Time   `json:"last_updated"`
	} `json:"results"`
}
```

このままだと1ページあたり10件しか取得できないため `Next` に次ページのURLがnullにならない限りループして、、、という面倒くさいことになります。
そのため、最初からクエリパラメータ `?page_size=10000` をつけて取得しています。
（そんなにタグ数があるイメージってあるのかしら）

### タグ検索

promptuiは自前のsearcherを実装することができます。（感動）
これにより、マイナーバージョンが多い言語の実行環境イメージも見つけやすくなっています。

```terminal
$ go run main.go
Image Name: ruby
Searching "ruby" tags...
"ruby" has 615 tags.
Search: 2.6.█
? Select Tag:
  ▸ 2.6.5-stretch
    2.6.5-slim-stretch
    2.6.5-slim-buster
    2.6.5-slim
↓   2.6.5-buster
```

cobraも、promptuiも色々できることがありそうなので、今後拡張していきたいです。

## まとめ

**Docker** アドベントカレンダー担当日の1日前に思いたったのですが、ライブラリが非常に強力で１日かからずにものをつくることができました！

今回作ったものは足りないところがたくさんありますが、実際つくってみると個人的には欲しい機能がどんどん思いついていきたので、今後継続的に開発していきたいと思います。

実は今年最初やりたいことのひとつに「CLIツールをつくる」がありまして、ぎりぎり達成することができたのでよかったです！！
（この記事を書いている最終に思い出しました笑）


## 参考

[Examples using the Docker Engine SDKs and Docker API](https://docs.docker.com/develop/sdk/examples/)
[How do I authenticate with the V2 API?
](https://success.docker.com/article/how-do-i-authenticate-with-the-v2-api)

[どうでもいいからささっとGoでCLIつくりたいとき](https://qiita.com/usk81/items/df68a00c898b145faee5)
[Go初心者がGoでコマンドラインツールの作成に挑戦した話](https://www.slideshare.net/dcubeio/gogo-81497334)