Golang 1.16中Module機(jī)制更新
最近,Golang發(fā)布了一個(gè)新版本1.16。版本引入了很多新功能,其中在模塊方面的改進(jìn),今天我們就一起來(lái)深入學(xué)習(xí)一下。
默認(rèn)情況下開(kāi)啟go module
go命令現(xiàn)在默認(rèn)情況下以模塊感知模式構(gòu)建軟件包,即使項(xiàng)目中沒(méi)有g(shù)o.mod也默認(rèn)啟動(dòng),這將對(duì)模塊的全面使用起到重要作用。但是通過(guò)環(huán)境變量GO111MODULE設(shè)置為 off下,GOPATH模式仍然可用。
如果將GO111MODULE設(shè)置為auto,則會(huì)檢測(cè)項(xiàng)目當(dāng)前目錄或任何父目錄,如果其中存在go.mod文件,就會(huì)啟用模塊感知模式。這以前是默認(rèn)設(shè)置。
如果要永久設(shè)置該選項(xiàng),可以使用go env -w設(shè)置:
- go env -w GO111MODULE=auto
據(jù)悉,Golang下個(gè)版本1.17中將完全放棄對(duì)GOPATH模式的支持。Golang1.17會(huì)忽略GO111MODULE變量設(shè)置。如果項(xiàng)目是以非模塊感知模式構(gòu)建的,請(qǐng)記得遷移。
不再自動(dòng)更改go.mod和go.sum
此前,當(dāng)go命令發(fā)現(xiàn)問(wèn)題,go.mod或go.sum中的配置為不全的require指令或未設(shè)置sum值,go命令會(huì)自動(dòng)嘗試補(bǔ)全解決這個(gè)問(wèn)題。但是該機(jī)制可能存在問(wèn)題,會(huì)導(dǎo)致副作用:如果必需的模塊未提供require所需的軟件包,則go命令會(huì)添加新的依賴(lài)項(xiàng),這可能會(huì)觸發(fā)常見(jiàn)依賴(lài)項(xiàng)的升級(jí)。有些明顯拼寫(xiě)錯(cuò)誤路徑也會(huì)耗費(fèi)時(shí)間去從進(jìn)行網(wǎng)絡(luò)查詢(xún)。
在Go 1.16中,支持模塊的命令在發(fā)現(xiàn)問(wèn)題后,go.mod或go.sum嘗試自動(dòng)修復(fù)問(wèn)題時(shí)會(huì)報(bào)告錯(cuò)誤。在大多數(shù)情況下,錯(cuò)誤消息建議你通過(guò)命令來(lái)解決。
注意go get和go mod tidy還是會(huì)修改go.mod和go.sum。
安裝特定版本模塊
我們知道可以通過(guò)通過(guò)指定@version后綴讓go install現(xiàn)安裝特定版本的可執(zhí)行文件。比如
- go install golang /x/tools/gopls@v0.6.5
使用該語(yǔ)法時(shí),go install使用確切模塊版本安裝命令,而會(huì)忽略go.mod當(dāng)前目錄和父目錄中的所有文件。
曾建議go get -u program安裝一個(gè)可執(zhí)行文件,但是該用法與go get中添加或更改模塊版本要求的含義容易造成了混淆。為了避免意外修改go.mod,一般使用更復(fù)雜的命令,例如:
- cd $HOME; GO111MODULE=on go get program@latest
在Go 1.16中,默認(rèn)可以使用go install program@latest的語(yǔ)法。
為了消除關(guān)于使用go.mod的歧義,使用此安裝語(yǔ)法時(shí),程序文件中可能存在的指令有一些限制。特別是,至少目前不允許使用replace和exclude指令。
模塊回退
大家可能遇到過(guò)意外發(fā)布了模塊版本的尷尬處境,或者在發(fā)布需要快速修復(fù)的版本后又馬上發(fā)現(xiàn)問(wèn)題問(wèn)題的場(chǎng)景,版本發(fā)布中的錯(cuò)誤很難糾正。為了保持模塊構(gòu)建的確定性,發(fā)布版本后不能對(duì)其進(jìn)行修改。即使刪除或更改了版本標(biāo)簽,proxy.golang其他代理也可能對(duì)其進(jìn)行了緩存。
在新版本中,模塊作者可以在go.mod中retract指令撤消模塊版本。回退的版本仍然存在并且可以下載(因此依賴(lài)它的版本不會(huì)中斷),但是go get和go list命令在解析諸如@latest標(biāo)簽時(shí)候,不會(huì)再自動(dòng)選擇它,而且會(huì)打印一條諸如下面例子的告警信息信息。
例如,假設(shè)一個(gè)庫(kù)的cc/lib開(kāi)發(fā)者發(fā)布了v1.0.5,然后發(fā)現(xiàn)一個(gè)新的安全問(wèn)題。開(kāi)發(fā)者可以將指令添加到其go.mod文件中,如下所示:
- // Remote-triggered crash in package cc. See CVE-2021-xxxx.
- retract v1.0.5
然后可以標(biāo)記并推送v1.0.6最新修復(fù)版本。此后,v1.0.5當(dāng)檢查更新或升級(jí)從屬軟件包時(shí),就會(huì)通知已依賴(lài)的用戶將撤消通知。通知消息可能包含retract語(yǔ)句上面注釋中的文本。
- go list -m -u all
- cc/lib v1.0.0 (retracted)
- go get .
- go: warning: cc/lib@v1.0.5: retracted by module author:
- Remote-triggered crash in package cc. See CVE-2021-xxxx.
- go: to switch to the latest unretracted version, run:
- go get cc/lib@latest
基于GOVCS進(jìn)行版本控制
go命令可以直接從源碼鏡像下載源碼,比如proxy.golang。也可以直接從常見(jiàn)版本管理倉(cāng)庫(kù),比如git,hg,svn,bzr,或fossil。直接從版本控制訪問(wèn)非常重要,尤其是對(duì)于代理中不可用的私有模塊而言,但這也是個(gè)安全風(fēng)險(xiǎn)點(diǎn),版本控制工具中的bug可能被惡意利用,并運(yùn)行精心設(shè)置的代碼。
Go 1.16引入了一個(gè)新的配置變量GOVCS,用戶可以通過(guò)它指定允許哪些模塊使用特定的版本控制工具。GOVCS接受以逗號(hào)分隔的pattern:vcslist規(guī)則列表。pattern是一個(gè)path.Match模式匹配的一個(gè)或一個(gè)模塊路徑。特殊模式public與private匹配的公共模塊和私有模塊(private被定義為由模式匹配的模塊GOPRIVATE;public其他所有內(nèi)容)。vcslist是允許的版本控制命令或關(guān)鍵字分隔的列表all或off。比如:
- GOVCS=github.com:git,evil.com:off,*:git|hg
上面的語(yǔ)句設(shè)置可以使用github來(lái)下載git模塊。evil.com為禁止使用的站點(diǎn)路徑,*可以匹配下載其他模塊(使用git和hg。
如果GOVCS未設(shè)置,或者模塊與任何模式都不匹配,則go命令使用以下默認(rèn)值:git和hg允許用于公共模塊,并且允許使用所有工具用于私有模塊。僅允許使用Git和Mercurial的原因是,這兩個(gè)系統(tǒng)常常默認(rèn)作為,默認(rèn)不受信任客戶端運(yùn)行。而B(niǎo)azaar,F(xiàn)ossil和Subversion主要用于受信任的,經(jīng)過(guò)身份驗(yàn)證的環(huán)境,并且沒(méi)有像攻擊面那樣受到嚴(yán)格的審查。即,默認(rèn)設(shè)置為:
- GOVCS=public:git|hg,private:all