読者です 読者をやめる 読者になる 読者になる

技術備忘記

日々調べたこととかとりとめなく

Goパッケージ依存管理最新事情

はじめに

Goの依存パッケージ管理といえば、以前から以下のような問題点が指摘されており、 総じてイマイチ、というのが通説である気がします。

  • 外部依存ライブラリのバージョン等が指定できないためビルドの再現性が保証されない
  • 複数prjの開発を同一環境で行う場合 GOPATH が汚染される、あるいは個別に切り替える必要があり面倒

こういった問題点を解消するため、バージョン1.6から(試験的には1.5から) Vendoring という機能が導入されました。 以前から存在しているパッケージ依存管理ツールもこの機能に絶賛対応中(あるいは対応済)といった状況のようです。

今回はこのVeondroing機能と、代表的なパッケージ管理ツールの特徴を調べてみましたので、ご紹介したいと思います。

Vendoring

Vendoringというと大層な機能に聞こえますが、言ってしまえば依存ライブラリの参照先(PATH)に./vendor を追加しただけです。(少なくとも利用側からすれば) この機能が有効になったことで、Goはコンパイル時に依存ライブラリを ./vendor => GOROOT => GOPATHの順番で探しに行くことになります。

冒頭でも述べた通り、Goは外部ライブラリをimportする際にバージョンやタグ、リビジョンなどを指定することが出来ません。 開発環境・ビルド環境を構築するタイミング(=外部ライブラリをgo getにより取得するタイミング)により、 全く同じソースコードでも異なる動作をする可能性があります。

それを解決するためにこのVendoringが導入されました。プロジェクトに関連するリソースは全てvendor下にぶち込んでしまえば再現性が担保できるでしょ、といった考え方です。余談ですが、Genericsを要望する声に対してのCode Generate、という解と、どことなく同じ印象を受けます。

加えて、GOPATH下に依存ライブラリを配置する必要がなくなるため、複数prjにおけるGOPTH汚染問題も解決できるようになります。

代表的なパッケージ依存管理ツール

上記のVendoringがサポートされる前から、様々なパッケージ依存管理ツールGopher達によって開発されていました。

私自身はGoを触り始めた2014年中頃からずっとgodepを使っていました。 当時は特に他のツールときちん比較検討せず、単純にGithub上のスターが一番多いし・・と割と安易に導入を決めてしまいましたw

godepは非常に優秀なツールではあるのですが、全く不満がない訳でもなく、もし他に良いものがあれば乗り換えるのも有りだな、 と思うに至り、今回改めて代表的なツールを一通り触ってみて特徴をまとめました。比較用にgodepも入れています。

ちなみに、それぞれGoのバージョンにより動作に違いがあったりするのですが、 今回は全てバージョン1.6前提とします。

godep

  • vendoring対応済。
  • godep save でプロジェクトのimportしている内容と、$GOPATH以下のVCSの情報などを解析し、以下の処理を行う
    • Godeps/Godeps.jsonに依存しているライブラリのバージョン情報等を出力
    • ./vendor以下に依存しているライブラリを$GOPATHからコピー (Godeps.jsonの例)
{
    "ImportPath": "github.com/kr/hk",
    "GoVersion": "go1.6",
    "Deps": [
        {
            "ImportPath": "code.google.com/p/go-netrc/netrc",
            "Rev": "28676070ab99"
        },
        {
            "ImportPath": "github.com/kr/binarydist",
            "Rev": "3380ade90f8b0dfa3e363fd7d7e941fa857d0d13"
        }
    ]
}
  • godep restore でGodeps.jsonの内容をもとに、$GOPATHに依存ライブラリをダウンロードする(リバースエンジニアリング)。汚染問題あり
  • その他 go testをwrapする機能(1.6では不要?)や、godep update foo/...による依存ライブラリの更新など、機能が充実している

gb

  • vendoring未対応。同じようなことは実現できるが、独自ルールのディレクトリ構成を強制する。(個人的には大きくマイナス..)
  • gb buildでビルドと同時に以下の処理を行う
    • $GOPATHをカレントディレクトリに書き換え
    • 依存ライブラリを./vendor/src/以下にダウンロード
  • 依存ライブラリのバージョン管理、リバースエンジニアリングの機能を使いたい場合は追加で gb-vendor が必要。機能的にはgodepと大差無いが、$GOPATHを汚染することは無い。

glide

  • vendoring対応済。
  • glide createglide.yamlが作成される。以後 golide get hogehoge(go getの代わり)をするとこのファイルに反映される
  • glide install/updateglide.yamlの内容をもとに、依存ライブラリを ./vendor以下にダウンロード
  • リバースエンジニアリング可能。依存ライブラリのバージョン情報などを自動で入れる仕組みは、単体では無いが、godepの出力するGodep.jsonから自動反映させることは可能。
  • bitbucketやstashなど、go getのルールにマッチしていないURLのサービスを指定することも可能
  • glide list glide treeなどの依存関係の確認するコマンドがとても便利。

gom

  • vendoring対応済。
  • gom gen gomfileGomfileが作成される。
  • gom installGomfileの内容をもとに、依存ライブラリを ./vendor以下にダウンロード
  • リバースエンジニアリング可能。ただしGomfileの入力は今の所手作業のみっぽい
  • go getのルールにマッチしていないURLのサービスを指定することも可能
  • RubyGemインスパイア

まとめ

Vendoringは、ご紹介した通り非常にプリミティブな機能だけを提供しているので、 細かなバージョン管理などを含めたパッケージの依存管理には、やはりツールを利用するようにした方が色々捗る、 ということは1.6でも変わらなそうです。

今回改めて色々触ってみましたが、godep以外だとglideがだいぶ良さそうな印象でした。

ただし、私がパッケージ依存管理ツールに求める機能、 という意味ではそこまで大きな差はなく、今回調べた限りではコストをかけて移行する気にはなれませんでした。

そして、残念ながらどのツールも、現時点では私のニーズを100%満たしてくれることは無さそうでした(ニッチなのかもれません、、)

こうなったら自作してみるのもありかな・・ 既存ツール達のどこに不満に感じていて、その不満を解決するために作りました! みたいな記事を、近いうち書けるように頑張ります(^^;)