Миграция на Opaque API в Go

Описывает автоматизированную миграцию на Opaque API.

Opaque API — это последняя версия реализации Protocol Buffers для языка программирования Go. Старая версия теперь называется Open Struct API. Смотрите Go Protobuf: Releasing the Opaque API (блогпост) для введения.

Миграция на Opaque API происходит постепенно, для каждого proto-сообщения или файла .proto, путем установки функции api_level в одно из ее возможных значений:

  • API_OPEN выбирает Open Struct API. Это было портировано обратно в редакцию 2023, поэтому более старые версии плагина Go могут не учитывать это.
  • API_HYBRID — это шаг между Open и Opaque: Hybrid API также включает методы доступа (так что вы можете обновить свой код), но все еще экспортирует поля структуры как и раньше. Нет разницы в производительности; этот уровень API только помогает с миграцией.
  • API_OPAQUE выбирает Opaque API; это значение по умолчанию для Edition 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 помогает в этом.

Для вашего удобства вы также можете переопределить уровень API по умолчанию с помощью флага командной строки protoc:

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

{{% alert title="Примечание" color="info" %}} Если вы столкнетесь с какими-либо проблемами при автоматизированной миграции, обратитесь к Opaque API: Руководство по ручной миграции. {{% /alert %}}

Подготовка проекта

Убедитесь, что ваша среда сборки и проект используют достаточно свежие версии Protocol Buffers и Go Protobuf:

  1. Обновите компилятор protobuf (protoc) с страницы релизов protobuf до версии 29.0 или новее.

  2. Обновите плагин Go для компилятора protobuf (protoc-gen-go) до версии 1.36.0 или новее:

    go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
    
  3. В каждом проекте обновите файл go.mod, чтобы использовать модуль protobuf версии 1.36.0 или новее:

    go get google.golang.org/protobuf@latest
    

    {{% alert title="Примечание" color="note" %}} Если вы еще не импортируете google.golang.org/protobuf, вы, возможно, все еще используете старый модуль. Смотрите анонс google.golang.org/protobuf (от 2020) и мигрируйте ваш код, прежде чем вернуться на эту страницу. {{% /alert %}}

Шаг 1. Переход на Hybrid API

Используйте инструмент open2opaque, чтобы перевести ваши файлы .proto на Hybrid API:

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

Затем перекомпилируйте ваши протокольные буферы.

Ваш существующий код продолжит собираться. 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 включает все перезаписи, включая те, которые требуют проверки человеком. Доступны следующие уровни:

  • зеленый: Безопасные перезаписи (высокая уверенность). Включает большинство изменений, которые делает инструмент. Эти изменения не требуют пристального взгляда и могут быть даже отправлены автоматизацией, без какого-либо человеческого надзора.
  • желтый: (разумная уверенность) Эти перезаписи требуют проверки человеком. Они должны быть правильными, но пожалуйста, проверьте их.
  • красный: Потенциально опасные перезаписи, изменяющие редкие и сложные шаблоны. Они требуют тщательной проверки человеком. Например, когда существующая функция принимает параметр *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 FAQ. Если это не ответит на ваш вопрос или не решит вашу проблему, смотрите Где можно задать вопросы или сообщить о проблемах?