Skip to content

Commit

Permalink
tools/api: support fully-qualified type names in *.proto files (env…
Browse files Browse the repository at this point in the history
…oyproxy#10774)

tools/api should support fully-qualified type names in *.proto files

Risk Level: Low
Testing: manual
Docs Changes: N/A
Release Notes: N/A

Fixes: envoyproxy#10755

Signed-off-by: Yaroslav Skopets <[email protected]>
  • Loading branch information
yskopets authored Apr 16, 2020
1 parent bbb261f commit e615e99
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 0 deletions.
27 changes: 27 additions & 0 deletions tools/protoxform/protoprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,33 @@ def NormalizeFieldTypeName(type_context, field_fqn):
remaining_field_fqn_splits = deque(field_fqn_splits[:-1])
normalized_splits = deque([field_fqn_splits[-1]])

if list(remaining_field_fqn_splits)[:1] != type_context_splits[:1] and (
len(remaining_field_fqn_splits) == 0 or
remaining_field_fqn_splits[0] in type_context_splits[1:]):
# Notice that in some cases it is error-prone to normalize a type name.
# E.g., it would be an error to replace ".external.Type" with "external.Type"
# in the context of "envoy.extensions.type.external.vX.Config".
# In such a context protoc resolves "external.Type" into
# "envoy.extensions.type.external.Type", which is exactly what the use of a
# fully-qualified name ".external.Type" was meant to prevent.
#
# A type SHOULD remain fully-qualified under the following conditions:
# 1. its root package is different from the root package of the context type
# 2. EITHER the type doesn't belong to any package at all
# OR its root package has a name that collides with one of the packages
# of the context type
#
# E.g.,
# a) although ".some.Type" has a different root package than the context type
# "TopLevelType", it is still safe to normalize it into "some.Type"
# b) although ".google.protobuf.Any" has a different root package than the context type
# "envoy.api.v2.Cluster", it still safe to normalize it into "google.protobuf.Any"
# c) it is error-prone to normalize ".TopLevelType" in the context of "some.Type"
# into "TopLevelType"
# d) it is error-prone to normalize ".external.Type" in the context of
# "envoy.extensions.type.external.vX.Config" into "external.Type"
return field_fqn

def EquivalentInTypeContext(splits):
type_context_splits_tmp = deque(type_context_splits)
while type_context_splits_tmp:
Expand Down
2 changes: 2 additions & 0 deletions tools/testdata/protoxform/envoy/v2/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ proto_library(
name = "fix_protos",
srcs = [
"discovery_service.proto",
"fully_qualified_names.proto",
"oneof.proto",
"package_move.proto",
"sample.proto",
],
visibility = ["//visibility:public"],
deps = [
"//tools/testdata/protoxform/external:external_protos",
"@com_github_cncf_udpa//udpa/annotations:pkg",
"@envoy_api//envoy/annotations:pkg",
"@envoy_api//envoy/api/v2:pkg",
Expand Down
31 changes: 31 additions & 0 deletions tools/testdata/protoxform/envoy/v2/fully_qualified_names.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
syntax = "proto3";

package envoy.v2;

import "envoy/api/v2/core/base.proto";

import "tools/testdata/protoxform/external/root_type.proto";
import "tools/testdata/protoxform/external/package_type.proto";

import "google/protobuf/any.proto";

import "udpa/annotations/migrate.proto";
import "udpa/annotations/status.proto";

option (udpa.annotations.file_migrate).move_to_package = "envoy.external.v3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// Verifies normalization of fully-qualified type names.
message UsesFullyQualifiedTypeNames {

envoy.api.v2.core.Locality another_envoy_type = 1;
.envoy.api.v2.core.Locality another_envoy_type_fqn = 2;

google.protobuf.Any google_protobuf_any = 3;
.google.protobuf.Any google_protobuf_any_fqn = 4;

external.PackageLevelType external_package_level_type = 5;
.external.PackageLevelType external_package_level_type_fqn = 6;

.RootLevelType external_root_level_type_fqn = 7;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
syntax = "proto3";

package envoy.v2;

import "envoy/api/v2/core/base.proto";

import "google/protobuf/any.proto";

import "tools/testdata/protoxform/external/package_type.proto";
import "tools/testdata/protoxform/external/root_type.proto";

import "udpa/annotations/migrate.proto";
import "udpa/annotations/status.proto";

option java_package = "io.envoyproxy.envoy.v2";
option java_outer_classname = "FullyQualifiedNamesProto";
option java_multiple_files = true;
option (udpa.annotations.file_migrate).move_to_package = "envoy.external.v3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// Verifies normalization of fully-qualified type names.
// [#next-free-field: 8]
message UsesFullyQualifiedTypeNames {
api.v2.core.Locality another_envoy_type = 1;

api.v2.core.Locality another_envoy_type_fqn = 2;

google.protobuf.Any google_protobuf_any = 3;

google.protobuf.Any google_protobuf_any_fqn = 4;

external.PackageLevelType external_package_level_type = 5;

external.PackageLevelType external_package_level_type_fqn = 6;

.RootLevelType external_root_level_type_fqn = 7;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
syntax = "proto3";

package envoy.external.v3;

import "envoy/api/v2/core/base.proto";

import "google/protobuf/any.proto";

import "tools/testdata/protoxform/external/package_type.proto";
import "tools/testdata/protoxform/external/root_type.proto";

import "udpa/annotations/status.proto";
import "udpa/annotations/versioning.proto";

option java_package = "io.envoyproxy.envoy.external.v3";
option java_outer_classname = "FullyQualifiedNamesProto";
option java_multiple_files = true;
option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSION_CANDIDATE;

// Verifies normalization of fully-qualified type names.
// [#next-free-field: 8]
message UsesFullyQualifiedTypeNames {
option (udpa.annotations.versioning).previous_message_type =
"envoy.v2.UsesFullyQualifiedTypeNames";

api.v2.core.Locality another_envoy_type = 1;

api.v2.core.Locality another_envoy_type_fqn = 2;

google.protobuf.Any google_protobuf_any = 3;

google.protobuf.Any google_protobuf_any_fqn = 4;

.external.PackageLevelType external_package_level_type = 5;

.external.PackageLevelType external_package_level_type_fqn = 6;

.RootLevelType external_root_level_type_fqn = 7;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
syntax = "proto3";

package envoy.external.v3;

import "envoy/api/v2/core/base.proto";

import "google/protobuf/any.proto";

import "tools/testdata/protoxform/external/package_type.proto";
import "tools/testdata/protoxform/external/root_type.proto";

import "udpa/annotations/status.proto";
import "udpa/annotations/versioning.proto";

option java_package = "io.envoyproxy.envoy.external.v3";
option java_outer_classname = "FullyQualifiedNamesProto";
option java_multiple_files = true;
option (udpa.annotations.file_status).package_version_status = NEXT_MAJOR_VERSION_CANDIDATE;

// Verifies normalization of fully-qualified type names.
// [#next-free-field: 8]
message UsesFullyQualifiedTypeNames {
option (udpa.annotations.versioning).previous_message_type =
"envoy.v2.UsesFullyQualifiedTypeNames";

api.v2.core.Locality another_envoy_type = 1;

api.v2.core.Locality another_envoy_type_fqn = 2;

google.protobuf.Any google_protobuf_any = 3;

google.protobuf.Any google_protobuf_any_fqn = 4;

.external.PackageLevelType external_package_level_type = 5;

.external.PackageLevelType external_package_level_type_fqn = 6;

.RootLevelType external_root_level_type_fqn = 7;
}
11 changes: 11 additions & 0 deletions tools/testdata/protoxform/external/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
licenses(["notice"]) # Apache 2

proto_library(
name = "external_protos",
srcs = [
"package_type.proto",
"root_type.proto",
],
visibility = ["//visibility:public"],
deps = [],
)
10 changes: 10 additions & 0 deletions tools/testdata/protoxform/external/package_type.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
syntax = "proto3";

package external;

// Type that belongs to a non-envoy package.
//
// Part of a test suite that verifies normalization of
// fully-qualified type names.
message PackageLevelType {
}
8 changes: 8 additions & 0 deletions tools/testdata/protoxform/external/root_type.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
syntax = "proto3";

// Type that doesn't belong to any package.
//
// Part of a test suite that verifies normalization of
// fully-qualified type names.
message RootLevelType {
}

0 comments on commit e615e99

Please sign in to comment.