Миграция на 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:
-
Обновите компилятор protobuf (protoc) с страницы релизов protobuf до версии 29.0 или новее.
-
Обновите плагин Go для компилятора protobuf (protoc-gen-go) до версии 1.36.0 или новее:
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest -
В каждом проекте обновите файл
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. Если это не ответит на ваш вопрос или не решит вашу проблему, смотрите Где можно задать вопросы или сообщить о проблемах?