Go Opaque API 遷移

描述了到 Opaque API 的自動化遷移。

Opaque API 是 Go 程式語言的 Protocol Buffers 實現的最新版本。舊版本現在稱為 Open Struct API。請參閱 Go Protobuf:釋出 Opaque API 部落格文章以獲取介紹。

遷移到 Opaque API 是增量進行的,基於每個 proto 訊息或每個 .proto 檔案,透過將 api_level 功能設定為其可能值之一來實現

  • API_OPEN 選擇 Open Struct API。這已向後移植到 2023 版中,因此舊版本的 Go 外掛可能不遵守它。
  • API_HYBRID 是 Open 和 Opaque 之間的一個步驟:混合 API 也包括訪問器方法(因此您可以更新您的程式碼),但仍像以前一樣匯出結構欄位。沒有效能差異;此 API 級別只對遷移有幫助。
  • API_OPAQUE 選擇 Opaque API;這是 2024 版及更新版本的預設設定。

要覆蓋特定 .proto 檔案的預設設定,請設定 api_level 功能

edition = "2024";

package log;

import "google/protobuf/go_features.proto";
option features.(pb.go).api_level = API_OPEN;

message LogEntry {  }

在您可以將現有檔案的 api_level 更改為 API_OPAQUE 之前,需要更新生成的 proto 程式碼的所有現有用法。open2opaque 工具可幫助完成此操作。

為方便起見,您還可以使用 protoc 命令列標誌覆蓋預設的 API 級別:

protoc […] --go_opt=default_api_level=API_OPEN

要為特定檔案 (而不是所有檔案) 覆蓋預設 API 級別,請使用 apilevelM 對映標誌 (類似於用於匯入路徑的 M 標誌):

protoc […] --go_opt=apilevelMhello.proto=API_OPEN

自動化遷移

我們努力使將現有專案遷移到 Opaque API 儘可能簡單:我們的 open2opaque 工具完成了大部分工作!

要安裝遷移工具,請使用

go install google.golang.org/open2opaque@latest
go install golang.org/x/tools/cmd/goimports@latest

專案準備

確保您的構建環境和專案正在使用足夠新的 Protocol Buffers 和 Go Protobuf 版本

  1. protobuf 釋出頁面 將 protobuf 編譯器 (protoc) 更新到 29.0 或更高版本。

  2. 將 protobuf 編譯器 Go 外掛 (protoc-gen-go) 更新到 1.36.0 或更高版本

    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    
  3. 在每個專案中,更新 go.mod 檔案以使用 1.36.0 或更高版本的 protobuf 模組

    go get google.golang.org/protobuf@latest
    

步驟 1. 切換到混合 API

使用 open2opaque 工具將您的 .proto 檔案切換到 Hybrid API

open2opaque setapi -api HYBRID $(find . -name "*.proto")

然後,重新編譯您的 protocol buffers。

您現有的程式碼將繼續構建。Hybrid API 是 Open 和 Opaque API 之間的一個步驟,它添加了新的訪問器方法但保持結構欄位可見。

步驟 2. open2opaque rewrite

要重寫您的 Go 程式碼以使用 Opaque API,請執行 open2opaque rewrite 命令

open2opaque rewrite -levels=red github.com/robustirc/robustirc/...

您可以指定一個或多個包或模式

例如,如果您有這樣的程式碼

logEntry := &logpb.LogEntry{}
if req.IPAddress != nil {
    logEntry.IPAddress = redactIP(req.IPAddress)
}
logEntry.BackendServer = proto.String(host)

該工具將重寫它以使用訪問器

logEntry := &logpb.LogEntry{}
if req.HasIPAddress() {
    logEntry.SetIPAddress(redactIP(req.GetIPAddress()))
}
logEntry.SetBackendServer(host)

另一個常見的例子是使用結構體字面量初始化 protobuf 訊息

return &logpb.LogEntry{
    BackendServer: proto.String(host),
}

在 Opaque API 中,等效的方法是使用 Builder

return logpb.LogEntry_builder{
    BackendServer: proto.String(host),
}.Build()

該工具將其可用的重寫分為不同的級別。-levels=red 引數啟用所有重寫,包括那些需要人工審查的。以下是可用的級別

  • green: 安全重寫(高置信度)。包括工具進行的大部分更改。這些更改不需要仔細檢視,甚至可以透過自動化提交,無需任何人工監督。
  • yellow: (合理置信度) 這些重寫需要人工審查。它們應該是正確的,但請仔細審查。
  • red: 潛在危險的重寫,改變了罕見而複雜的模式。這些需要仔細的人工審查。例如,當現有函式採用 *string 引數時,典型的修復方法是使用 proto.String(msg.GetFoo()),如果該函式旨在透過寫入指標來更改欄位值(*foo = "value"),則該方法不起作用。

許多程式可以透過僅進行綠色更改進行完全遷移。在您可以將 proto 訊息或檔案遷移到 Opaque API 之前,您需要完成所有級別的所有重寫,此時您的程式碼中不再存在直接的結構體訪問。

步驟 3. 遷移和驗證

要完成遷移,請使用 open2opaque 工具將您的 .proto 檔案切換到 Opaque API

open2opaque setapi -api OPAQUE $(find . -name "*.proto")

現在,任何尚未重寫為 Opaque API 的剩餘程式碼將不再編譯。

執行您的單元測試、整合測試和其他驗證步驟(如果有)。

有問題?有疑問?

首先,請檢視 Opaque API 常見問題。如果這不能回答您的問題或解決您的問題,請參閱 我可以在哪裡提問或報告問題?