Go包管理工具
- 2019 年 12 月 30 日
- 筆記
真的,Go的包管理工具之發展過程充分體現了什麼叫折騰
。 (嘆氣~~~)
想想Java的Maven, Nodejs的NPM,還有我們讚頌一萬遍也不過分的Python包管理,為什麼生命總要浪費在這些事情上面呢? 陷入了深深的沉思~~
從Go1.11版本發佈Go MODULE之後,我希望這是最後一次折騰包管理
這件事情,神吶,誠心誠意的祈禱中~~
摘抄備忘下:
GO111MODULE
Modules 是作為 experiment feature 加入到不久前正式發佈的 Go 1.11 中的。 按照 Go 的慣例,在新的 experiment feature 首次加入時,都會有一個特性開關,go modules 也不例外,GO111MODULE 這個臨時的環境變量就是 go modules 特性的 experiment 開關。
- off: go modules experiment feature 關閉,go compiler 會始終使用 GOPATH mode,即無論要構建的源碼目錄是否在 GOPATH 路徑下,go compiler 都會在傳統的 GOPATH 和 vendor 目錄 (僅支持在 GOPATH 目錄下的 package) 下搜索目標程序依賴的 go package;
- on: 始終使用 module-aware mode,只根據 go.mod 下載 dependency 而完全忽略 GOPATH 以及 vendor 目錄
- auto: Golang 1.11 預設值,使用 GOPATH mode 還是 module-aware mode,取決於要構建的源碼目錄所在位置以及是否包含 go.mod 文件。滿足任一條件時才使用 module-aware mode:
- 當前目錄位於 GOPATH/src 之外並且包含 go.mod 文件
- 當前目錄位於包含 go.mod 文件的目錄下
go mod 命令
download download modules to local cache (下載依賴的 modules 到本地 cache) edit edit go.mod from tools or scripts (編輯 go.mod 文件) graph print module requirement graph (打印模塊依賴圖) init initialize new module in current directory (再當前文件夾下初始化一個新的 module, 創建 go.mod 文件) tidy add missing and remove unused modules (增加丟失的 modules,去掉未用的 modules) vendor make vendored copy of dependencies (將依賴複製到 vendor 下) verify verify dependencies have expected content (校驗依賴) why explain why packages or modules are needed (解釋為什麼需要依賴)
既有項目
假設你已經有了一個 go 項目, 比如在$GOPATH/github.com/brain-zhang/hello下, 你可以使用go mod init github.com/brain-zhang/hello在這個文件夾下創建一個空的 go.mod (只有第一行 module github.com/brain-zhang/hello)。
然後你可以通過 go get ./…讓它查找依賴,並記錄在 go.mod 文件中 (你還可以指定 -tags, 這樣可以把 tags 的依賴都查找到)。
通過go mod tidy也可以用來為 go.mod 增加丟失的依賴,刪除不需要的依賴,但是我不確定它怎麼處理tags。
執行上面的命令會把 go.mod 的latest版本換成實際的最新的版本,並且會生成一個go.sum記錄每個依賴庫的版本和哈希值。
replace
在國內訪問golang.org/x的各個包都需要梯子,你可以在 go.mod 中使用replace替換成 github 上對應的庫。
replace ( golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac => github.com/golang/crypto v0.0.0-20180820150726-614d502a4dac golang.org/x/net v0.0.0-20180821023952-922f4815f713 => github.com/golang/net v0.0.0-20180826012351-8a410e7b638d golang.org/x/text v0.3.0 => github.com/golang/text v0.3.0 )
依賴庫中的replace對你的主 go.mod 不起作用,比如github.com/brain-zhang/hello的 go.mod 已經增加了replace, 但是你的 go.mod 雖然require了rpcx的庫,但是沒有設置replace的話, go get還是會訪問golang.org/x。
所以如果想編譯哪個項目,就在哪個項目中增加replace。
包的版本控制
下面的版本都是合法的:
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 gopkg.in/vmihailenco/msgpack.v2 v2.9.1 gopkg.in/yaml.v2 <=v2.2.1 github.com/tatsushid/go-fastping v0.0.0-20160109021039-d7bb493dee3e latest
版本號遵循如下規律:
vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef vX.0.0-yyyymmddhhmmss-abcdefabcdef vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef vX.Y.Z
也就是版本號 + 時間戳 + hash,我們自己指定版本時只需要制定版本號即可,沒有版本 tag 的則需要找到對應 commit 的時間和 hash 值。
另外版本號是支持 query 表達式的,其求值算法是 「選擇最接近於比較目標的版本 (tagged version)」,即上文中的 gopkg.in/yaml.v2 會找不高於 v2.2.1 的最高版本。
go get 升級
- 運行 go get -u 將會升級到最新的次要版本或者修訂版本 (x.y.z,z 是修訂版本號, y 是次要版本號)
- 運行 go get -u=patch 將會升級到最新的修訂版本
- 運行 go get package@version 將會升級到指定的版本號version
go modules 與 vendor
- 在最初的設計中,Russ Cox 是想徹底廢除掉 vendor 的,但在社區的反饋下,vendor 得以保留,這也是為了兼容 Go 1.11 之前的版本。
- Go modules 支持通過go mod vendor命令將某個 module 的所有依賴保存一份 copy 到 root module dir 的 vendor 下,然後在構建的使用go build -mod=vendor即可忽略 cache 里的包而只使用 vendor 目錄里的版本。
參考:
https://github.com/golang/go/wiki/Modules
https://windmt.com/2018/11/08/first-look-go-modules/