前言
在上文中,我們介紹了gopath
的含義、功能、優(yōu)劣、以及如何通過(guò)GOPATH來(lái)組織項(xiàng)目
在本文中,我們將介紹go module
的原理和用法以試圖能夠回答下面的幾個(gè)問(wèn)題
是什么?
g
g
g
g
g
在go module
之前,有一些問(wèn)題長(zhǎng)期困擾go語(yǔ)言的開發(fā)人員
能否將go工程代碼脫離gopath
之外
go1.11開始支持,go1.13全面支持的go modules
正是為了解決上面的問(wèn)題誕生的,下面我們?cè)敿?xì)介紹go module
企圖解決的問(wèn)題
在介紹gopath
時(shí),我們介紹了如果導(dǎo)入為
實(shí)際引用的是$GOPATH/src/github.com/gobuffalo/buffalo
文件中的代碼。
也就是說(shuō),在gopath
中 ,導(dǎo)入路徑與項(xiàng)目在文件系統(tǒng)中的目錄結(jié)構(gòu)和名稱必須是匹配的。
那么能否import
路徑為github.com/gobuffalo/buffalo
,但是項(xiàng)目實(shí)際的路徑卻是在另一個(gè)任意的文件目錄中?(例如/users/gobuffalo/buffalo
).答案是肯定的,go module
通過(guò)在一個(gè)特殊的叫做go.mod
的文件中指定模塊名來(lái)解決這一問(wèn)題。
module .//
...
在go.mod文件的第一行指定了模塊名,模塊名表示開發(fā)人員可以用此來(lái)引用當(dāng)前代碼倉(cāng)庫(kù)中任何package
的路徑名,以此來(lái)替代$gopath
的路徑。從而,代碼倉(cāng)庫(kù)在任何位置都已經(jīng)沒(méi)有關(guān)系,因?yàn)镚o工具可以使用模塊文件的位置和模塊名來(lái)解析代碼倉(cāng)庫(kù)中的任何內(nèi)部import
。
對(duì)于任何版本控制(VCS)工具,我們都能在任何代碼提交點(diǎn)打上"tag"標(biāo)記,如下所示:
更棘手的是,一個(gè)第三方包A可能引用了其他的第三方包B,因此還必須把第三方包A的全部依賴下載
因此,只通過(guò)gopath
維護(hù)單一的master包的方式是遠(yuǎn)遠(yuǎn)不夠的,因?yàn)橐蕾嚢淖钚麓a不一定與項(xiàng)目兼容。盡管go社區(qū)已經(jīng)針對(duì)以上問(wèn)題提供了一些解決方案(例如dep,godep,glide等)但是go官方的go moudle
提供了一種集成解決方案,通過(guò)在文件中維護(hù)直接和間接依賴項(xiàng)的版本列表來(lái)解決這一問(wèn)題。通過(guò)將一個(gè)特定版本的依賴項(xiàng)看做是捆綁的不可變的依賴項(xiàng),就叫做一個(gè)模塊(moudle)
為了加快構(gòu)建程序的速度并快速切換、獲取項(xiàng)目中依賴項(xiàng)的更新,Go維護(hù)了下載到本地計(jì)算機(jī)上的所有模塊的緩存,緩存目前默認(rèn)位于$GOPATH/pkg
目錄中。有g(shù)o的提議希望能夠自定義緩存的位置。
所在位置看上去如下所示:
go/
├── bin
├── pkg
├── darwin_amd64
└──
└── src
在mod目錄下,我們能夠看到模塊名路徑中的第一部分用作了模塊緩存中的頂級(jí)文件夾
~/go/pkg/ ? ls -l jackson@
drwxr-xr-x jackson staff : cache
drwxr-xr-x jackson staff : cloud.google.com
drwxr-xr-x jackson staff : git.apache.org
drwxr-xr-x jackson staff : github.com
drwxr-xr-x jackson staff : gitlab.followme.com
drwxr-xr-x jackson staff : go.etcd.
...
當(dāng)我們打開一個(gè)實(shí)際的模塊,例如github.com/nats-io
,我們會(huì)看到與nats庫(kù)有關(guān)許多模塊
~-io jackson@192
total
dr-x------ jackson staff gnatsd@v1.
dr-x------ jackson staff go-nats-streaming@v0.
dr-x------ jackson staff go-nats@v1.
dr-x------ jackson staff go-nats@v1.
...
為了擁有一個(gè)干凈的工作環(huán)境,我們可以用如下代碼清空緩存區(qū)。但是請(qǐng)注意,在正常的工作流程中,是不需要執(zhí)行如下代碼的。
$ go clean -modcache
我們從GOPATH
外開始一個(gè)新的項(xiàng)目講解,新建一個(gè)新建夾以及一個(gè)main
文件
cd
cd mathlib jackson@192
~dreamerjackson/mathlib
go mod init
指令的功能很簡(jiǎn)單,自動(dòng)生成一個(gè)go.mod
文件 后面緊跟的路徑即是自定義的模塊名。習(xí)慣上以托管代碼倉(cāng)庫(kù)的URL為模塊名(代碼將會(huì)放置在https://github.com/dreamerjackson/mathlib
下)
go.mod
文件 位于項(xiàng)目的根目錄下,內(nèi)容如下所示,第一行即為模塊名。
module .//
go
main
func {
}
我們?cè)诖a片段中導(dǎo)入了為了講解go moudle
而特地的引入的packagegithub.com/dreamerjackson/mydiv
,其進(jìn)行簡(jiǎn)單的除法操作,同時(shí)又引入了另一個(gè)包github.com/pkg/errors
。其代碼如下圖所示:
如下圖所示,在goland中我們可以看到導(dǎo)入的package 是紅色的,因?yàn)榇藭r(shí)在go module的緩存并不能找到此package。
為了能夠?qū)⒋藀ackage下載到本地,我們可以使用go mod tidy
指令
$ mod tidy
: finding github.com/dreamerjackson/mydiv latest
: downloading github.com/dreamerjackson/mydiv v0-fdd187670161
: extracting github.com/dreamerjackson/mydiv v0-fdd187670161
同時(shí)我們?cè)?code>go.mod中能夠看到新增加了一行用于表示我們引用的依賴關(guān)系
module .//
go
github.com/dreamerjackson/mydiv v..--fdd187670161
注意在這里間接的依賴(即github.com/dreamerjackson/mydiv
依賴的github.com/pkg/errors
)并沒(méi)有也沒(méi)有必要在go.mod
文件展示出來(lái),而是出現(xiàn)在了一個(gè)自動(dòng)生成的新的文件go.sum
中.
## .sum
github.com/dreamerjackson/mydiv v0-fdd187670161 h2:QR1fJ05yjzJ0qv1gcUS+gAe5Q3UU5Y0le6TIb2pcJpQ=
github.com/dreamerjackson/mydiv v0-fdd187670161/.mod h2:h70Xf3RkhKSNbUF8W3htLNJskYJSITf6AdEGK22QksQ=
github.com/pkg/errors v0 h2:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0/.mod h2:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
main
(
)
func {
res,_ :=mydiv.Div(,)
fmt.Println(res)
}
運(yùn)行go run
命令后,即會(huì)為我們輸出除法結(jié)果2
有多種方式可以實(shí)現(xiàn)依賴模塊的更新,在go.mod
文件中修改版本號(hào)為:
github.com/dreamerjackson/mydiv latest
或者
github.com/dreamerjackson/mydiv master
獲取復(fù)制commitId 到最后
github.com/dreamerjackson/mydiv c9a7ffa8112626ba6c85619d7fd98122dd49f850
還有一種辦法是在終端當(dāng)前項(xiàng)目中,運(yùn)行go get
go github.com/dreamerjackson/mydiv
上述幾種方式在保存文件后,再次運(yùn)行go mod tidy
即會(huì)進(jìn)行更新
此時(shí)如果我們?cè)俅未蜷_go.sum
文件會(huì)發(fā)現(xiàn),go.sum
中不僅僅存儲(chǔ)了直接和間接的依賴,還會(huì)存儲(chǔ)過(guò)去的版本信息。
github.com/dreamerjackson/mydiv v0-fdd187670161 h2:QR1fJ05yjzJ0qv1gcUS+gAe5Q3UU5Y0le6TIb2pcJpQ=
github.com/dreamerjackson/mydiv v0-fdd187670161/go. h2:h70Xf3RkhKSNbUF8W3htLNJskYJSITf6AdEGK22QksQ=
github.com/dreamerjackson/mydiv v0-c9a7ffa81126/go. h2:h70Xf3RkhKSNbUF8W3htLNJskYJSITf6AdEGK22QksQ=
github.com/pkg/errors v0 h2:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0/go. h2:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
當(dāng)我們不想在使用此第三方包時(shí),可以直接在代碼中刪除無(wú)用的代碼,接著執(zhí)行
$ go mod tidy
會(huì)發(fā)現(xiàn)go.mod
與go.sum
一切又都空空如也~
Go決定采用其他方法,Russ Cox花費(fèi)了大量時(shí)間和精力撰寫和談?wù)?Go團(tuán)隊(duì)的版本選擇方法,即最小版本選擇(Minimal Version Selection,MVS)。從本質(zhì)上講,Go團(tuán)隊(duì)相信MVS可以為Go程序提供最佳的機(jī)會(huì),以實(shí)現(xiàn)兼容性和可重復(fù)性。我建議閱讀這篇文章,以了解Go團(tuán)隊(duì)為什么相信這一點(diǎn)。
舉一個(gè)簡(jiǎn)單的例子,假設(shè)現(xiàn)在項(xiàng)目github.com/dreamerjackson/mydiv
的最新版本為v1.0.2
,可通過(guò)下面指令查看所有
> go -m -versions github.com/dreamerjackson/mydiv
github.com/dreamerjackson/mydiv v1 v1 v1 v1
假設(shè)現(xiàn)在有兩個(gè)模塊A、B,都依賴模塊D。其中
> ,
>
如果我們的當(dāng)前項(xiàng)目只依賴A,這個(gè)時(shí)候go module
會(huì)如何選擇呢?像dep這樣的依賴工具將選擇v1.0.3,即最新的語(yǔ)義版本控制。但是在go module
中,最小版本選擇原理將遵循A項(xiàng)目聲明的版本,即v1.0.1
為了驗(yàn)證最小版本選擇原理,作者嘔心瀝血設(shè)計(jì)了一個(gè)簡(jiǎn)單的示例。
以項(xiàng)目github.com/dreamerjackson/mydiv
為例,讀者可以將其看做上節(jié)中的模塊D
,其v1.0.1
與v1.0.2
版本的代碼如下,只是簡(jiǎn)單的改變了錯(cuò)誤返回的字符串。
## v1
mydiv
func int,b ) int,error){
b=={
,errors.Errorf()
}
a/b,
}
## v1
mydiv
func int,b ) int,error){
b=={
,errors.Errorf()
}
a/b,
}
接著模塊B
即github.com/dreamerjackson/minidiv
引用了模塊D即github.com/dreamerjackson/mydiv
v1.0.1版本
## 模塊B
div
(
)
func int,b ) int,error){
mydiv.Div(a,b)
}
最后當(dāng)前的項(xiàng)目,我們將其稱為模塊Now
直接依賴了模塊D v1.0.2,同時(shí)依賴了模塊B
main
(
div
)
func {
_,err1:= mydiv.Div(,)
_,err2 := div.Div(,)
fmt.Println(err1,err2)
}
當(dāng)前的依賴關(guān)系如下:
當(dāng)前模塊 > 模塊
當(dāng)前模塊 > 模塊 > 模塊
$ run main.
v1 b cant =
第二種方式是使用go list
指令
~/mathlib ? go -m all | grep mydiv
github.com/dreamerjackson/mydiv v1
我們還可以通過(guò)使用go mod mhy
z指令,查看在哪里引用了包github.com/dreamerjackson/mydiv
~/mathlib ? go why github.com/dreamerjackson/mydiv
github.com/dreamerjackson/mathlib
github.com/dreamerjackson/mydiv
我們可以使用go list -m -u all
指令查看直接和間接模塊的當(dāng)前和最新版本
~/mathlib ? list -m -u all | column -t jackson@
: finding github.com/dreamerjackson/minidiv latest
github.com/dreamerjackson/mathlib
github.com/dreamerjackson/minidiv v0-fcd15cf402bb
github.com/dreamerjackson/mydiv v1 [v1]
github.com/pkg/errors v0
如上所示,我們可以看到github.com/dreamerjackson/mydiv
的當(dāng)前版本為v1.0.2
,但是最新的版本為v1.0.3
獲取直接和間接模塊可以使用go get
指令。其中有不少的參數(shù)。
下面命令以最小版本原則
更新所有的直接和間接模塊
go -t -d -v ./...
-t
考慮構(gòu)建測(cè)試所需的模塊
-d
下載每個(gè)模塊的源代碼
-v
提供詳細(xì)輸出
./…
在整個(gè)源代碼樹中執(zhí)行這些操作,并且僅更新所需的依賴項(xiàng)
注意,除非你了解項(xiàng)目的所有細(xì)節(jié),否則慎用全部的大最新版本的更新
如果go get中使用-u
參數(shù)會(huì)用大最新版本
原則更新所有的直接和間接模塊
~/mathlib ? get -u -t -d -v ./... jackson@
: finding github.com/dreamerjackson/minidiv latest
: downloading github.com/dreamerjackson/mydiv v1
: extracting github.com/dreamerjackson/mydiv v1
接著我們可以再次查看當(dāng)前引用的版本,我們會(huì)發(fā)現(xiàn)模塊github.com/dreamerjackson/mydiv
已經(jīng)強(qiáng)制更新到了最新的v1.0.3
~/mathlib ? go -m all | grep mydiv jackson@
github.com/dreamerjackson/mydiv v1
如果您不滿意所選的模塊和版本,則始終可以通過(guò)刪除go.mod go.sum
模塊文件并再次運(yùn)行g(shù)o mod tidy來(lái)重置。當(dāng)項(xiàng)目還不太成熟時(shí)這是一種選擇。
$ rm go.*
$ go mod init <module >
$ go mod tidy
Go模塊引入了一種新的導(dǎo)入路徑語(yǔ)法,即語(yǔ)義導(dǎo)入版本控制。每個(gè)語(yǔ)義版本均采用vMAJOR.MINOR.PATCH的形式。
因此我們?cè)谏厦娴膶?shí)例中可以看到,go預(yù)料到v1.0.3與v1.0.1是兼容的,因?yàn)樗麄冇邢嗤闹靼姹咎?hào)1
v2.0.0
如上圖實(shí)例顯示了go對(duì)于版本更新的處理。my/thing/v2
標(biāo)識(shí)特定模塊的語(yǔ)義主版本2
。版本1是my/thing
,模塊路徑中沒(méi)有明確的版本。但是,當(dāng)您引入主要版本2或更大版本時(shí),必須在模塊名稱后添加版本,以區(qū)別于版本1和其他主要版本,因此版本2為my/thing/v2,版本3為my/thing/v3,依此類推。
> 模塊 > 模塊
> 模塊 > 模塊
首先我們給mydiv打一個(gè)v2.0.0的tag,其代碼如下,簡(jiǎn)單修改了錯(cuò)誤文字v2.0.0 b can't = 0
mydiv
func int,b ) int,error){
b=={
,errors.Errorf()
}
a/b,
}
module .///
main
(
div
mydiv
)
func {
_,err1:= mydiv.Div(,)
_,err2 := div.Div(,)
fmt.Println(err1,err2)
}
mathlib --> 直接引用mydiv v2
mathlib --> 直接引用minidiv --> 間接引用mydiv v1
當(dāng)我們運(yùn)行代碼之后,會(huì)發(fā)現(xiàn)兩段代碼是共存的
v2.0.0 b cant = 0
接著執(zhí)行go list
,模塊共存,驗(yàn)證成功~
~/mathlib(master*) ? go -m all | grep mydiv
github.com/dreamerjackson/mydiv v1
github.com/dreamerjackson/mydiv/v2 v2
模塊鏡像于2019年八月推出,是go官方1.13版本的默認(rèn)系統(tǒng)。模塊鏡像是一個(gè)代理服務(wù)器,以幫助加快構(gòu)建本地應(yīng)用程序所需的模塊的獲取。代理服務(wù)器實(shí)現(xiàn)了基于REST的API,并根據(jù)Go工具的需求進(jìn)行了設(shè)計(jì)。
模塊鏡像將會(huì)緩存已請(qǐng)求的模塊及其特定版本,從而可以更快地檢索將來(lái)的請(qǐng)求。一旦代碼被獲取并緩存在模塊鏡像中,就可以將其快速提供給世界各地的用戶。
checksum數(shù)據(jù)庫(kù)也于2019八月推出,是可以用來(lái)防止模塊完整性、有效性的手段。它驗(yàn)證特定版本的任何給定模塊代碼的正確性,而不管何人何時(shí)何地以及是如何獲取的。Google擁有唯一的校驗(yàn)和數(shù)據(jù)庫(kù),但是可以通過(guò)私有模塊鏡像對(duì)其進(jìn)行緩存。
有幾個(gè)環(huán)境變量可以控制與模塊鏡像和checksum數(shù)據(jù)庫(kù)有關(guān)的行為
GOPROXY:一組指向模塊鏡像的URL,用于獲取模塊。如果您希望Go工具僅直接從VCS地址獲取模塊,則可以將其設(shè)置為direct
。如果將此設(shè)置為off
,則將不會(huì)下載模塊
GOSUMDB:用于驗(yàn)證給定模塊/版本的代碼的checksum數(shù)據(jù)庫(kù)地址。此地址用于形成一個(gè)適當(dāng)?shù)腢RL,該URL告訴Go工具在哪里執(zhí)行這些checksum校驗(yàn)和查找。該URL可以指向Google擁有的checksum數(shù)據(jù)庫(kù),也可以指向支持對(duì)checksum數(shù)據(jù)庫(kù)進(jìn)行緩存或代理的本地模塊鏡像。如果您不希望Go工具驗(yàn)證添加到go.sum文件中的給定模塊/版本的哈希碼,也可以將其設(shè)置為off,僅在將任何新module添加到go.sum文件之時(shí),才查詢checksum數(shù)據(jù)庫(kù)
GOPRIVATE:一個(gè)方便變量,用于將GONOPROXY和GONOSUMDB設(shè)置為相同的默認(rèn)值
我們可以通過(guò)go env
來(lái)查看到這些默認(rèn)值
$ go env
GONOPROXY=
GONOSUMDB=
GOPRIVATE=
GOPROXY=
GOSUMDB=
例如,如果我們需要訪問(wèn)所有代理服務(wù)器,例如需要權(quán)限的位于gitlab
等地的代碼,我們可以使用export GOPRIVATE=gitlab.XXX.com,gitlab.XXX-XX.com,XXX.io
多個(gè)域名用逗號(hào)分隔。
Athens是一個(gè)私有模塊鏡像,可以用于搭建私有模塊鏡像。使用私有模塊鏡像的一個(gè)原因是允許緩存公共模塊鏡像無(wú)法訪問(wèn)的私有模塊。Athens項(xiàng)目提供了一個(gè)在Docker Hub
上發(fā)布的Docker
容器,因此不需要特殊的安裝。
run -p gomods/athens:latest
接下來(lái),啟動(dòng)一個(gè)新的終端會(huì)話以運(yùn)行Athens,為大家演示其用法。啟動(dòng)Athens服務(wù)并通過(guò)額外的參數(shù)調(diào)試日志(請(qǐng)確保系統(tǒng)已經(jīng)安裝并啟動(dòng)了docker)并有科學(xué)*上網(wǎng)的環(huán)境
$ docker run -p -e ATHENS_LOG_LEVEL=debug -e GO_ENV=development gomods/latest
INFO[AM]: Exporter specified. Traces won2020-03-06 07:11:30.671249 I | Starting application at port :3000
接著我們修改GOPROXY參數(shù),指向本地3000
端口,初始化我們之前的項(xiàng)目,再次執(zhí)行go mod tidy
export GOPROXY=
在Athens日志中即可查看對(duì)應(yīng)信息
INFO[AM]: incoming request http-method=GET http-path=@v/list http-status=
INFO[AM]: incoming request http-method=GET http-path=@v/list http-status=
INFO[AM]: incoming request http-method=GET http-path=@latest http-status=
提供脫離gopath
管理go代碼的優(yōu)勢(shì)
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。
名稱欄目:golang中的gomodule的介紹和使用方法-創(chuàng)新互聯(lián)
標(biāo)題來(lái)源:http://chinadenli.net/article0/dgpiio.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站設(shè)計(jì)、品牌網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)、響應(yīng)式網(wǎng)站、做網(wǎng)站、自適應(yīng)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容