Go 部落格

Go 1.16 的新模組變更

Jay Conrod
2021 年 2 月 18 日

希望您喜歡 Go 1.16!此版本帶來了許多新功能,尤其是針對模組。 釋出說明 簡要描述了這些更改,但讓我們深入探討其中一些。

模組預設啟用

go 命令現在預設以模組感知模式構建包,即使沒有 go.mod 檔案也是如此。這是在所有專案中推廣使用模組的重要一步。

透過設定 GO111MODULE 環境變數為 off,仍然可以在 GOPATH 模式下構建包。您也可以將 GO111MODULE 設定為 auto,僅在當前目錄或任何父目錄中存在 go.mod 檔案時啟用模組感知模式。這以前是預設設定。請注意,您可以使用 go env -w 永久設定 GO111MODULE 和其他變數。

go env -w GO111MODULE=auto

我們計劃在 Go 1.17 中放棄對 GOPATH 模式的支援。換句話說,Go 1.17 將忽略 GO111MODULE。如果您有不適合在模組感知模式下構建的專案,現在是時候遷移了。如果您有阻止您遷移的問題,請考慮提交一個 issue 或一個 experience report

go.mod 和 go.sum 無自動更改

以前,當 go 命令發現 go.modgo.sum 存在問題時,例如缺少 require 指令或缺少校驗和,它會嘗試自動修復問題。我們收到了大量反饋,認為這種行為令人驚訝,特別是對於像 go list 這樣通常沒有副作用的命令。自動修復並不總是理想的:如果匯入的包沒有由任何必需的模組提供,go 命令會新增一個新的依賴項,可能觸發常見依賴項的升級。即使是拼寫錯誤的匯入路徑也會導致(失敗的)網路查詢。

在 Go 1.16 中,模組感知命令在發現 go.modgo.sum 中的問題後會報告錯誤,而不是嘗試自動修復問題。在大多數情況下,錯誤訊息會推薦一個用於修復問題的命令。

$ go build
example.go:3:8: no required module provides package golang.org/x/net/html; to add it:
    go get golang.org/x/net/html
$ go get golang.org/x/net/html
$ go build

與之前一樣,go 命令可以使用 vendor 目錄(如果存在)(有關詳細資訊,請參閱 Vendoring)。像 go getgo mod tidy 這樣的命令仍然會修改 go.modgo.sum,因為它們的主要目的是管理依賴項。

安裝特定版本的可執行檔案

go install 命令現在可以透過指定 @version 字尾來安裝特定版本的可執行檔案。

go install golang.org/x/tools/gopls@v0.6.5

使用此語法時,go install 將安裝該精確模組版本的命令,忽略當前目錄及其父目錄中的任何 go.mod 檔案。(如果不帶 @version 字尾,go install 將繼續按原樣執行,使用當前模組的 go.mod 中列出的版本要求和替換來構建程式。)

我們過去曾推薦使用 go get -u program 來安裝可執行檔案,但這會與 go get 用於在 go.mod 中新增或更改模組版本要求的含義產生過多混淆。為了避免意外修改 go.mod,人們開始建議使用更復雜的命令,例如

cd $HOME; GO111MODULE=on go get program@latest

現在我們可以使用 go install program@latest 來代替。有關詳細資訊,請參閱 go install

為了消除有關使用哪個版本的歧義,當使用此安裝語法時,程式的 go.mod 檔案中允許存在的指令有一些限制。特別是,replaceexclude 指令目前不允許。長遠來看,一旦新的 go install program@version 在足夠多的用例中執行良好,我們計劃讓 go get 停止安裝命令二進位制檔案。有關詳細資訊,請參閱 issue 43684

模組撤回

您是否曾不小心在模組版本準備好之前釋出過它?或者在版本釋出後立即發現了一個需要快速修復的問題?已釋出版本的錯誤很難糾正。為了保持模組構建的確定性,已釋出版本在釋出後無法修改。即使您刪除或更改了版本標籤,proxy.golang.org 和其他代理可能已經快取了原始版本。

模組作者現在可以使用 go.mod 中的 retract 指令來 *撤回* 模組版本。已撤回的版本仍然存在並且可以下載(因此依賴於它的構建不會中斷),但 go 命令在解析如 @latest 這樣的版本時不會自動選擇它。go getgo list -m -u 將會列印關於現有使用的警告。

例如,假設一個流行的庫 example.com/lib 的作者釋出了 v1.0.5,然後發現了一個新的安全問題。他們可以在其 go.mod 檔案中新增如下指令:

// Remote-triggered crash in package foo. See CVE-2021-01234.
retract v1.0.5

接下來,作者可以標記並推送版本 v1.0.6,這是新的最高版本。此後,已經依賴 v1.0.5 的使用者將在檢查更新或升級依賴包時收到撤回通知。通知訊息可能包含 retract 指令上方的註釋文字。

$ go list -m -u all
example.com/lib v1.0.0 (retracted)
$ go get .
go: warning: example.com/lib@v1.0.5: retracted by module author:
    Remote-triggered crash in package foo. See CVE-2021-01234.
go: to switch to the latest unretracted version, run:
    go get example.com/lib@latest

對於互動式、基於瀏覽器的指南,請檢視 play-with-go.dev 上的 撤回模組版本。有關語法詳情,請參閱 retract 指令文件

使用 GOVCS 控制版本控制工具

go 命令可以從映象(如 proxy.golang.org)下載模組原始碼,或者直接從版本控制倉庫使用 githgsvnbzrfossil 下載。直接訪問版本控制很重要,特別是對於不在代理上的私有模組,但它也可能是一個安全問題:版本控制工具中的一個 bug 可能被惡意伺服器利用來執行未經授權的程式碼。

Go 1.16 引入了一個新的配置變數 GOVCS,它允許使用者指定哪些模組可以使用特定的版本控制工具。GOVCS 接受一個逗號分隔的 pattern:vcslist 規則列表。pattern 是一個 path.Match 模式,匹配模組路徑的一個或多個前導元素。特殊模式 publicprivate 分別匹配公共和私有模組(private 定義為 GOPRIVATE 中模式匹配的模組;public 是其他所有模組)。vcslist 是一個管道分隔的允許的版本控制命令列表,或者關鍵字 alloff

例如

GOVCS=github.com:git,evil.com:off,*:git|hg

使用此設定,可以透過 git 下載路徑在 github.com 上的模組;不能透過任何版本控制命令下載路徑在 evil.com 上的模組,並且所有其他路徑(* 匹配所有)可以使用 githg 下載。

如果未設定 GOVCS,或者模組不匹配任何模式,go 命令將使用以下預設設定:公共模組允許使用 githg,私有模組允許使用所有工具。允許僅使用 Git 和 Mercurial 的理由是,這兩個系統對作為不受信任伺服器的客戶端執行時的問題給予了最多的關注。相比之下,Bazaar、Fossil 和 Subversion 主要在受信任、已認證的環境中使用,並且沒有像攻擊面那樣受到嚴格審查。也就是說,預設設定是:

GOVCS=public:git|hg,private:all

有關詳細資訊,請參閱 使用 GOVCS 控制版本控制工具

下一步是什麼?

希望您覺得這些功能很有用。我們正在努力開發 Go 1.17 的下一組模組功能,特別是 延遲模組載入,這將使模組載入過程更快、更穩定。一如既往,如果您遇到新的 bug,請在 issue tracker 上告知我們。祝您編碼愉快!

下一篇文章:Contexts and structs
上一篇文章:Go 1.16 已釋出
部落格索引