Änderungen angekündigt am 20. April 2023

Änderungen für Protocol Buffers angekündigt am 20. April 2023.

Änderungen am Ruby-Generator

Dieser GitHub PR, der in der Version 23.x erscheinen wird, ändert den Ruby-Code-Generator so, dass anstelle des DSL ein serialisiertes Proto ausgegeben wird.

Er entfernt das DSL aus dem Code-Generator, um das DSL in ein separates Paket auszulagern.

Gegeben eine .proto-Datei wie

syntax = "proto3";

package pkg;

message TestMessage {
  optional int32 i32 = 1;
  optional TestMessage msg = 2;
}

Generierter Code vorher

# Generated by the protocol buffer compiler.  DO NOT EDIT!
# source: protoc_explorer/main.proto

require 'google/protobuf'

Google::Protobuf::DescriptorPool.generated_pool.build do
  add_file("test.proto", :syntax => :proto3) do
    add_message "pkg.TestMessage" do
      proto3_optional :i32, :int32, 1
      proto3_optional :msg, :message, 2, "pkg.TestMessage"
    end
  end
end

module Pkg
  TestMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("pkg.TestMessage").msgclass
end

Generierter Code danach

# frozen_string_literal: true
# Generated by the protocol buffer compiler.  DO NOT EDIT!
# source: test.proto

require 'google/protobuf'

descriptor_data = "\n\ntest.proto\x12\x03pkg\"S\n\x0bTestMessage\x12\x10\n\x03i32\x18\x01 \x01(\x05H\x00\x88\x01\x01\x12\"\n\x03msg\x18\x02 \x01(\x0b\x32\x10.pkg.TestMessageH\x01\x88\x01\x01\x42\x06\n\x04_i32B\x06\n\x04_msgb\x06proto3"
begin
  Google::Protobuf::DescriptorPool.generated_pool.add_serialized_file(descriptor_data)
rescue TypeError => e
  # <compatibility code, see below>
end

module Pkg
  TestMessage = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("pkg.TestMessage").msgclass
end

Diese Änderung behebt fast alle verbleibenden Konformitätsprobleme, die zuvor bestanden. Dies ist ein Nebeneffekt der Umstellung vom DSL (das verlustbehaftet ist) auf einen serialisierten Deskriptor (der alle Informationen bewahrt).

Abwärtskompatibilität

Diese Änderung sollte zu 100 % kompatibel mit Ruby Protobuf >= 3.18.0 sein, das im September 2021 veröffentlicht wurde. Außerdem sollte sie mit allen bestehenden Benutzern und Bereitstellungen kompatibel sein.

Es gibt speziellen Kompatibilitätscode, der eingefügt wurde, um dieses Maß an Rückwärtskompatibilität zu erreichen, dessen Sie sich bewusst sein sollten. Ohne den Kompatibilitätscode gibt es einen Grenzfall, der die Rückwärtskompatibilität beeinträchtigen könnte. Der vorherige Code ist nachsichtig, während der neue Code strenger sein wird.

Bei der Verwendung eines vollständigen serialisierten Deskriptors enthält dieser eine Liste aller .proto-Dateien, die von dieser Datei importiert wurden (während das DSL Abhängigkeiten nie ordnungsgemäß hinzugefügt hat). Sehen Sie sich den Code in descriptor.proto an.

add_serialized_file überprüft, ob alle im Deskriptor aufgeführten Abhängigkeiten zuvor mit add_serialized_file hinzugefügt wurden. Im Allgemeinen sollte dies kein Problem sein, da der generierte Code Ruby require-Anweisungen für alle Abhängigkeiten enthält und der Deskriptor ohnehin nicht geladen werden kann, wenn die abhängigen Typen nicht zuvor im DescriptorPool definiert wurden.

Es besteht jedoch die Gefahr von Problemen, wenn es Mehrdeutigkeiten bei Dateipfaden gibt. Betrachten Sie zum Beispiel das folgende Szenario

// foo/bar.proto

syntax = "proto2";

message Bar {}
// foo/baz.proto

syntax = "proto2";

import "bar.proto";

message Baz {
  optional Bar bar = 1;
}

Wenn Sie protoc wie folgt aufrufen, funktioniert es korrekt

$ protoc --ruby_out=. -Ifoo foo/bar.proto foo/baz.proto
$ RUBYLIB=. ruby baz_pb.rb

Wenn Sie jedoch protoc wie folgt aufrufen und keinen Kompatibilitätscode hätten, würde das Laden fehlschlagen

$ protoc --ruby_out=. -I. -Ifoo foo/baz.proto
$ protoc --ruby_out=. -I. -Ifoo foo/bar.proto
$ RUBYLIB=foo ruby foo/baz_pb.rb
foo/baz_pb.rb:10:in `add_serialized_file': Unable to build file to DescriptorPool: Depends on file 'bar.proto', but it has not been loaded (Google::Protobuf::TypeError)
    from foo/baz_pb.rb:10:in `<main>'

Das Problem ist, dass bar.proto unter zwei verschiedenen kanonischen Namen referenziert wird: bar.proto und foo/bar.proto. Dies ist ein Benutzerfehler: Jeder Import sollte immer mit einem konsistenten vollständigen Pfad referenziert werden. Hoffentlich sind Benutzerfehler dieser Art selten, aber ohne Ausprobieren ist es schwer zu wissen.

Der Code in dieser Änderung gibt eine Warnung mit warn aus, wenn wir erkennen, dass dieser Grenzfall aufgetreten ist

$ RUBYLIB=foo ruby foo/baz_pb.rb
Warning: Protobuf detected an import path issue while loading generated file foo/baz_pb.rb
- foo/baz.proto imports bar.proto, but that import was loaded as foo/bar.proto
Each proto file must use a consistent fully-qualified name.
This will become an error in the next major version.

In diesem Fall gibt es zwei mögliche Lösungen. Eine besteht darin, konsistent den Namen bar.proto für den Import zu verwenden (entfernt -I.). Die andere besteht darin, konsistent den Namen foo/bar.proto für den Import zu verwenden (Änderung der Importzeile zu import "foo/bar.proto" und Entfernen von -Ifoo).

Wir planen, diesen Kompatibilitätscode in der nächsten Hauptversion zu entfernen.