Go:包管理工具GOPATH、vendor、dep 、go module

目錄

Go包管理工具:前言

GOPATH

vendor、dep

Go modules

Module 文件

go mod命令

Go modules使用步驟:


Go包管理工具:前言

Golang一直存在一個被人詬病的問題是缺少一個官方的包依賴管理工具。從我個人的角度上來看存在兩個問題:

  1. GOPATH特性對於多工程的情況下,支持不算友好。
  2. 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 官方博客

 

Module Big Picture

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使用步驟:

  1. 首先將你的版本更新到最新的Go版本(>=1.11)。
  2. 通過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

     

  3. 執行命令go mod init在當前目錄下生成一個go.mod文件,執行這條命令時,當前目錄不能存在go.mod文件。如果之前生成過,要先刪除;
  4. 如果你工程中存在一些不能確定版本的包,那麼生成的go.mod文件可能就不完整,因此繼續執行下面的命令;
  5. 執行go mod tidy命令,它會添加缺失的模塊以及移除不需要的模塊。執行後會生成go.sum文件(模塊下載條目)。添加參數-v,例如go mod tidy -v可以將執行的信息,即刪除和添加的包打印到命令行;
  6. 執行命令go mod verify來檢查當前模塊的依賴是否全部下載下來,是否下載下來被修改過。如果所有的模塊都沒有被修改過,那麼執行這條命令之後,會打印all modules verified。
  7. 執行命令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/

https://research.swtch.com/vgo

發佈了410 篇原創文章 · 獲贊 1345 · 訪問量 208萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章