自分用日本語訳 Go Module
(この記事は、執筆時点でのGo Modulesをもとにした私のメモです。Go Moduleの理解のために、元記事と記載の順番が入れ替わっている項目もあります。)
Go言語は, 1.11以降はモジュールのバージョン管理をサポートしています。初期のプロトタイプ vgo
がアナウンスされたのは2018/2です。2018/5にバージョン管理されたモジュールが初めてgoのリポジトリで使用されだしました。
Go1.14で、モジュールサポートは本番利用に向けて考慮され, 全goユーザは他の依存管理システムからモジュールへ以降することが推奨されました。もし、goのツールチェインの問題で以降できない場合、その問題が起票されているか確認してください。
(もし、その起票が1.15のマイルストーンに載っていない場合、問題解決の優先順位を適切にするために、その問題であなたのモジュール移行がどうして妨害されているのかコメントしてください。 ) より詳細なフィードバックをするために experience report も提供されています。
Quick Start
Example
詳細はこのページの以降に記載するとして、ここでは初めから作成する簡単なモジュールの例を取り上げる。
- $GOPATHの外でディレクトリを作成して、適宜VCSも初期化してください。
$ mkdir -p /tmp/scratchpad/repo
$ cd /tmp/scratchpad/repo
$ git init -q
$ git remote add origin https://github.com/my/repo
- moduleの初期化
$ go mod init github.com/my/repo
go: creating new go.mod: module github.com/my/repo
- コードを書きます。
package main
import (
"fmt"
"rsc.io/quote"
)
func main() {
fmt.Println(quote.Hello())
}
- build and run.
$ go build -o hello
$ ./hello
Hello, world.
-
go.mod
が更新され、依存関係にあるバージョンが明示的に記載される。 ここの1.5.2
はセマンティックバージョン体系になっている。
module github.com/my/repo
require rsc.io/quote v1.5.2
Daily workflow
注意して欲しいのが、上記の例では go get
がなかった。
あなたの典型的な日々のworkflowは以下のようになるだろう。
-
*.go
に必要なimport行を追加する。 - 標準的なコマンド(
go build
orgo test
)がimportステートメントを満たすように必要な新しい依存関係を自動的に追加する。 - 必要であれば、依存関係にあるライブラリの特定バージョンを次のようなコマンドで選ぶことができるし、また
go.mod
を直接編集して指定できる。go get foo@v1.2.3
go get foo@master
go get foo@3702bed2
その他の共通機能に関する短いツアーで以下を使う。
-
go list -m all
--- 直接/間接的な依存関係に対してビルドで使用されるライブラリの最終バージョンを表示する。detail:Version selection -
go list -u -m all
--- 直接/間接的な依存関係に対して利用可能なパッチ/マイナーのアップグレードを表示する。 detail:How to upgrade and downgrade dependencies -
go get -u ./...
orgo get -u=pathc ./...
(from module root directory) --- すべての直接/間接的な依存関係にあるライブラリを最新のバージョンにアップデートします。(pre-releaseは除く) -
go build ./...
orgo test ./...
(from module root directory) --- build or testをモジュール内の全パッケージで実施します。detail:How to define a module -
go mod tidy
--- もう使われていない依存関係のライブラリをgo.mod
から削除し、OS/arch/build tagのその他の組み合わせで必要な依存関係を追加します。detail:How to prepare for a release -
replace
ディレクティブ orgohack
--- forkやローカルにコピーしたライブラリ、正確なバージョンのライブラリを使います。 -
go mod vendor
---vendor
ディレクトリを作成する任意の手順です。detail:How do I use vendoring with modules is vendoring going away
次のセクションNew Concepts
を読めば、ほとんどのプロジェクトでモジュールを始めるのに必要な情報が揃ったことになります。また上の[Table of Contents]を見直すことは詳細な内容に慣れるのにも役立ちます。
New Concepts
これらのセクションは主な新しいコンセプトに対する高レベルの説明になります。詳細なコンセプトと根拠は40分のビデオと公式の提案を見るか、より詳細な初期のvgo blogシリーズを見てください。
Modules
moduleは関連するGoのパッケージ(1つの集まりとしてバージョン付けされた)達の集合です。
moduleらは正確な依存関係を記録し、再現可能なビルドを作成します。
よくあるのが、バージョン管理リポジトリがリポジトリのルートにたった一つに定まったモジュールを含んでいることです。
(1つのリポジトリで複数のモジュールをサポートしますが、一般的には1モジュール/リポジトリより継続敵に管理するためにより多くのことをしなくてはいけなくなります。)
ようやくすると、repository/modules/package間の関係は、
- 1リポジトリで1つ以上のGoモジュールを含む。
- いずれのモジュールも1つ以上のGoパッケージを含む。
- いずれのパッケージも1つのディレクトリ内で1つ以上のGoソースから成る。
モジュールはセマンティックバージョン体系でなければいけません。通常はv(major).(minor).(patch)
の形でv0.1.0
, v1.2.3
, v1.5.0-rc.1
のように採番する。先頭のv
は必須です。
もしGitを使っている場合、これらのバージョンを用いてtagリリースされます。Publicとprivateモジュールリポジトリ、プロキシは使用可能になります。FAQ:Are there "always on" module repositories and enterprise proxies?
go.mod
moduleはGoソースのルートディレクトリにあるgo.mod
ファイルとGoソースのツリー構成によって決められます。
moduleのソースコードはGOPATHの外に配置されているかもしれません。go.mod
は4つのディレクティブmodule
, require
, replace
, exclude
から構成されます。
モジュールgithub.com/my/thing
に対するgo.mod
の例を挙げます。
module github.com/my/thing
require (
github.com/some/dependency v1.2.3
github.com/another/dependency/v4 v4.0.0
)
モジュールはgo.mod
のmodule
ディレクティブでmodule pathを用いて自身を宣言します。module内の全パッケージのimport pathは共通のプレフィックスとしてmodule pathを共有します。moduleパスとパッケージディレクトリまでのgo.mod
からの相対パスはpackageのimportパスを決定します。
例えば、インポートパスがgithub.com/user/mymod/foo
とgithub.com/user/mymod/bar
の2つのパッケージを含むgithub.com/user/mymod
モジュールをリポジトリに作っているとして、一般的にその時のgo.mod
の1行目ではモジュールパスとしてmodule github.com/user/mymod
を宣言して、対応する構成は以下のようになっているでしょう。
mymod
|-- bar
| `-- bar.go
|-- foo
| `-- foo.go
`-- go.mod
Goソースの中で、パッケージはモジュールパスを含んだフルパスでインポートされ使用される。例えば、上記の例で言えば、go.mod
の中でmodule github.com/user/mymod/
とした場合、外部で使用する時には下記のようにすればいい。
import "github.com/user/mymod/bar"
パッケージbar
がmodule github.com/user/mymod
からインポートされる。
exclude
とreplace
ディレクティブは現在のmainモジュールにのみ動作します。mainモジュールをビルドする時、モジュール内のexclude
とreplace
ディレクティブはmainモジュール以外では無視されます。したがって、exluce
とreplace
はmainモジュールを、依存関係により制御されることなく、完全に制御できます。detail:When should i use replace directice
Discussion