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