$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

flycheck-gometalinterを利用して、EmacsでGoのシンタックスチェックや型チェックを行う

今までgolangシンタックスや型のエラーがあった時にEmacsに表示するために、flycheck標準のgo用のcheckerを利用していた。しかし、これがだんだん遅くなってきて、結構いらつく感じになってきた。そこで、flycheck-gometalinterを使ったら解決したのでメモ。

flycheck-gometalinterとは

flycheck-gometalinter とは、gometalinterシンタックスやlintのチェックをした結果を、Emacsのflycheckのインターフェースで表示してくれるもの。gometalinterはgolangのいろんなlintツール(例えばgofmtとかvetとかgotypeとか)を統合してlintを行ってくれるので、柔軟に設定して利用することができる。

flycheck-gometalinterを利用するように設定する

まずflycheck-gometalinterをインストールする。

M-x package-install RET flycheck-gometalinter

そして、重くならないようにfastオプションを付けるのと、テストファイルでも利用するようにelispで設定する。

(require 'flycheck-gometalinter)
(flycheck-gometalinter-setup) ;; flycheckのcheckerのリストにgometalinterを追加
(setq flycheck-gometalinter-fast t) ;; only run fast linters
(setq flycheck-gometalinter-test t) ;; use in tests files
(add-hook 'go-mode-hook 'flycheck-mode) ;; go-modeでflycheckを利用するように

これだけで設定が終わり。

これをしておくだけで、シンタックスエラーや型エラーなどがあった時に、flycheckがその行にエラー表示をしてくれる。


便利。

なぜデフォルトのgo-modeのcheckerが利用されなくなるか

なぜflycheck-gometalinter-setupをするだけで、デフォルトのgo-modeのcheckerが利用されなくなるのだろうと疑問だった。それでドキュメントを見て見ると、

http://www.flycheck.org/en/latest/user/syntax-checkers.html#select-syntax-checkers-automatically

Flycheck picks the first syntax checker from this list which exists and supports the current major mode, and runs it over the current buffer.

と書かれていて、つまりgo-modeに紐づく最初のcheckerが利用されることが分かった。

さらにflycheck-gometalinter-setupのコード( https://github.com/favadi/flycheck-gometalinter/blob/c90ea1aba80ddfdf603c9ba731be302400fd6ba2/flycheck-gometalinter.el#L119 )を読むと、flycheck-checkersにgometalinterをadd-to-listしている。これによって、flycheck-checkersの一番最初にgometalinterが入るため、gometalinterがgo-modeに紐づく最初のcheckerとなる。

以上から、gometalinterのみピックアップされ、デフォルトのcheckerが利用されなくなるということが分かった。

まとめ

今回はflycheck-gometalinterを利用して、golangシンタックスチェックや型チェックなどを行うように設定してみた。デフォルトのcheckerを利用すると、かなりCPUが回っていたが、この設定をすることで快適に編集できるようになったので良かった。

Kindleまとめ買いセールでHUNTERxHUNTER買った

Kindle本 電子書籍 | Amazon | アマゾン

Kindleまとめ買いで、20%オフになるセールがやっていた。10/11まで。

僕は久しぶりにHUNTERxHUNTERを読みたいと思って、そういえばKindleで持っていないと思い出したので、この期に全巻買ってみた。週末に一気に読んだけど、やっぱり面白い。個人的にはグリードアイランド編が好き。

他にもいろいろ売っていたけど、個人的には

あたりがおすすめ。特にキングダムは最高に面白い。

[asin:B072KRPRGX:detail]

goxc + ghrを使って、Goで書いたツールのバイナリをGithub Releasesで配布する

先日の goreleaserを使ってGoで書いたツールのバイナリをGithub Releasesで配布する - $shibayu36->blog; で、Goツールのバイナリ配布ができるようになった。しかし、アーカイブ周りの処理が少し期待と違い、作成したzipをunzipコマンドで取り出すとファイルのアクセス権がおかしくなり、バイナリに実行権限がつかなくなるという問題が起こった。これは困る。

goreleaserを深追いをしても良いけど、ひとまず別の方法も試してみようと思って、goxc + ghrを使うようにしてみた。これがうまくいったので、メモしておく。

今回のコードは以下のところで確認できる。

バイナリをリリースする作戦

バイナリをリリースする方法はいろいろあるが、今回はgoxcghr を使うことにした。

goxcはクロスコンパイル、アーカイブ、リリースなどなんでもできるツール。使い方はgoxc -helphttps://github.com/laher/goxc/wiki を見るのが良いだろう。ghrはGithub Releasesへのリリースを行うツール。使い方は 高速に自作パッケージをGithubにリリースするghrというツールをつくった | SOTA が詳しい。


goxcを使えばGithub Releasesにリリースするまで一気通貫で出来るはずなのだが、ghrが非常に便利なので、以下のような使い分けをすることにした。

  • goxcはクロスコンパイルやアーカイブなど、成果物を作るために利用する
  • ghrは成果物をGithub Releasesにアップロードするために利用する

こうしておけば、例えばGithub Releasesじゃないところにアップロードしたくなったとしても、ghrの部分を置き換えれば良いだけになる。

goxcとghrをインストールする

先にgo getでインストールしておく。

$ go get -v -u github.com/laher/goxc
$ go get -v -u github.com/tcnksm/ghr

goxcで成果物を作成する

まずgoxcで成果物を作成する設定を行う。

作りたい成果物

作りたい成果物は以下のようなものとする。

  • windows/darwin/linuxamd64/386用バイナリを作る(6プラットフォーム分)
  • すべてzipで固め、その中にはバイナリとREADME.md、LICENSEファイルを入れる

.goxc.jsonで成果物作成ルールを作る

以上の成果物を作るには、.goxc.jsonを作り、成果物作成ルールを作っておくと良い。

まず、コマンドから雛形を作る。-wcコマンドを使うと、コマンド引数を考慮した.goxc.jsonを作ってくれる。

$ goxc -os="linux darwin windows" -arch="386 amd64" -d=dist -tasks="clean-destination,xc,archive-zip,rmbin" -wc
# -osでビルドするOSを、-archでビルドするArchを設定
# -dで成果物配置場所を指定
# それぞれのタスクは
#   - clean-distinationは成果物を配置するディレクトリを先にrmするタスク
#   - xcはクロスコンパイルするタスク
#   - archive-zipは成果物をzip圧縮するタスク
#   - rmbinは成果物ディレクトリからバイナリを消すタスク
#     - zip内に既にバイナリが入っているため消して良い
# 最後に-wcで引数の設定で設定ファイルに書き出し

すると以下のような設定ができる。

{
    "ArtifactsDest": "dist",
    "Tasks": [
        "clean-destination",
        "xc",
        "archive-zip",
        "rmbin"
    ],
    "Arch": "386 amd64",
    "Os": "linux darwin windows",
    "ConfigVersion": "0.9"
}

しかし、archive-zipというタスクはデフォルトだとlinuxの成果物をzip圧縮してくれない。このままだとうまくいかない。

これをなんとかするために、goxc -help archive-zipでarchive-zipのヘルプを見てみると、platformsというオプションでどのプラットフォームをzip圧縮するか設定できることが分かった。また、include-top-level-dirというオプションで、ディレクトリごとzipで固めるかを設定できた。そこで、.goxc.jsonを書き換えて以下のように変更する。

{
	"ArtifactsDest": "dist",
	"Tasks": [
		"clean-destination",
		"xc",
		"archive-zip",
		"rmbin"
	],
    "TaskSettings": {
        "archive-zip": {
            "include-top-level-dir": "windows darwin linux",
            "platforms": "windows darwin linux"
        }
    },
	"Arch": "386 amd64",
	"Os": "linux darwin windows",
	"ConfigVersion": "0.9"
}

あとはREADME.mdとLICENSEファイルをzipに含める設定だが、goxcはデフォルトでINSTALL*,README*,LICENSE*というルールのファイルをアーカイブに含めてくれるため、明示的に設定しなくても良い。

成果物を生成する

あとはgoxcコマンドを打つだけ。

$ goxc
$ tree dist
dist
└── snapshot
    ├── shibayu36_darwin_386.zip
    ├── shibayu36_darwin_amd64.zip
    ├── shibayu36_linux_386.zip
    ├── shibayu36_linux_amd64.zip
    ├── shibayu36_windows_386.zip
    └── shibayu36_windows_amd64.zip
$ unzip dist/snapshot/shibayu36_darwin_amd64.zip
Archive:  dist/snapshot/shibayu36_darwin_amd64.zip
  inflating: shibayu36_darwin_amd64/shibayu36
  inflating: shibayu36_darwin_amd64/README.md
  inflating: shibayu36_darwin_amd64/LICENSE
$ ls -l shibayu36_darwin_amd64
total 7120
-rw-r--r--  1 shibayu36  staff      560 Oct  8 17:30 LICENSE
-rw-r--r--  1 shibayu36  staff      400 Oct  8 17:30 README.md
-rwxr-xr-x  1 shibayu36  staff  3637000 Oct  9 01:11 shibayu36

期待通りに成果物が作成できた。

ghrでGithub Releasesに成果物をアップロードする

あとはこのdist/snapshot/以下に存在するファイルをすべてGithub Releasesにアップロードすれば良い。これはghrを使えば簡単に行える。

例えば、shibayu36ユーザのshibayu36レポジトリに、v0.0.7というリリースタグ名でdist/snapshot/以下のファイルをアップロードするには、以下のようなコマンドを発行するだけで良い。

$ GITHUB_TOKEN=... ghr -u shibayu36 -r shibayu36 v0.0.7 dist/snapshot/

あとは、goxcして、一番最新のgitのタグ名を使ってghrで上げるというスクリプトを用意しておけば、簡単にリリースができるようになる。次のとおり。

script/release

#!/bin/sh

# Usage: GITHUB_TOKEN=... script/release
set -e
latest_tag=$(git describe --abbrev=0 --tags)
goxc
ghr -u shibayu36 -r shibayu36 $latest_tag dist/snapshot/

これで手元からクロスコンパイルしてGithub Releasesにアップロードするには、タグを打ってscript/releaseすれば良いだけとなった。

$ git tag vx.y.z
$ GITHUB_TOKEN=... script/release

TravisCIを使い自動で成果物をアップロードする

これまででとりあえずやりたいことはできた。しかし、やはりTravisCIで自動で成果物生成とアップロードを行えるようにしておきたい。

これまでの設定と簡単なMakefileさえあれば、非常に簡単に設定できる。

Makefile

setup:
	go get -v -u \
		github.com/Masterminds/glide \
		github.com/laher/goxc \
		github.com/tcnksm/ghr

deps: setup
	glide install

test: deps
	go test -v $$(glide novendor)

.PHONY: setup deps test

.travis.yml

language: go
go:
  - 1.9
script:
  - make test
after_success:
  - test -n "$TRAVIS_TAG" && script/release

GITHUB_TOKEN環境変数も指定する必要はあるので、それは https://docs.travis-ci.com/user/environment-variables/#Defining-Variables-in-Repository-Settings あたりを見ながらTravisCI側で設定したら良い。


これでタグをpushした時にのみ、TravisCIでscript/releaseが動き、成果物生成からGithub Releasesへのアップロードまで自動で行われるようになった。自分がやるのはタグ付けだけとなる。

$ git tag vx.y.z
$ git push --tags

便利!!