From 0c1815fa9bbf2565748cc86c144feb451a4dadfb Mon Sep 17 00:00:00 2001 From: George Barnett Date: Tue, 18 Feb 2025 09:11:16 +0000 Subject: [PATCH 1/3] Add more plugin integration tests Motivation: The SwiftPM build plugin doesn't currently handle proto files with the same name even if they come from different packages. This happens because the build system cannot handle object files with the same name. This change adds such a test while tidying up some of the plugin test code. Modifications: - Divide up test resources in sources, config, and proto directories. - Have one function per test - Document each test with the expected structure - Add another test but don't run it. (It fails.) Result: More tests. The issue will be fixed in a separate change. --- ...y-1-grpc-swift-proto-generator-config.json | 0 ...nal-grpc-swift-proto-generator-config.json | 0 ...lic-grpc-swift-proto-generator-config.json | 0 .../{ => Protos}/Foo/foo-messages.proto | 0 .../{ => Protos}/Foo/foo-service.proto | 0 .../{ => Protos}/HelloWorld/HelloWorld.proto | 0 .../{ => Protos}/HelloWorld/Messages.proto | 0 .../{ => Protos}/HelloWorld/Service.proto | 0 .../Resources/Protos/noop/noop.proto | 9 + .../Resources/Protos/noop2/noop.proto | 9 + .../{ => Sources}/FooHelloWorldAdopter.swift | 0 .../{ => Sources}/HelloWorldAdopter.swift | 0 .../PluginTests/Resources/Sources/NoOp.swift | 43 ++++ .../Resources/{ => Sources}/Package.swift | 1 - dev/setup-plugin-tests.sh | 231 +++++++++++++----- 15 files changed, 233 insertions(+), 60 deletions(-) rename IntegrationTests/PluginTests/Resources/{ => Config}/import-directory-1-grpc-swift-proto-generator-config.json (100%) rename IntegrationTests/PluginTests/Resources/{ => Config}/internal-grpc-swift-proto-generator-config.json (100%) rename IntegrationTests/PluginTests/Resources/{ => Config}/public-grpc-swift-proto-generator-config.json (100%) rename IntegrationTests/PluginTests/Resources/{ => Protos}/Foo/foo-messages.proto (100%) rename IntegrationTests/PluginTests/Resources/{ => Protos}/Foo/foo-service.proto (100%) rename IntegrationTests/PluginTests/Resources/{ => Protos}/HelloWorld/HelloWorld.proto (100%) rename IntegrationTests/PluginTests/Resources/{ => Protos}/HelloWorld/Messages.proto (100%) rename IntegrationTests/PluginTests/Resources/{ => Protos}/HelloWorld/Service.proto (100%) create mode 100644 IntegrationTests/PluginTests/Resources/Protos/noop/noop.proto create mode 100644 IntegrationTests/PluginTests/Resources/Protos/noop2/noop.proto rename IntegrationTests/PluginTests/Resources/{ => Sources}/FooHelloWorldAdopter.swift (100%) rename IntegrationTests/PluginTests/Resources/{ => Sources}/HelloWorldAdopter.swift (100%) create mode 100644 IntegrationTests/PluginTests/Resources/Sources/NoOp.swift rename IntegrationTests/PluginTests/Resources/{ => Sources}/Package.swift (99%) diff --git a/IntegrationTests/PluginTests/Resources/import-directory-1-grpc-swift-proto-generator-config.json b/IntegrationTests/PluginTests/Resources/Config/import-directory-1-grpc-swift-proto-generator-config.json similarity index 100% rename from IntegrationTests/PluginTests/Resources/import-directory-1-grpc-swift-proto-generator-config.json rename to IntegrationTests/PluginTests/Resources/Config/import-directory-1-grpc-swift-proto-generator-config.json diff --git a/IntegrationTests/PluginTests/Resources/internal-grpc-swift-proto-generator-config.json b/IntegrationTests/PluginTests/Resources/Config/internal-grpc-swift-proto-generator-config.json similarity index 100% rename from IntegrationTests/PluginTests/Resources/internal-grpc-swift-proto-generator-config.json rename to IntegrationTests/PluginTests/Resources/Config/internal-grpc-swift-proto-generator-config.json diff --git a/IntegrationTests/PluginTests/Resources/public-grpc-swift-proto-generator-config.json b/IntegrationTests/PluginTests/Resources/Config/public-grpc-swift-proto-generator-config.json similarity index 100% rename from IntegrationTests/PluginTests/Resources/public-grpc-swift-proto-generator-config.json rename to IntegrationTests/PluginTests/Resources/Config/public-grpc-swift-proto-generator-config.json diff --git a/IntegrationTests/PluginTests/Resources/Foo/foo-messages.proto b/IntegrationTests/PluginTests/Resources/Protos/Foo/foo-messages.proto similarity index 100% rename from IntegrationTests/PluginTests/Resources/Foo/foo-messages.proto rename to IntegrationTests/PluginTests/Resources/Protos/Foo/foo-messages.proto diff --git a/IntegrationTests/PluginTests/Resources/Foo/foo-service.proto b/IntegrationTests/PluginTests/Resources/Protos/Foo/foo-service.proto similarity index 100% rename from IntegrationTests/PluginTests/Resources/Foo/foo-service.proto rename to IntegrationTests/PluginTests/Resources/Protos/Foo/foo-service.proto diff --git a/IntegrationTests/PluginTests/Resources/HelloWorld/HelloWorld.proto b/IntegrationTests/PluginTests/Resources/Protos/HelloWorld/HelloWorld.proto similarity index 100% rename from IntegrationTests/PluginTests/Resources/HelloWorld/HelloWorld.proto rename to IntegrationTests/PluginTests/Resources/Protos/HelloWorld/HelloWorld.proto diff --git a/IntegrationTests/PluginTests/Resources/HelloWorld/Messages.proto b/IntegrationTests/PluginTests/Resources/Protos/HelloWorld/Messages.proto similarity index 100% rename from IntegrationTests/PluginTests/Resources/HelloWorld/Messages.proto rename to IntegrationTests/PluginTests/Resources/Protos/HelloWorld/Messages.proto diff --git a/IntegrationTests/PluginTests/Resources/HelloWorld/Service.proto b/IntegrationTests/PluginTests/Resources/Protos/HelloWorld/Service.proto similarity index 100% rename from IntegrationTests/PluginTests/Resources/HelloWorld/Service.proto rename to IntegrationTests/PluginTests/Resources/Protos/HelloWorld/Service.proto diff --git a/IntegrationTests/PluginTests/Resources/Protos/noop/noop.proto b/IntegrationTests/PluginTests/Resources/Protos/noop/noop.proto new file mode 100644 index 0000000..fa8fc26 --- /dev/null +++ b/IntegrationTests/PluginTests/Resources/Protos/noop/noop.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +import "google/protobuf/empty.proto"; + +package noop; + +service NoOpService { + rpc NoOp(google.protobuf.Empty) returns (google.protobuf.Empty); +} diff --git a/IntegrationTests/PluginTests/Resources/Protos/noop2/noop.proto b/IntegrationTests/PluginTests/Resources/Protos/noop2/noop.proto new file mode 100644 index 0000000..db03888 --- /dev/null +++ b/IntegrationTests/PluginTests/Resources/Protos/noop2/noop.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +import "google/protobuf/empty.proto"; + +package noop2; + +service NoOpService { + rpc NoOp(google.protobuf.Empty) returns (google.protobuf.Empty); +} diff --git a/IntegrationTests/PluginTests/Resources/FooHelloWorldAdopter.swift b/IntegrationTests/PluginTests/Resources/Sources/FooHelloWorldAdopter.swift similarity index 100% rename from IntegrationTests/PluginTests/Resources/FooHelloWorldAdopter.swift rename to IntegrationTests/PluginTests/Resources/Sources/FooHelloWorldAdopter.swift diff --git a/IntegrationTests/PluginTests/Resources/HelloWorldAdopter.swift b/IntegrationTests/PluginTests/Resources/Sources/HelloWorldAdopter.swift similarity index 100% rename from IntegrationTests/PluginTests/Resources/HelloWorldAdopter.swift rename to IntegrationTests/PluginTests/Resources/Sources/HelloWorldAdopter.swift diff --git a/IntegrationTests/PluginTests/Resources/Sources/NoOp.swift b/IntegrationTests/PluginTests/Resources/Sources/NoOp.swift new file mode 100644 index 0000000..7dc5cef --- /dev/null +++ b/IntegrationTests/PluginTests/Resources/Sources/NoOp.swift @@ -0,0 +1,43 @@ +/* + * Copyright 2025, gRPC Authors All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import GRPCCore +import GRPCProtobuf +import SwiftProtobuf + +@main +struct PluginAdopter { + static func main() async throws { + } +} + +struct NoOp: Noop_NoOpService.SimpleServiceProtocol { + func noOp( + request: Google_Protobuf_Empty, + context: ServerContext + ) async throws -> Google_Protobuf_Empty { + return Google_Protobuf_Empty() + } +} + +struct NoOp2: Noop2_NoOpService.SimpleServiceProtocol { + func noOp( + request: Google_Protobuf_Empty, + context: ServerContext + ) async throws -> Google_Protobuf_Empty { + return Google_Protobuf_Empty() + } +} diff --git a/IntegrationTests/PluginTests/Resources/Package.swift b/IntegrationTests/PluginTests/Resources/Sources/Package.swift similarity index 99% rename from IntegrationTests/PluginTests/Resources/Package.swift rename to IntegrationTests/PluginTests/Resources/Sources/Package.swift index 9c13aaa..8f4d107 100644 --- a/IntegrationTests/PluginTests/Resources/Package.swift +++ b/IntegrationTests/PluginTests/Resources/Sources/Package.swift @@ -28,7 +28,6 @@ let package = Package( ], dependencies: [ // Dependency on grpc-swift-protobuf to be added by setup-plugin-tests.sh script - .package( url: "https://github.com/grpc/grpc-swift.git", from: "2.0.0" diff --git a/dev/setup-plugin-tests.sh b/dev/setup-plugin-tests.sh index 666c535..baeb59c 100755 --- a/dev/setup-plugin-tests.sh +++ b/dev/setup-plugin-tests.sh @@ -24,73 +24,186 @@ output_directory="${PLUGIN_TESTS_OUTPUT_DIRECTORY:=$(mktemp -d)}" here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" grpc_swift_protobuf_directory="$(readlink -f "${here}/..")" resources_directory="$(readlink -f "${grpc_swift_protobuf_directory}/IntegrationTests/PluginTests/Resources")" +config="${resources_directory}/Config" +sources="${resources_directory}/Sources" +protos="${resources_directory}/Protos" scratch_directory="$(mktemp -d)" +package_manifest="${scratch_directory}/Package.swift" echo "Output directory: $output_directory" echo "grpc-swift-protobuf directory: $grpc_swift_protobuf_directory" # modify Package.swift -cp "${resources_directory}/Package.swift" "${scratch_directory}/" -cat >> "${scratch_directory}/Package.swift" <<- EOM +cp "${resources_directory}/Sources/Package.swift" "${scratch_directory}/" +cat >> "${package_manifest}" <<- EOM package.dependencies.append( .package(path: "$grpc_swift_protobuf_directory") ) EOM -# test_01_top_level_config_file -test_01_output_directory="${output_directory}/test_01_top_level_config_file" -mkdir -p "${test_01_output_directory}/Sources/Protos" -cp "${scratch_directory}/Package.swift" "${test_01_output_directory}/" -cp "${resources_directory}/HelloWorldAdopter.swift" "${test_01_output_directory}/Sources/adopter.swift" -cp "${resources_directory}/HelloWorld/HelloWorld.proto" "${test_01_output_directory}/Sources/Protos" -cp "${resources_directory}/internal-grpc-swift-proto-generator-config.json" "${test_01_output_directory}/Sources/grpc-swift-proto-generator-config.json" - -# test_02_peer_config_file -test_02_output_directory="${output_directory}/test_02_peer_config_file" -mkdir -p "${test_02_output_directory}/Sources/Protos" -cp "${scratch_directory}/Package.swift" "${test_02_output_directory}/" -cp "${resources_directory}/HelloWorldAdopter.swift" "${test_02_output_directory}/Sources/adopter.swift" -cp "${resources_directory}/HelloWorld/HelloWorld.proto" "${test_02_output_directory}/Sources/Protos/" -cp "${resources_directory}/internal-grpc-swift-proto-generator-config.json" "${test_02_output_directory}/Sources/Protos/grpc-swift-proto-generator-config.json" - -# test_03_separate_service_message_protos -test_03_output_directory="${output_directory}/test_03_separate_service_message_protos" -mkdir -p "${test_03_output_directory}/Sources/Protos" -cp "${scratch_directory}/Package.swift" "${test_03_output_directory}/" -cp "${resources_directory}/HelloWorldAdopter.swift" "${test_03_output_directory}/Sources/adopter.swift" -cp "${resources_directory}/internal-grpc-swift-proto-generator-config.json" "${test_03_output_directory}/Sources/Protos/grpc-swift-proto-generator-config.json" -cp "${resources_directory}/HelloWorld/Service.proto" "${test_03_output_directory}/Sources/Protos/" -cp "${resources_directory}/HelloWorld/Messages.proto" "${test_03_output_directory}/Sources/Protos/" - -# test_04_cross_directory_imports -test_04_output_directory="${output_directory}/test_04_cross_directory_imports" -mkdir -p "${test_04_output_directory}/Sources/Protos/directory_1" -mkdir -p "${test_04_output_directory}/Sources/Protos/directory_2" -cp "${scratch_directory}/Package.swift" "${test_04_output_directory}/" -cp "${resources_directory}/HelloWorldAdopter.swift" "${test_04_output_directory}/Sources/adopter.swift" -cp "${resources_directory}/internal-grpc-swift-proto-generator-config.json" "${test_04_output_directory}/Sources/Protos/directory_1/grpc-swift-proto-generator-config.json" -cp "${resources_directory}/import-directory-1-grpc-swift-proto-generator-config.json" "${test_04_output_directory}/Sources/Protos/directory_2/grpc-swift-proto-generator-config.json" -cp "${resources_directory}/HelloWorld/Service.proto" "${test_04_output_directory}/Sources/Protos/directory_2/" -cp "${resources_directory}/HelloWorld/Messages.proto" "${test_04_output_directory}/Sources/Protos/directory_1/" - -# test_05_two_definitions -test_05_output_directory="${output_directory}/test_05_two_definitions" -mkdir -p "${test_05_output_directory}/Sources/Protos/HelloWorld" -mkdir -p "${test_05_output_directory}/Sources/Protos/Foo" -cp "${scratch_directory}/Package.swift" "${test_05_output_directory}/" -cp "${resources_directory}/FooHelloWorldAdopter.swift" "${test_05_output_directory}/Sources/adopter.swift" -cp "${resources_directory}/HelloWorld/HelloWorld.proto" "${test_05_output_directory}/Sources/Protos/HelloWorld/" -cp "${resources_directory}/internal-grpc-swift-proto-generator-config.json" "${test_05_output_directory}/Sources/Protos/grpc-swift-proto-generator-config.json" -cp "${resources_directory}/Foo/foo-messages.proto" "${test_05_output_directory}/Sources/Protos/Foo/" -cp "${resources_directory}/Foo/foo-service.proto" "${test_05_output_directory}/Sources/Protos/Foo/" - -# test_06_nested_definitions -test_06_output_directory="${output_directory}/test_06_nested_definitions" -mkdir -p "${test_06_output_directory}/Sources/Protos/HelloWorld/FooDefinitions/Foo" -cp "${scratch_directory}/Package.swift" "${test_06_output_directory}/" -cp "${resources_directory}/FooHelloWorldAdopter.swift" "${test_06_output_directory}/Sources/adopter.swift" -cp "${resources_directory}/HelloWorld/HelloWorld.proto" "${test_06_output_directory}/Sources/Protos/HelloWorld/" -cp "${resources_directory}/internal-grpc-swift-proto-generator-config.json" "${test_06_output_directory}/Sources/Protos/HelloWorld/grpc-swift-proto-generator-config.json" -cp "${resources_directory}/public-grpc-swift-proto-generator-config.json" "${test_06_output_directory}/Sources/Protos/HelloWorld/FooDefinitions/grpc-swift-proto-generator-config.json" -cp "${resources_directory}/Foo/foo-messages.proto" "${test_06_output_directory}/Sources/Protos/HelloWorld/FooDefinitions/Foo/" -cp "${resources_directory}/Foo/foo-service.proto" "${test_06_output_directory}/Sources/Protos/HelloWorld/FooDefinitions/Foo/" +function test_dir_name { + # $FUNCNAME is a stack of function names. The 0th element is the name of this + # function, so the 1st element is the calling function. + echo "${output_directory}/${FUNCNAME[1]}" +} + +function test_01_top_level_config_file { + # . + # ├── Package.swift + # └── Sources + # ├── HelloWorldAdopter.swift + # ├── Protos + # │ └── HelloWorld.proto + # └── grpc-swift-proto-generator-config.json + + local test_dir=$(test_dir_name) + mkdir -p "${test_dir}/Sources/Protos" + cp "${package_manifest}" "${test_dir}/" + cp "${sources}/HelloWorldAdopter.swift" "${test_dir}/Sources/" + cp "${protos}/HelloWorld/HelloWorld.proto" "${test_dir}/Sources/Protos" + cp "${config}/internal-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/grpc-swift-proto-generator-config.json" +} + +function test_02_peer_config_file { + # . + # ├── Package.swift + # └── Sources + # ├── HelloWorldAdopter.swift + # └── Protos + # ├── HelloWorld.proto + # └── grpc-swift-proto-generator-config.json + + local test_dir=$(test_dir_name) + mkdir -p "${test_dir}/Sources/Protos" + cp "${package_manifest}" "${test_dir}/" + cp "${sources}/HelloWorldAdopter.swift" "${test_dir}/Sources/" + cp "${protos}/HelloWorld/HelloWorld.proto" "${test_dir}/Sources/Protos/" + cp "${config}/internal-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/grpc-swift-proto-generator-config.json" +} + +function test_03_separate_service_message_protos { + # . + # ├── Package.swift + # └── Sources + # ├── HelloWorldAdopter.swift + # └── Protos + # ├── Messages.proto + # ├── Service.proto + # └── grpc-swift-proto-generator-config.json + + local test_dir=$(test_dir_name) + mkdir -p "${test_dir}/Sources/Protos" + cp "${package_manifest}" "${test_dir}/" + cp "${sources}/HelloWorldAdopter.swift" "${test_dir}/Sources/" + cp "${config}/internal-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/grpc-swift-proto-generator-config.json" + cp "${protos}/HelloWorld/Service.proto" "${test_dir}/Sources/Protos/" + cp "${protos}/HelloWorld/Messages.proto" "${test_dir}/Sources/Protos/" +} + +function test_04_cross_directory_imports { + # . + # ├── Package.swift + # └── Sources + # ├── HelloWorldAdopter.swift + # └── Protos + # ├── directory_1 + # │ ├── Messages.proto + # │ └── grpc-swift-proto-generator-config.json + # └── directory_2 + # ├── Service.proto + # └── grpc-swift-proto-generator-config.json + + local test_dir=$(test_dir_name) + mkdir -p "${test_dir}/Sources/Protos/directory_1" + mkdir -p "${test_dir}/Sources/Protos/directory_2" + + cp "${package_manifest}" "${test_dir}/" + cp "${sources}/HelloWorldAdopter.swift" "${test_dir}/Sources/" + cp "${config}/internal-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/directory_1/grpc-swift-proto-generator-config.json" + cp "${config}/import-directory-1-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/directory_2/grpc-swift-proto-generator-config.json" + cp "${protos}/HelloWorld/Service.proto" "${test_dir}/Sources/Protos/directory_2/" + cp "${protos}/HelloWorld/Messages.proto" "${test_dir}/Sources/Protos/directory_1/" +} + +function test_05_two_definitions { + # . + # ├── Package.swift + # └── Sources + # ├── FooHelloWorldAdopter.swift + # └── Protos + # ├── Foo + # │ ├── foo-messages.proto + # │ └── foo-service.proto + # ├── HelloWorld + # │ └── HelloWorld.proto + # └── grpc-swift-proto-generator-config.json + + local test_dir=$(test_dir_name) + mkdir -p "${test_dir}/Sources/Protos/HelloWorld" + mkdir -p "${test_dir}/Sources/Protos/Foo" + + cp "${package_manifest}" "${test_dir}/" + cp "${sources}/FooHelloWorldAdopter.swift" "${test_dir}/Sources/" + cp "${protos}/HelloWorld/HelloWorld.proto" "${test_dir}/Sources/Protos/HelloWorld/" + cp "${config}/internal-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/grpc-swift-proto-generator-config.json" + cp "${protos}/Foo/foo-messages.proto" "${test_dir}/Sources/Protos/Foo/" + cp "${protos}/Foo/foo-service.proto" "${test_dir}/Sources/Protos/Foo/" +} + +function test_06_nested_definitions { + # . + # ├── Package.swift + # └── Sources + # ├── FooHelloWorldAdopter.swift + # └── Protos + # └── HelloWorld + # ├── FooDefinitions + # │ ├── Foo + # │ │ ├── foo-messages.proto + # │ │ └── foo-service.proto + # │ └── grpc-swift-proto-generator-config.json + # ├── HelloWorld.proto + # └── grpc-swift-proto-generator-config.json + + local test_dir=$(test_dir_name) + mkdir -p "${test_dir}/Sources/Protos/HelloWorld/FooDefinitions/Foo" + cp "${package_manifest}" "${test_dir}/" + cp "${sources}/FooHelloWorldAdopter.swift" "${test_dir}/Sources/" + cp "${protos}/HelloWorld/HelloWorld.proto" "${test_dir}/Sources/Protos/HelloWorld/" + cp "${config}/internal-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/HelloWorld/grpc-swift-proto-generator-config.json" + cp "${config}/public-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/HelloWorld/FooDefinitions/grpc-swift-proto-generator-config.json" + cp "${protos}/Foo/foo-messages.proto" "${test_dir}/Sources/Protos/HelloWorld/FooDefinitions/Foo/" + cp "${protos}/Foo/foo-service.proto" "${test_dir}/Sources/Protos/HelloWorld/FooDefinitions/Foo/" +} + +function test_07_duplicated_proto_file_name { + # . + # ├── Package.swift + # └── Sources + # ├── NoOp.swift + # └── Protos + # ├── grpc-swift-proto-generator-config.json + # ├── noop + # │ └── noop.proto + # └── noop2 + # └── noop.proto + + local test_dir=$(test_dir_name) + mkdir -p "${test_dir}/Sources/Protos" + + cp "${package_manifest}" "${test_dir}/" + mkdir -p "${test_dir}/Sources/Protos" + cp -rp "${protos}/noop" "${test_dir}/Sources/Protos" + cp -rp "${protos}/noop2" "${test_dir}/Sources/Protos" + cp "${sources}/NoOp.swift" "${test_dir}/Sources" + cp "${config}/internal-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/grpc-swift-proto-generator-config.json" +} + +test_01_top_level_config_file +test_02_peer_config_file +test_03_separate_service_message_protos +test_04_cross_directory_imports +test_05_two_definitions +test_06_nested_definitions +# Expected to fail: +# test_07_duplicated_proto_file_name From 249739e5a5597047f95ac0d483431d95ba4c50aa Mon Sep 17 00:00:00 2001 From: George Barnett Date: Tue, 18 Feb 2025 18:45:48 +0000 Subject: [PATCH 2/3] Appease shellcheck --- dev/setup-plugin-tests.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/dev/setup-plugin-tests.sh b/dev/setup-plugin-tests.sh index baeb59c..7befd9a 100755 --- a/dev/setup-plugin-tests.sh +++ b/dev/setup-plugin-tests.sh @@ -56,7 +56,7 @@ function test_01_top_level_config_file { # │ └── HelloWorld.proto # └── grpc-swift-proto-generator-config.json - local test_dir=$(test_dir_name) + local -r test_dir=$(test_dir_name) mkdir -p "${test_dir}/Sources/Protos" cp "${package_manifest}" "${test_dir}/" cp "${sources}/HelloWorldAdopter.swift" "${test_dir}/Sources/" @@ -73,7 +73,7 @@ function test_02_peer_config_file { # ├── HelloWorld.proto # └── grpc-swift-proto-generator-config.json - local test_dir=$(test_dir_name) + local -r test_dir=$(test_dir_name) mkdir -p "${test_dir}/Sources/Protos" cp "${package_manifest}" "${test_dir}/" cp "${sources}/HelloWorldAdopter.swift" "${test_dir}/Sources/" @@ -91,7 +91,7 @@ function test_03_separate_service_message_protos { # ├── Service.proto # └── grpc-swift-proto-generator-config.json - local test_dir=$(test_dir_name) + local -r test_dir=$(test_dir_name) mkdir -p "${test_dir}/Sources/Protos" cp "${package_manifest}" "${test_dir}/" cp "${sources}/HelloWorldAdopter.swift" "${test_dir}/Sources/" @@ -113,7 +113,7 @@ function test_04_cross_directory_imports { # ├── Service.proto # └── grpc-swift-proto-generator-config.json - local test_dir=$(test_dir_name) + local -r test_dir=$(test_dir_name) mkdir -p "${test_dir}/Sources/Protos/directory_1" mkdir -p "${test_dir}/Sources/Protos/directory_2" @@ -138,7 +138,7 @@ function test_05_two_definitions { # │ └── HelloWorld.proto # └── grpc-swift-proto-generator-config.json - local test_dir=$(test_dir_name) + local -r test_dir=$(test_dir_name) mkdir -p "${test_dir}/Sources/Protos/HelloWorld" mkdir -p "${test_dir}/Sources/Protos/Foo" @@ -165,7 +165,7 @@ function test_06_nested_definitions { # ├── HelloWorld.proto # └── grpc-swift-proto-generator-config.json - local test_dir=$(test_dir_name) + local -r test_dir=$(test_dir_name) mkdir -p "${test_dir}/Sources/Protos/HelloWorld/FooDefinitions/Foo" cp "${package_manifest}" "${test_dir}/" cp "${sources}/FooHelloWorldAdopter.swift" "${test_dir}/Sources/" @@ -188,7 +188,7 @@ function test_07_duplicated_proto_file_name { # └── noop2 # └── noop.proto - local test_dir=$(test_dir_name) + local -r test_dir=$(test_dir_name) mkdir -p "${test_dir}/Sources/Protos" cp "${package_manifest}" "${test_dir}/" From 4e864e013301b5df92189f1a8e5a3284330db69a Mon Sep 17 00:00:00 2001 From: George Barnett Date: Tue, 18 Feb 2025 09:33:57 +0000 Subject: [PATCH 3/3] Use path-to-underscore when generating files with the plugin Motivation: The build system can't compile the code generated by the plugin when different proto files with the same name are used. This is allowed and expected if the files are in different proto packages. Modifications: - Use the "path to underscore" naming scheme instead of the "full path" naming scheme. This changes path components to underscores, so "foo/bar/baz.proto" would have "foo_bar_baz.grpc.swift" generated for it. - Uncomment test. Result: Test passes. --- .../BuildPluginConfig.swift | 6 ++- Plugins/GRPCProtobufGenerator/Plugin.swift | 39 ++++++++++--------- dev/setup-plugin-tests.sh | 3 +- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/Plugins/GRPCProtobufGenerator/BuildPluginConfig.swift b/Plugins/GRPCProtobufGenerator/BuildPluginConfig.swift index d5bf4c5..4a0ce62 100644 --- a/Plugins/GRPCProtobufGenerator/BuildPluginConfig.swift +++ b/Plugins/GRPCProtobufGenerator/BuildPluginConfig.swift @@ -196,8 +196,10 @@ extension GenerationConfig { self.server = buildPluginConfig.generate.servers self.client = buildPluginConfig.generate.clients self.message = buildPluginConfig.generate.messages - // hard-code full-path to avoid collisions since this goes into a temporary directory anyway - self.fileNaming = .fullPath + // Use path to underscores as it ensures output files are unique (files generated from + // "foo/bar.proto" won't collide with those generated from "bar/bar.proto" as they'll be + // uniquely named "foo_bar.(grpc|pb).swift" and "bar_bar.(grpc|pb).swift". + self.fileNaming = .pathToUnderscores self.visibility = buildPluginConfig.generatedSource.accessLevel self.accessLevelOnImports = buildPluginConfig.generatedSource.accessLevelOnImports // Generate absolute paths for the imports relative to the config file in which they are specified diff --git a/Plugins/GRPCProtobufGenerator/Plugin.swift b/Plugins/GRPCProtobufGenerator/Plugin.swift index 3c872b3..f882ebd 100644 --- a/Plugins/GRPCProtobufGenerator/Plugin.swift +++ b/Plugins/GRPCProtobufGenerator/Plugin.swift @@ -189,7 +189,7 @@ func protocGenGRPCSwiftCommand( let outputPathURL = URL(fileURLWithPath: config.outputPath) let outputFilePath = deriveOutputFilePath( - for: inputFile, + protoFile: inputFile, baseDirectoryPath: baseDirectoryPath, outputDirectory: outputPathURL, outputExtension: "grpc.swift" @@ -239,7 +239,7 @@ func protocGenSwiftCommand( let outputPathURL = URL(fileURLWithPath: config.outputPath) let outputFilePath = deriveOutputFilePath( - for: inputFile, + protoFile: inputFile, baseDirectoryPath: baseDirectoryPath, outputDirectory: outputPathURL, outputExtension: "pb.swift" @@ -267,28 +267,32 @@ func protocGenSwiftCommand( ) } -/// Derive the expected output file path to match the behavior of the `protoc-gen-swift` and `protoc-gen-grpc-swift` `protoc` plugins -/// when using the `FullPath` naming scheme. +/// Derive the expected output file path to match the behavior of the `protoc-gen-swift` +/// and `protoc-gen-grpc-swift` `protoc` plugins using the `PathToUnderscores` naming scheme. +/// +/// This means the generated file for an input proto file called "foo/bar/baz.proto" will +/// have the name "foo\_bar\_baz.proto". +/// /// - Parameters: -/// - inputFile: The input `.proto` file. -/// - baseDirectoryPath: The root path to the source `.proto` files used as the reference for relative path naming schemes. +/// - protoFile: The path of the input `.proto` file. +/// - baseDirectoryPath: The root path to the source `.proto` files used as the reference for +/// relative path naming schemes. /// - outputDirectory: The directory in which generated source files are created. /// - outputExtension: The file extension to be appended to generated files in-place of `.proto`. /// - Returns: The expected output file path. func deriveOutputFilePath( - for inputFile: URL, + protoFile: URL, baseDirectoryPath: URL, outputDirectory: URL, outputExtension: String ) -> URL { - // The name of the output file is based on the name of the input file. - // We validated in the beginning that every file has the suffix of .proto - // This means we can just drop the last 5 elements and append the new suffix - let lastPathComponentRoot = inputFile.lastPathComponent.dropLast(5) - let lastPathComponent = String(lastPathComponentRoot + outputExtension) + // Replace the extension (".proto") with the new extension (".grpc.swift" + // or ".pb.swift"). + precondition(protoFile.pathExtension == "proto") + let fileName = String(protoFile.lastPathComponent.dropLast(5) + outputExtension) // find the inputFile path relative to the proto directory - var relativePathComponents = inputFile.deletingLastPathComponent().pathComponents + var relativePathComponents = protoFile.deletingLastPathComponent().pathComponents for protoDirectoryPathComponent in baseDirectoryPath.pathComponents { if relativePathComponents.first == protoDirectoryPathComponent { relativePathComponents.removeFirst() @@ -297,10 +301,7 @@ func deriveOutputFilePath( } } - let outputFileComponents = relativePathComponents + [lastPathComponent] - var outputFilePath = outputDirectory - for outputFileComponent in outputFileComponents { - outputFilePath.append(component: outputFileComponent) - } - return outputFilePath + relativePathComponents.append(fileName) + let path = relativePathComponents.joined(separator: "_") + return outputDirectory.appending(path: path) } diff --git a/dev/setup-plugin-tests.sh b/dev/setup-plugin-tests.sh index 7befd9a..6d9eaae 100755 --- a/dev/setup-plugin-tests.sh +++ b/dev/setup-plugin-tests.sh @@ -205,5 +205,4 @@ test_03_separate_service_message_protos test_04_cross_directory_imports test_05_two_definitions test_06_nested_definitions -# Expected to fail: -# test_07_duplicated_proto_file_name +test_07_duplicated_proto_file_name