目錄
Go包管理工具:前言
Golang一直存在一個被人詬病的問題是缺少一個官方的包依賴管理工具。從我個人的角度上來看存在兩個問題:
- GOPATH特性對於多工程的情況下,支持不算友好。
- GOPATH無法對依賴包進行有效的版本管理,沒有任何地方能夠表明依賴包的具體版本號,無法簡單清晰獲取到有效的依賴包版本信息等。
GOPATH
在 go mod 出現之前,所有的 Go 項目都需要放在同一個工作空間:$GOPATH/src
內,比如:
src/
github.com/golang/example/
.git/ # Git repository metadata
outyet/
main.go # command source
main_test.go # test source
stringutil/
reverse.go # package source
reverse_test.go # test source
相比其他語言,這個限制有些無法理解。其實,這和 Go 的一設計理念緊密相關:
包管理應該是去中心化的
所以 Go 裏面沒有 maven/npm 之類的包管理工具,只有一個 go get
,支持從公共的代碼託管平臺(Bitbucket/GitHub..)下載依賴,當然也支持自己託管,具體可參考官方文檔:Remote import paths。
由於沒有中央倉庫,所以 Go 項目位置決定了其 import path,同時爲了與 go get 保持一致,所以一般來說我們的項目名稱都是 github.com/user/repo
的形式。
當然也可以不是這種形式,只是不方便別人引用而已,後面會講到如何在 go mod 中實現這種效果
vendor、dep
使用 go get
下載依賴的方式簡單暴力,伴隨了 Go 七年之久,直到 1.6(2016/02/17)才正式支持了 vendor,可以把所有依賴下載到當前項目中,解決可重複構建(reproducible builds)的問題,但是無法管理依賴版本。社區出現了各式各樣的包管理工具,來方便開發者固化依賴版本,由於不同管理工具採用不同的元信息格式(比如:godep 的 Godeps.json、Glide 的 glide.yaml),不利於社區發展,所以 Go 官方推出了 dep。
dep 的定位是實驗、探索如何管理版本,並不會直接集成到 Go 工具鏈,Go 核心團隊會吸取 dep 使用經驗與社區反饋,開發下一代包管理工具 modules,並於 2019/09/03 發佈的 1.13 正式支持,並隨之發佈 Module Mirror, Index, Checksum,用於解決軟件分發、中間人攻擊等問題。下圖截取自 Go 官方博客
Go modules
Go modules機制在go 1.11中是experiment feature,按照Go的慣例,在新的experiment feature首次加入時,都會有一個特性開關,go modules也不例外,GO111MODULE這個臨時的環境變量就是go module特性的experiment開關。GO111MODULE有三個值:auto、on和off,默認值爲auto。GO111MODULE的值會直接影響Go compiler的“依賴管理”模式的選擇(是GOPATH mode還是module-aware mode),我們詳細來看一下:
當GO111MODULE的值爲off時,go modules experiment feature關閉,go compiler顯然會始終使用GOPATH mode,即無論要構建的源碼目錄是否在GOPATH路徑下,go compiler都會在傳統的GOPATH和vendor目錄(僅支持在gopath目錄下的package)下搜索目標程序依賴的go package;
當GO111MODULE的值爲on時(export GO111MODULE=on),go modules experiment feature始終開啓,與off相反,go compiler會始終使用module-aware mode,即無論要構建的源碼目錄是否在GOPATH路徑下,go compiler都不會在傳統的GOPATH和vendor目錄下搜索目標程序依賴的go package,而是在go mod命令的緩存目錄($GOPATH/pkg/mod)下搜索對應版本的依賴package;
當GO111MODULE的值爲auto時(不顯式設置即爲auto),也就是我們在上面的例子中所展現的那樣:使用GOPATH mode還是module-aware mode,取決於要構建的源碼目錄所在位置以及是否包含go.mod文件。如果要構建的源碼目錄不在以GOPATH/src爲根的目錄體系下,且包含go.mod文件(兩個條件缺一不可),那麼使用module-aware mode;否則使用傳統的GOPATH mode。
Module 文件
執行命令 go build && go mod tidy
,下載依賴並整理。
項目根目錄下會生成兩個文件(需要加入到 git 中):
- 文件
go.mod
:指示模塊名稱、go 的版本、該模塊的依賴信息(依賴名稱),類似 npm 生成的文件package.json
。- 文件
go.sum
:該模塊的所有依賴的校驗和,類似 npm 生成的文件package-lock.json
Module 是多個 package 的集合,版本管理的基本單元,使用 go.mod 文件記錄依賴的 module。
go.mod 位於項目的根目錄,支持 4 條命令:module、require、replace、exclude。示例:
module github.com/my/repo
require (
github.com/some/dependency v1.2.3
github.com/another/dependency/v4 v4.0.0
)
- module 聲明 module path,一個 module 內所有 package 的 import path 都以它爲前綴
- require 聲明所依賴的 module,版本信息使用形如
v(major).(minor).(patch)
的語義化版本 - replace/exclude 用於替換、排查指定 module path
go mod命令
golang 提供了
go mod
命令來管理包。
go mod 有以下命令:
命令 | 說明 |
---|---|
download | download modules to local cache(下載依賴包) |
edit | edit go.mod from tools or scripts(編輯go.mod) |
graph | print module requirement graph (打印模塊依賴圖) |
init | initialize new module in current directory(在當前目錄初始化mod) |
tidy | add missing and remove unused modules(拉取缺少的模塊,移除不用的模塊) |
vendor | make vendored copy of dependencies(將依賴複製到vendor下) |
verify | verify dependencies have expected content (驗證依賴是否正確) |
why | explain why packages or modules are needed(解釋爲什麼需要依賴) |
Go modules使用步驟:
- 首先將你的版本更新到最新的Go版本(>=1.11)。
- 通過go命令行,進入到你當前的工程目錄下,在命令行設置臨時環境變量set GO111MODULE=on;
# 開啓 export GO111MODULE=on # 1.13 之後才支持多個地址,之前版本只支持一個 export GOPROXY=https://goproxy.cn,https://mirrors.aliyun.com/goproxy,direct # 1.13 開始支持,配置私有 module,不去校驗 checksum export GOPRIVATE=*.corp.example.com,rsc.io/private
- 執行命令go mod init在當前目錄下生成一個go.mod文件,執行這條命令時,當前目錄不能存在go.mod文件。如果之前生成過,要先刪除;
- 如果你工程中存在一些不能確定版本的包,那麼生成的go.mod文件可能就不完整,因此繼續執行下面的命令;
- 執行go mod tidy命令,它會添加缺失的模塊以及移除不需要的模塊。執行後會生成go.sum文件(模塊下載條目)。添加參數-v,例如go mod tidy -v可以將執行的信息,即刪除和添加的包打印到命令行;
- 執行命令go mod verify來檢查當前模塊的依賴是否全部下載下來,是否下載下來被修改過。如果所有的模塊都沒有被修改過,那麼執行這條命令之後,會打印all modules verified。
- 執行命令go mod vendor生成vendor文件夾,該文件夾下將會放置你go.mod文件描述的依賴包,文件夾下同時還有一個文件modules.txt,它是你整個工程的所有模塊。在執行這條命令之前,如果你工程之前有vendor目錄,應該先進行刪除。同理go mod vendor -v會將添加到vendor中的模塊打印出來;
參考鏈接:
https://liujiacai.net/blog/2019/10/24/go-modules/
https://tonybai.com/2018/07/15/hello-go-module/
https://l1905.github.io/golang%E5%BC%80%E5%8F%91/2019/08/05/golang-mod-build/