Go Opaque API 遷移

描述自動化遷移至 Opaque API 的過程。

Opaque API 是 Protocol Buffers 針對 Go 程式語言實作的最新版本。舊版本現在稱為 Open Struct API。請參閱Go Protobuf:發布 Opaque API 部落格文章以取得簡介。

遷移至 Opaque API 是逐步進行的,以每個 proto 訊息或每個 .proto 檔案為基礎,透過將 Protobuf Editions 功能 api_level 選項設定為其中一個可能的值

  • API_OPEN 選擇 Open Struct API;這是 2024 年 12 月之前唯一的 API。
  • API_HYBRID 是 Open 和 Opaque 之間的中間步驟:Hybrid API 也包含存取器方法 (因此您可以更新程式碼),但仍像以前一樣匯出 struct 欄位。效能上沒有差異;此 API 層級僅有助於遷移。
  • API_OPAQUE 選擇 Opaque API。

目前,預設值為 API_OPEN,但即將推出的Protobuf Edition 2024 將把預設值變更為 API_OPAQUE

若要在 Edition 2024 之前使用 Opaque API,請像這樣設定 api_level

edition = "2023";

package log;

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

message LogEntry {  }

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

為了您的方便,您也可以使用 protoc 命令列旗標覆寫預設 API 層級

protoc […] --go_opt=default_api_level=API_OPAQUE

若要覆寫特定檔案 (而非所有檔案) 的預設 API 層級,請使用 apilevelM 對應旗標 (類似於import 路徑的 M 旗標)

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

命令列旗標也適用於仍使用 proto2 或 proto3 語法的 .proto 檔案,但如果您想要從 .proto 檔案中選取 API 層級,則需要先將所述檔案遷移至 editions。

自動化遷移

我們盡力讓您盡可能輕鬆地將現有專案遷移至 Opaque API:我們的 open2opaque 工具完成了大部分工作!

若要安裝遷移工具,請使用

go install google.golang.org/open2opaque@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")

您現有的程式碼將繼續建置。Hybrid API 是 Open 和 Opaque API 之間的中間步驟,它新增了新的存取器方法,但保持 struct 欄位可見。

步驟 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)

另一個常見的範例是使用 struct 常值初始化 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 參數時,如果函數旨在透過寫入指標來變更欄位值 (*foo = "value"),則使用 proto.String(msg.GetFoo()) 的典型修復方法將無法運作。

許多程式可以使用綠色變更完全遷移。在您可以將 proto 訊息或檔案遷移至 Opaque API 之前,您需要完成所有層級的所有重寫,屆時您的程式碼中將不再有直接的 struct 存取。

步驟 3. 遷移與驗證

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

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

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

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

有問題嗎?遇到問題?

首先,查看Opaque API 常見問題。如果這無法回答您的問題或解決您的問題,請參閱我可以在哪裡提出問題或回報問題?