Glide を使用した Go の依存関係管理

GlidenpmNodeJS のような Go のパッケージ管理ツールです。シンプルな例を作成して、その機能を見てみましょう。

$GOPATH の内部にプロジェクトを作成する

Go のパッケージのパスを解決するには、プロジェクトフォルダが $GOPATH に存在している必要があります。この例では、ルートフォルダは $GOPATH/src/gitlab.com/ykyuen/glide-example です。

Hello World Go プログラム

シンプルな Go プログラムを作ってみましょう。

main.go

1
2
3
4
5
6
7
package main

import "fmt"

func main() {
  fmt.Println("hello world")
}

ビルドと実行

1
2
3
[[email protected] glide-example]$ go build -o hello
[[email protected] glide-example]$ ./hello
hello world

Go の依存関係の追加

dustin/go-humanize は、数値、文字列、時刻をフォーマットするのに役立つ Go パッケージです。Go プログラムを次のようにアップデートしてみましょう。

main.go

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package main

import humanize "github.com/dustin/go-humanize"
import "fmt"

func main() {
  fmt.Println("hello world")
  fmt.Printf("That file is %s.\n", humanize.Bytes(82854982)) // That file is 83 MB.
  fmt.Printf("You're my %s best friend.\n", humanize.Ordinal(193)) // You are my 193rd best friend.
  fmt.Printf("You owe $%s.\n", humanize.Comma(6582491)) // You owe $6,582,491.
}

これでビルドしようとすると、次のエラーが検出されます。

1
2
3
4
[[email protected] glide-example]$ go build -o hello
main.go:3:8: cannot find package "github.com/dustin/go-humanize" in any of:
  /home/ykyuen/tools/go1.8.4/src/github.com/dustin/go-humanize (from $GOROOT)
  /home/ykyuen/go/src/github.com/dustin/go-humanize (from $GOPATH)

これは dustin/go-humanize をダウンロードしていないためです。Glide なしでも、go get コマンドを実行することでこのビルドエラーを解決することができます

1
go get github.com/dustin/go-humanize

しかしこの場合、プロジェクトをチェックする際、プログラムをビルドするために必要なのがどのパッケージなのかわかりません。すでに go get コマンドを実行している場合は、先に進む前にパッケージを削除しましょう。

Glide の使いかた

glide.yaml を作成する

glide.yamlglide create コマンドで生成することができます。Go ソースファイルをスキャンし、必要な依存関係をインクルードします。以下はその例のアウトプットです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[[email protected] glide-example]$ glide create
[INFO]  Generating a YAML configuration file and guessing the dependencies
[INFO]  Attempting to import from other package managers (use --skip-import to skip)
[INFO]  Scanning code to look for dependencies
[INFO]  --> Found reference to github.com/dustin/go-humanize
[INFO]  Writing configuration file (glide.yaml)
[INFO]  Would you like Glide to help you find ways to improve your glide.yaml configuration?
[INFO]  If you want to revisit this step you can use the config-wizard command at any time.
[INFO]  Yes (Y) or No (N)?
Y
[INFO]  Looking for dependencies to make suggestions on
[INFO]  --> Scanning for dependencies not using version ranges
[INFO]  --> Scanning for dependencies using commit ids
[INFO]  Gathering information on each dependency
[INFO]  --> This may take a moment. Especially on a codebase with many dependencies
[INFO]  --> Gathering release information for dependencies
[INFO]  --> Looking for dependency imports where versions are commit ids
[INFO]  No proposed changes found. Have a nice day.

glide.yaml

1
2
3
package: gitlab.com/ykyuen/glide-example
import:
- package: github.com/dustin/go-humanize

Go の依存関係を vendor のフォルダにダウンロードする

次に、glide install コマンドを実行して依存関係をダウンロードします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
[[email protected] glide-example]$ glide install
[INFO]  Lock file (glide.lock) does not exist. Performing update.
[INFO]  Downloading dependencies. Please wait...
[INFO]  --> Fetching updates for github.com/dustin/go-humanize
[INFO]  Resolving imports
[INFO]  Downloading dependencies. Please wait...
[INFO]  Setting references for remaining imports
[INFO]  Exporting resolved dependencies...
[INFO]  --> Exporting github.com/dustin/go-humanize
[INFO]  Replacing existing vendor dependencies
[INFO]  Project relies on 1 dependencies.

glide.lock ファイルと dustin/go-humanize パッケージを含む vendor フォルダが生成されます。 glide.lock ファイルには、タグまたは git のコミットハッシュなどのパッケージのバージョンが含まれます。

glide.lock

1
2
3
4
5
6
hash: de8aada0e0453f13dc438db5fb412db797d701d6afeadcc052c477fd55e01aa8
updated: 2017-12-04T23:20:53.616704682+08:00
imports:
- name: github.com/dustin/go-humanize
  version: 8929fe90cee4b2cb9deb468b51fb34eba64d1bf0
testImports: []

依存関係のバージョンをアップデートする

8929fe9 コミットは時代遅れです。glide.lock ファイルのバージョンを変更し、glide install を再度実行すれば、希望するバージョンのパッケージを入手することが可能です。

glide.lock

1
2
3
4
5
6
hash: de8aada0e0453f13dc438db5fb412db797d701d6afeadcc052c477fd55e01aa8
updated: 2017-12-04T23:20:53.616704682+08:00
imports:
- name: github.com/dustin/go-humanize
  version: bb3d318650d48840a39aa21a027c6630e198e626
testImports: []

1
2
3
4
5
6
7
8
[[email protected] glide-example]$ glide install
[INFO]  Downloading dependencies. Please wait...
[INFO]  --> Found desired version locally github.com/dustin/go-humanize bb3d318650d48840a39aa21a027c6630e198e626!
[INFO]  Setting references.
[INFO]  --> Setting version for github.com/dustin/go-humanize to bb3d318650d48840a39aa21a027c6630e198e626.
[INFO]  Exporting resolved dependencies...
[INFO]  --> Exporting github.com/dustin/go-humanize
[INFO]  Replacing existing vendor dependencies

ビルドして再度実行する

1
2
3
4
5
6
[[email protected] glide-example]$ go build -o hello
[[email protected] glide-example]$ ./hello
hello world
That file is 83 MB.
You're my 193rd best friend.
You owe $6,582,491.

vendor のフォルダをチェックインしますか?

NodeJS プロジェクトでは、コードリポジトリの node_modules フォルダを無視するのは常識といっていいでしょう。一方、Go コミュニティは異なる視点を持っています。

絶対的な答えはありません。より適切だと思うオプションを選びましょう。

その他の懸念点

プロジェクトの拡大にしたがって依存関係ツリーが大きくなると、glide にもかなりの時間が必要です。さらに、依存関係のバージョンを管理するのも困難です。

このような問題を解決してくれるのが、Glide チームが提案している依存関係管理ツール、dep活発に開発されており、人気が高まっているツールです。dep のプロジェクトステータスを参照し、より適切だと感じるものを選びましょう。

まとめ

  • プロジェクトフォルダは $GOPATH 以下になければいけない。
  • 依存関係はすべてのソースコードをスキャンすることによって自動的にインクルードされる。
  • 依存関係のバージョンは glide.lock によって管理される。
  • vendor のフォルダをコミットするかどうかに絶対的な答えはまだない。
  • 依存関係ツリーが大きくなるとパフォーマンスの問題が発生する。
  • gitlab.com で実例を参照することができる。