[Go] Go Modules

程式語言:Go
工具:
go mod
官方文件
官方 wiki 文件

功能:套件管理,V1.11 之後才支援,建議搭配 VCS (例:github)

環境變數設定

使用 modules,build|test|install 需在 go.mod 的目錄下,不然會出錯
go.mod & go.sum 必須要加入版控,以確保在不同版本都能成功的 build
  • GO111MODULE
    • unset or auto
      • Inside GOPATH
        • 預設跟 1.10 行為一樣 (忽略 modules) 
      • Outside GOPATH
        • 當存在 go.mod,則為 modules 行為
    • on
      • 強制為 modules 行為,即使 inside GOPATH
    • off
      • 強制為 1.10 的行為,即使擁有 go.mod

簡易步驟

  1. 移至 Project 目錄
    $ cd <project path outside $GOPATH/src>         # e.g., cd ~/projects/hello
    若 Project 位於 GOPATH 中,需設定以下環境變數
    $ export GO111MODULE=on                         # manually active module mode
  2. 建立 go.mod
    $ go mod init github.com/my/repo
    module 名字可任意,通常與 VCS 相關
  3. build|test|install 後,go.mod 將自動加入依賴,且 pkg 下載到 GOPATH/pkg/mod 內
    $ go build|test|install ./...
  4. 測試確認
    $ go test ./...
  5. 測試 all direct and indirect dependencies,防止不相容
    $ go test ./...

簡單範例

  1. 測試 code,hello.go
    1. package main
    2.  
    3. import (
    4. "fmt"
    5. "rsc.io/quote"
    6. )
    7.  
    8. func main() {
    9. fmt.Println("Hello World")
    10. quote.Hello()
    11. }
  2. 初始化 mod
    $ go mod init hello
    得到 go.mod
    1. module hello
    2.  
    3. go 1.12
  3. build
    $ go build
    go.mod 多出一行 require
    1. module hello
    2.  
    3. go 1.12
    4.  
    5. require rsc.io/quote v1.5.2
    多出 go.sum,內為依賴版本的 Hash
    1. golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8=
    2. golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
    3. rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3Y=
    4. rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
    5. rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
    6. rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
  4. 列出目前的依賴
    $ go list -m all
    1. hello
    2. golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c
    3. rsc.io/quote v1.5.2
    4. rsc.io/sampler v1.3.0
  5. 更新 text 為 tag 版本
    $ go get golang.org/x/text
    go.mod 多出一行 require,並標注為 indirect
    1. module hello
    2.  
    3. go 1.12
    4.  
    5. require (
    6. golang.org/x/text v0.3.2 // indirect
    7. rsc.io/quote v1.5.2
    8. )

升级更新

  • 升級到最新的版本
    $ go get
  • 升級到最新的次要版本或者修訂版本 (x.y.z,z 是修訂版本號, y 是次要版本號)
    $ go get -u
  • 升級到最新的修訂版本
    $ go get -u=patch
  • 升級到指定的版本號 version
    $ go get package@version

版本號命名規則 semver

以下命名皆合法,詳細說明可參考連結
  1. gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7
  2. gopkg.in/vmihailenco/msgpack.v2 v2.9.1
  3. gopkg.in/yaml.v2 <=v2.2.1
  4. github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e
  5. latest

指定不同版本的 module 範例

hello.go
  1. package hello
  2.  
  3. import (
  4. "rsc.io/quote"
  5. quoteV3 "rsc.io/quote/v3"
  6. )
  7.  
  8. func Hello() string {
  9. return quote.Hello()
  10. }
  11.  
  12. func Proverb() string {
  13. return quoteV3.Concurrency()
  14. }
hello_test.go
  1. package hello
  2.  
  3. import "testing"
  4.  
  5. func TestProverb(t *testing.T) {
  6. want := "Concurrency is not parallelism."
  7. if got := Proverb(); got != want {
  8. t.Errorf("Proverb() = %q, want %q", got, want)
  9. }
  10. }
執行測試
  1. $ go test
  2. go: finding rsc.io/quote/v3 v3.1.0
  3. go: downloading rsc.io/quote/v3 v3.1.0
  4. go: extracting rsc.io/quote/v3 v3.1.0
  5. PASS
  6. ok hello 1.391s
可發現 rsc.io/quote 有兩個版本
  1. $ go list -m rsc.io/q...
  2. rsc.io/quote v1.5.2
  3. rsc.io/quote/v3 v3.1.0
go.mod
  1. module hello
  2.  
  3. go 1.12
  4.  
  5. require (
  6. rsc.io/quote v1.5.2
  7. rsc.io/quote/v3 v3.1.0
  8. )
go.sum
  1. golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c h1:qgOY6WgZOaTkIIMiVjBQcw93ERBE4m30iBm00nkL0i8=
  2. golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
  3. rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3Y=
  4. rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0=
  5. rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=
  6. rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
  7. rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
  8. rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
順帶一提,如下,加了版本,仍是使用原來的 module 名,除非有重新指定
  1. package hello
  2.  
  3. import (
  4. "rsc.io/quote/v3"
  5. )
  6.  
  7. func Proverb() string {
  8. return quote.Concurrency()
  9. }

本地依賴範例

Folder
└── test
    └── hello.go
    └── go.mod
└── test2
    └── hello.go
    └── go.mod
test/hello.go
  1. package hello
  2.  
  3. func Hello() string {
  4. println("hello")
  5. return "Hello, world."
  6. }
test/go.mod
  1. module ttt //不影響運行
  2.  
  3. go 1.12
test2/hello.go
  1. package main
  2.  
  3. import "test/hello" //可以是錯誤的路徑,只要 replace 是對的
  4.  
  5. func main() {
  6. hello.Hello()
  7. }
test2/go.mod
  1. module main
  2.  
  3. go 1.12
  4.  
  5. require test/hello v0.0.0 // 虛擬版號
  6.  
  7. // 取代為真正的路徑,可為絕對或相對路徑,但注意為 go.mod 所在的資料夾
  8. replace test/hello => ../test
執行測試,需在 go.mod 的資料夾中
  1. $ cd test2
  2. $ go run hello.go
  3. hello

命令

  • go mod download
    • 下載依賴的 module 到本地 cache,go get|build|test|install 有同樣效果
  • go mod edit
    • 編輯 go.mod 文件,需搭配 flag,可查看說明
      go help mod edit
  • go mod graph
    • 印出 module 依賴圖
  • go mod init
    • 在當前文件夾下初始化一個新的 module, 建立 go.mod 文件
  • go mod tidy
    • 增加丟失的 module,去掉未用的 module 
  • go mod vendor
    • 將依賴複製到 vendor
  • go mod verify
    • 校驗依賴
  • go mod why
    • 解釋為什麼需要依賴
  • go list -m
    • 列出所有的依賴

參考

浅析 golang module
gvm + go mod
关于Go Module的争吵
Go 語言 1.11 版本推出 go module
go modules详解
跳出Go module的泥潭
語意化版本 2.0.0

留言