【golang】vendoring時はビルドタグでのフィルタリングは使わない方がいい
English version:【golang】Don't use filtering by build tags to vendoring
TL;DR
govendor
ではvendoringする際に無視するビルドタグが指定できる- しかし、ビルドに必要なファイルがvendorディレクトリ配下にコピーされないケースがある
- 必要なファイルがコピーされないことにより、クロスコンパイルできなくなるといった問題が起こるかもしれない
- なので、vendorディレクトリのサイズは増えてしまうが、ビルドタグでのフィルタリングはしない方がシンプルで良い
Introduction
現在、Go言語には次のようにたくさんのパッケージ管理(vendoring)ツールがあります。
こちらのページでは他にもたくさんのツールが紹介されています。
PackageManagementTools · golang/go Wiki · GitHub
私はその中でも、govendor
をよく利用しています。
govendor
は簡単/手軽に利用できるため、これまでたくさんのプロジェクトで利用してきました。
でもある時、govendor
の設定次第では面倒な問題が発生することがわかりました。。。
What is the problem?
先月(2016/12)、Terraformに対して以下のPullRequestを作成しました。
このPRは、Arukasプロバイダを追加するものです。
この新しいプロバイダは以下のリポジトリにてサードパーティープラグインとしてリリース済みであったものを
Terraform本体に取り込んでもらうためのものでした。
このPRはすぐにマージされ、Terraform v0.8.3としてリリースされました。
しかしその時、、、
Windowsでビルドできなくなった!?!?
What's!? What's happened!?!?
Arukasプロバイダーはサードパーティープラグインとしてのリリース時にWindows版を含んでおり、(Windows上でも)問題なくビルドできていました。
Terraform本体に取り込んでもらう際、ソースコードへの変更は行われていないのに、なぜビルドが壊れてしまったのでしょうか?
Who broke the build on Windows?
原因を探るため、@jbardinからのメッセージで指摘されているライブラリgopkg.in/alecthomas/kingpin.v2
から調査を始めることにしました。
ライブラリgopkg.in/alecthomas/kingpin.v2
はArukasプロバイダによってimportされているものです。
このライブラリは、Arukasプロバイダをサードパーティープラグインとしてリリースしていた頃から利用しているため、Windowsでも問題なく利用できることが判明しています。
かつ、Terraform本体 / サードパーティープラグインとしてリリースしていたArukasプロバイダ共にvendoringにはgovendor
を利用しています。
このため、(govendor
によって)vendorディレクトリ配下にコピーされたgopkg.in/alecthomas/kingpin.v2
ライブラリのファイルを比較してみることにしました。
Compare gopkg.in/alecthomas/kingpin.v2
files under vendor directory
比較結果は以下の通りです。
guesswidth.go
がなんらかの理由でコピーされていないようです。
なぜでしょうか???
Answer: govendor
was setted to ignore some build tags
(Terraformにおける)govendor
の設定ファイルvendor/vendor.json
で以下のような設定が行われています。
https://github.com/hashicorp/terraform/blob/v0.8.4/vendor/vendor.json#L3
"ignore": "appengine test",
govendor
はvendor/vendor.json
の"ignore"に設定された各値とソースファイルの接尾詞 or ソースコード中のビルドタグを比較し、
対象のファイルを無視すべきか判定しています。
この設定ではappengine
とtest
というタグが無視対象として設定されているということです。
そして、今回コピーされていなかったguesswidth.go
のビルドタグは以下のようになっていました。
https://github.com/alecthomas/kingpin/blob/v2.2.3/guesswidth.go#L1
// +build appengine !linux,!freebsd,!darwin,!dragonfly,!netbsd,!openbsd
なお、*nix系プラットフォーム(Linx/BSD/MacOSなど)ではこのファイルの代わりにguesswidth_unix.go
が利用されます。
こちらのファイルのビルドタグは以下のようになっています。
https://github.com/alecthomas/kingpin/blob/v2.2.3/guesswidth_unix.go#L1
// +build !appengine,linux freebsd darwin dragonfly netbsd openbsd
これらのビルドタグが与えられている場合、(対象プラットフォームが)Windowsでのビルドではguesswidth.go
の方が利用されます。
しかし、vendor.json
の"ignore"にてappengine
が指定されているため、govendor
はguesswidth.go
を無視してしまうのです!!!
(日本語版注 : govendorはビルドタグを解析し、一つでもignoreに設定されたタグとマッチするタグが指定されている場合は該当ファイルをvendor配下にコピーしないのです)
この状況では、*nix系プラットフォームではビルド出来ても、Windowsではビルド出来ないのです。
ではどうすれば良いのでしょうか??
Conclusion
vendoring時にビルドタグでフィルタリングすることは、vendorディレクトリのサイズ削減ができるという利点はありますが、
いくつかのプラットフォームでビルドできなくなるといった問題が発生する可能性があります。
さらに、これらの問題解決の際は、importしている各ファイルのビルドタグの確認といった面倒な調査が必要になるでしょう。
このため、vendoring時のビルドタグによるフィルタは利用しない方が良いです。
(注:ただし、ignore
タグとtest
タグについてはフィルタしても問題なく動くと思います)
これらの問題があってもビルドタグによるフィルタリングを利用するユースケースはあるのでしょうか?
少なくとも私は思いつきませんでした。
あなたはどう思いますか?
もし良い方法があればこの記事にコメントをください!