Go Modules 模式
GOPATH 目錄
GOPATH 目錄下一共包含三個(gè)子目錄:
- bin:存儲(chǔ)所編譯生成的二進(jìn)制文件倦卖。
- pkg:存儲(chǔ)預(yù)編譯的目標(biāo)文件释簿,以加快程序的后續(xù)編譯速度钦听。
- src:存儲(chǔ)所有
.go
文件或源代碼。在編寫 Go 應(yīng)用程序倍奢,程序包和庫(kù)時(shí)朴上,一般會(huì)以$GOPATH/src/github.com/foo/bar
的路徑進(jìn)行存放。
使用
go get
來(lái)拉取外部依賴時(shí)卒煞,會(huì)自動(dòng)下載并安裝到$GOPATH
目錄下痪宰。
go mod 命令
查看 go mod 都有哪些命令
# Go 的所有工具都可以使用 `go help` 來(lái)查看使用方法
go help mod
# 查看 go mod download 有哪些參數(shù)
go help mod download
命令 | 作用 |
---|---|
go mod help | 查看幫助信息 |
go mod init | 初始化當(dāng)前文件夾,生成 go.mod 文件 |
go mod download | 下載 go.mod 文件中指明的所有依賴到本地(默認(rèn)為 $GOPATH/pkg/mod 目錄)增加 -x 參數(shù) go mod download -x 會(huì)打印下載信息畔裕;go mod download -json 用來(lái)查看模塊下載的 zip 存放位置衣撬,以及解壓后的位置; |
go mod tidy | 整理現(xiàn)有的依賴扮饶,執(zhí)行時(shí)會(huì)把未使用的 module 移除掉具练,同時(shí)也會(huì)增加缺少的包 |
go mod graph | 查看現(xiàn)有的依賴結(jié)構(gòu)圖 |
go mod edit | 編輯 go.mod 文件,比如修改項(xiàng)目中使用的 go 版本 go mod edit -go=1.17
|
go mod vendor | 導(dǎo)出項(xiàng)目所有的依賴到 vendor 目錄(需要執(zhí)行 go build -mod=vendor 才可以使用 vendor 作為依賴來(lái)編譯甜无,但是在 v1.14 及以后的版本中扛点,如果 golang 項(xiàng)目根目錄下存在 vendor 目錄,go build 命令會(huì)默認(rèn)優(yōu)先基于 vendor 目錄緩存的三方依賴包構(gòu)建 golang 程序岂丘,除非我們?cè)?go build 命令后面加上 -mod=mod 參數(shù)) |
go mod verify | 校驗(yàn)一個(gè)模塊是否被篡改過(guò)陵究,校驗(yàn)從 GOPROXY 服務(wù)器上下載的 zip 文件與 GOSUMDB 服務(wù)器下載下來(lái)的哈希值,是否匹配奥帘。 |
go mod why | 查看為什么需要依賴某模塊铜邮,比如 go mod why gopkg.in/yaml.v2 gopkg.in/yaml.v3
|
go clean -modcache | 可以清空本地下載的 Go Modules 緩存 (會(huì)清空 $GOPATH/pkg/mod 目錄) |
go mod 環(huán)境變量
和 go mod
比較關(guān)聯(lián)的幾個(gè)環(huán)境變量
go env
GO111MODULE="auto"
GOPROXY="https://goproxy.cn,direct"
GOSUMDB="sum.golang.org"
GONOPROXY=""
GONOSUMDB=""
GOPRIVATE=""
GO111MODULE
Go 語(yǔ)言提供了 GO111MODULE 這個(gè)環(huán)境變量來(lái)作為 Go modules 的開關(guān),其允許設(shè)置以下參數(shù):
- auto:只要項(xiàng)目包含了 go.mod 文件的話啟用 Go modules,目前在 Go1.11 至 Go 1.14 中仍然是默認(rèn)值
- on:?jiǎn)⒂?Go modules松蒜,推薦設(shè)置扔茅,將會(huì)是未來(lái)版本中的默認(rèn)值
- off:禁用 Go modules,不推薦設(shè)置
設(shè)置方式
go env -w GO111MODULE=on
也可以直接在 shell 環(huán)境變量中設(shè)置牍鞠,比如我這里使用的是 Mac咖摹,且使用的 zsh,則在 vim ~/.zshrc
然后添加以下內(nèi)容难述,如果是其它 Linux 系列系統(tǒng)萤晴,則需要在 ~/.bash_profile
文件中進(jìn)行設(shè)置。
export GO111MODULE=on
然后要記得 source ~/.zshrc
GOPROXY
這個(gè)環(huán)境變量主要是用于設(shè)置 Go 模塊代理(Go module proxy)胁后,其作用是用于使 Go 在后續(xù)拉取模塊版本時(shí)直接通過(guò)鏡像站點(diǎn)來(lái)快速拉取
GOPROXY 的默認(rèn)值是:https://proxy.golang.org,direct
# 1. 七牛 CDN
go env -w GOPROXY=https://goproxy.cn,direct
# 2. 阿里云
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,direct
# 3. 官方
go env -w GOPROXY=https://goproxy.io,direct
direct
是一個(gè)特殊指示符店读,用于指示 Go 在獲取源碼包時(shí),先嘗試在設(shè)置 GOPROXY 的地址下抓取攀芯,如果遇到 404 或 410 等錯(cuò)誤時(shí)屯断,再回溯到模塊版本的源地址去抓取 (比如 GitHub 等)。
GOSUMDB
它的值是一個(gè) Go checksum database侣诺,用于在拉取模塊版本時(shí)(無(wú)論是從源站拉取還是通過(guò) Go module proxy 拉戎逞荨)保證拉取到的模塊版本數(shù)據(jù)未經(jīng)過(guò)篡改,若發(fā)現(xiàn)不一致年鸳,也就是可能存在篡改趴久,將會(huì)立即終止。
GOSUMDB 的默認(rèn)值為:sum.golang.org
搔确,在國(guó)內(nèi)也是無(wú)法訪問(wèn)的彼棍,但是 GOSUMDB 可以被 Go 模塊代理所代理,因此我們可以通過(guò)設(shè)置 GOPROXY
來(lái)解決膳算,而先前我們所設(shè)置的模塊代理 goproxy.cn
(七牛云的 CDN)就能支持代理 sum.golang.org
座硕,所以這一個(gè)問(wèn)題在設(shè)置 GOPROXY 后,可以不需要過(guò)度關(guān)心涕蜂。
也可以將其設(shè)置為 off
华匾,也就是禁止 Go 在后續(xù)操作中校驗(yàn)?zāi)K版本。但是不建議關(guān)閉校驗(yàn)机隙。
GONOPROXY/GONOSUMDB/GOPRIVATE
- GONOPROXY —— 設(shè)置不走 Go Proxy 的 URL 規(guī)則瘦真;
- GONOSUMDB —— 設(shè)置不檢查哈希的 URL 規(guī)則;
- GOPRIVATE —— 設(shè)置私有模塊的 URL 規(guī)則黍瞧,會(huì)同時(shí)設(shè)置以上兩個(gè)變量诸尽。
這三個(gè)環(huán)境變量都是用在當(dāng)前項(xiàng)目依賴了私有模塊,例如自己公司部署的私有 git 倉(cāng)庫(kù)或者是 GitHub 中的私有倉(cāng)庫(kù)印颤,都是需要進(jìn)行設(shè)置的您机,否則會(huì)拉取失敗。
設(shè)置 GOPRIVATE 之后,表示該地址為私有倉(cāng)庫(kù)际看,不會(huì)從 GOPROXY 所對(duì)應(yīng)的地址上去下載咸产。
而一般建議直接設(shè)置 GOPRIVATE,它的值將作為 GONOPROXY 和 GONOSUMDB 的默認(rèn)值仲闽,所以建議直接設(shè)置 GOPRIVATE 即可脑溢。
# 以下表示 git.example.com 和 github.com/username/package 都是私有倉(cāng)庫(kù),不會(huì)進(jìn)行 GOPROXY 下載和校驗(yàn)
go env -w GOPRIVATE="git.example.com,github.com/username/package"
# 設(shè)置后赖欣,前綴為 `git.example.com` 和 `github.com/username/package` 的模塊都會(huì)被認(rèn)為是私有模塊
# 表示所有模塊路徑為 example.com 的子域名都不進(jìn)行 GOPROXY 下載和校驗(yàn)
# 需要注意的是不包括 example.com 本身
go env -w GOPRIVATE="*.example.com"
使用 Go Modules 初始化項(xiàng)目
# 開啟 Go Modules 模塊屑彻,保證 GO111MODULE=on
go env -w GO111MODULE=on
# 在任意文件夾下創(chuàng)建一個(gè)項(xiàng)目(不要求在 $GOPATH/src 目錄下創(chuàng)建)
mkdir -p $HOME/modules_test
cd $HOME/modules_test
# 創(chuàng)建 go.mod 文件,同時(shí)起當(dāng)前項(xiàng)目的模塊名稱
# 如果你是在 `$GOPATH/src` 目錄下創(chuàng)建的文件夾可以直接執(zhí)行 `go mod init` 命令初始化顶吮,不需要加模塊名稱
go mod init github.com/pudongping/moudles_test
# 在該項(xiàng)目下編寫源代碼社牲,并下載依賴庫(kù)
# 也可以不加 `-v` 參數(shù)
go get -v XXXXXXXX
eg: go get -v github.com/pudongping/test_moudles
下載的包其實(shí)被緩存在
$GOPATH/pkg/mod
目錄和$GOPATH/pkg/sumdb
目錄下
go.mod
文件中:
- module:用于定義當(dāng)前項(xiàng)目的模塊路徑。
- go:用于標(biāo)識(shí)當(dāng)前模塊的 Go 語(yǔ)言版本悴了,值為初始化模塊時(shí)的版本搏恤。
- require:用于設(shè)置一個(gè)特定的模塊版本。
- exclude:用于從使用中排除一個(gè)特定的模塊版本湃交。
- replace:用于將一個(gè)模塊版本替換為另外一個(gè)模塊版本熟空。
# v0.0.0 表示版本信息
# 20190718012654 表示所拉取版本的 commit 時(shí)間
# fb15b899a751 表示所拉取版本的 commit 哈希值
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
go.sum
文件中:
go.sum 文件的作用是:羅列當(dāng)前項(xiàng)目直接或間接依賴的所有模塊版本,保證今后項(xiàng)目依賴的版本不會(huì)被篡改搞莺。間接依賴的包的哈希值也會(huì)被保存痛阻。
go.sum 文件中有兩種 hash 的形式:
-
h1:<hash>
將目標(biāo)模塊版本的 zip 文件開包后,針對(duì)所有包內(nèi)文件依次進(jìn)行 hash腮敌,然后再把它們的 hash 結(jié)果按照固定格式和算法組成總的 hash 值,如果不存在俏扩,表示可能依賴的庫(kù)用不上 -
xxx/go.mod h1.<hash>
表示 go.mod 文件做的 hash
# 將目標(biāo)模塊版本的 zip 文件開包后糜工,針對(duì)包內(nèi)所有文件依次進(jìn)行 hash,然后再將 它們的 hash 結(jié)果匯總組成 hash
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
# 針對(duì) go.mod 文件的 hash 值
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
go get 拉取命令
下載的模塊會(huì)被放置于
$GOPATH/pkg/mod
目錄中
命令 | 作用 |
---|---|
go get | 拉取依賴录淡,會(huì)進(jìn)行指定性拉劝颇尽(更新),并不會(huì)更新所依賴的其它模塊嫉戚。(如果本地已存在要下載的包刨裆,將會(huì)直接使用本地已存在的包) |
go get -u | 更新現(xiàn)有的依賴,會(huì)強(qiáng)制更新它所依賴的其它全部模塊彬檀,不包括自身帆啃。 |
go get -u -t ./… | 更新所有直接依賴和間接依賴的模塊版本,包括單元測(cè)試中用到的窍帝。 |
go get golang.org/x/text@latest | 拉取最新的版本努潘,若存在 tag,則優(yōu)先使用。 |
go get golang.org/x/text@master | 拉取 master 分支的最新 commit疯坤。 |
go get golang.org/x/text@v0.3.2 | 拉取 tag 為 v0.3.2 的 commit报慕。 |
go get golang.org/x/text@342b2e | 拉取 hash 為 342b231 的 commit,最終會(huì)被轉(zhuǎn)換為 v0.3.2压怠。 |
go get 子參數(shù)說(shuō)明
子命令 | 描述 |
---|---|
-d | 僅下載眠冈,不安裝 |
-f | 和 -u 配合,強(qiáng)制更新菌瘫,不檢查是否過(guò)期 |
-t | 下載測(cè)試代碼所需的依賴包 |
-u | 更新包蜗顽,包括他們的依賴項(xiàng) |
-v | 輸出詳細(xì)信息 |
insecure | 使用 http 等非安全協(xié)議 |
修改項(xiàng)目模塊的版本依賴關(guān)系
go mod edit -replace=<老版本>=<需要替換的版本>
# 比如
go mod edit -replace=demo-package@v1.0.0=demo-package@v2.0.0
go list 命令以及參數(shù)
go list -m -u all
參數(shù) | 作用 |
---|---|
-f | 用于查看對(duì)應(yīng)依賴結(jié)構(gòu)體中的指定的字段,其默認(rèn)值就是 {{.ImportPath}} 突梦,也就是導(dǎo)入路徑诫舅,因此我們一般不需要進(jìn)行調(diào)整 |
-json | 顯示的格式,若不指定該選項(xiàng)宫患,則會(huì)一行行輸出刊懈。 |
-u | 顯示能夠升級(jí)的模塊信息 |
-m | 顯示當(dāng)前項(xiàng)目所依賴的全部模塊 |
比如查看 gin
框架的版本
go list -m -versions -json github.com/gin-gonic/gin
輸出如下:
{
"Path": "github.com/gin-gonic/gin",
"Version": "v1.7.7",
"Versions": [
"v1.1.1",
"v1.1.2",
"v1.1.3",
"v1.1.4",
"v1.3.0",
"v1.4.0",
"v1.5.0",
"v1.6.0",
"v1.6.1",
"v1.6.2",
"v1.6.3",
"v1.7.0",
"v1.7.1",
"v1.7.2",
"v1.7.3",
"v1.7.4",
"v1.7.6",
"v1.7.7"
],
"Time": "2021-11-24T13:54:13Z",
"Dir": "/Users/pudongping/go/pkg/mod/github.com/gin-gonic/gin@v1.7.7",
"GoMod": "/Users/pudongping/go/pkg/mod/cache/download/github.com/gin-gonic/gin/@v/v1.7.7.mod",
"GoVersion": "1.13"
}
私有庫(kù)使用 Go Modules 時(shí)
- 需要將
GOPRIVATE
環(huán)境變量設(shè)置成你私有庫(kù)的域名
# GO111MODULE 設(shè)置成 on 或者 auto 都行
GO111MODULE="auto"
# GOPROXY 最好設(shè)置成國(guó)內(nèi)鏡像地址
GOPROXY="https://goproxy.cn,direct"
# GOPRIVATE 一定要設(shè)置成你的私有庫(kù)域名,比如
GOPRIVATE="gitlab.xxx.com"
- 然后執(zhí)行以下命令即可娃闲。注意:前提是你能夠通過(guò) ssh 公鑰拉取代碼
# 以下假設(shè)我私有 git 倉(cāng)庫(kù)地址為 gitlab.xxx.com:2222
# 那么則需要調(diào)整為
cat << EOF >> ~/.gitconfig
[url "ssh://git@gitlab.xxx.com:2222"]
insteadOf = https://gitlab.xxx.com
EOF
# 或者執(zhí)行(效果都是一樣的)
git config --global url."ssh://git@gitlab.xxx.com:2222".insteadof "https://gitlab.xxx.com"
- 測(cè)試一下下載一個(gè)包
# 僅僅作為示范虚汛,此地址根本就不存在
go get -v gitlab.xxx.com/utils/arrayx