diff --git a/src/compiler/objective_c_plugin.cc b/src/compiler/objective_c_plugin.cc index 0aeab19b1ad..5a9c7e7d5a4 100644 --- a/src/compiler/objective_c_plugin.cc +++ b/src/compiler/objective_c_plugin.cc @@ -39,7 +39,8 @@ namespace { inline ::std::string ImportProtoHeaders( const grpc::protobuf::FileDescriptor* dep, const char* indent, - const ::std::string& framework) { + const ::std::string& framework, + const ::std::string& pb_runtime_import_prefix) { ::std::string header = grpc_objective_c_generator::MessageHeaderName(dep); if (!IsProtobufLibraryBundledProtoFile(dep)) { @@ -56,12 +57,16 @@ inline ::std::string ImportProtoHeaders( // create the import code snippet ::std::string framework_header = ::std::string(ProtobufLibraryFrameworkName) + "/" + file_name; + ::std::string local_header = file_name; + if (!pb_runtime_import_prefix.empty()) { + local_header = pb_runtime_import_prefix + "/" + file_name; + } static const ::std::string kFrameworkImportsCondition = "GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS"; return PreprocIfElse(kFrameworkImportsCondition, indent + SystemImport(framework_header), - indent + LocalImport(file_name)); + indent + LocalImport(local_header)); } } // namespace @@ -86,6 +91,7 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { } ::std::string framework; + ::std::string pb_runtime_import_prefix; std::vector<::std::string> params_list = grpc_generator::tokenize(parameter, ","); for (auto param_str = params_list.begin(); param_str != params_list.end(); @@ -104,6 +110,13 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { return false; } framework = param[1]; + } else if (param[0] == "runtime_import_prefix") { + if (param.size() != 2) { + *error = grpc::string("Format: runtime_import_prefix=dir/"); + return false; + } + pb_runtime_import_prefix = param[1]; + grpc_generator::StripSuffix(&pb_runtime_import_prefix, "/"); } } @@ -173,8 +186,8 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { ::std::string class_imports; for (int i = 0; i < file->dependency_count(); i++) { - class_imports += - ImportProtoHeaders(file->dependency(i), " ", framework); + class_imports += ImportProtoHeaders( + file->dependency(i), " ", framework, pb_runtime_import_prefix); } ::std::string ng_protocols; @@ -228,7 +241,8 @@ class ObjectiveCGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { ::std::string class_imports; for (int i = 0; i < file->dependency_count(); i++) { - class_imports += ImportProtoHeaders(file->dependency(i), "", framework); + class_imports += ImportProtoHeaders(file->dependency(i), "", framework, + pb_runtime_import_prefix); } ::std::string definitions; diff --git a/src/objective-c/tests/run_plugin_option_tests.sh b/src/objective-c/tests/run_plugin_option_tests.sh new file mode 100755 index 00000000000..2263f571d75 --- /dev/null +++ b/src/objective-c/tests/run_plugin_option_tests.sh @@ -0,0 +1,68 @@ +#!/bin/bash +# Copyright 2015 gRPC authors. +# +# 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. + +# Don't run this script standalone. Instead, run from the repository root: +# ./tools/run_tests/run_tests.py -l objc + +set -ev + +cd $(dirname $0) + +# Run the tests server. + +ROOT_DIR=../../.. +BAZEL=$ROOT_DIR/tools/bazel +PROTOC=$ROOT_DIR/bazel-bin/external/com_google_protobuf/protoc +PLUGIN=$ROOT_DIR/bazel-bin/src/compiler/grpc_objective_c_plugin +RUNTIME_IMPORT_PREFIX=prefix/dir/ + +[ -f $PROTOC ] && [ -f $PLUGIN ] || { + BAZEL build @com_google_protobuf//:protoc //src/compiler:grpc_objective_c_plugin +} + +rm -rf RemoteTestClient/*pb* + +$PROTOC \ + --plugin=protoc-gen-grpc=$PLUGIN \ + --objc_out=RemoteTestClient \ + --grpc_out=runtime_import_prefix=$RUNTIME_IMPORT_PREFIX:RemoteTestClient \ + -I $ROOT_DIR \ + -I ../../../third_party/protobuf/src \ + $ROOT_DIR/src/objective-c/examples/RemoteTestClient/*.proto + +# Verify the output proto filename +[ -e ./RemoteTestClient/src/objective-c/examples/RemoteTestClient/Test.pbrpc.m ] || { + echo >&2 "protoc outputs wrong filename." + exit 1 +} + +# Verify paths of protobuf WKTs in generated code contain runtime import prefix. +[ "`cat RemoteTestClient/src/objective-c/examples/RemoteTestClient/Test.pbrpc.m | + egrep '#import "'"${RUNTIME_IMPORT_PREFIX}"'GPBEmpty\.pbobjc\.h'`" ] || { + echo >&2 "protoc generated import with wrong filename." + exit 1 +} + +# Verify paths of non WKTs protos in generated code don't contain runtime import prefix. +[ "`cat RemoteTestClient/src/objective-c/examples/RemoteTestClient/Test.pbrpc.m | + egrep '.*\Messages.pbobjc.h"$' | + egrep '#import "'"${RUNTIME_IMPORT_PREFIX}"`" ] && { + echo >&2 "protoc generated import with wrong filename." + exit 1 +} + +# Run one extra command to clear $? before exiting the script to prevent +# failing even when tests pass. +echo "Plugin option tests passed." diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py index b1c56762bd1..38286345aac 100755 --- a/tools/run_tests/run_tests.py +++ b/tools/run_tests/run_tests.py @@ -1149,6 +1149,13 @@ class ObjCLanguage(object): shortname='ios-test-plugintest', cpu_cost=1e6, environ=_FORCE_ENVIRON_FOR_WRAPPERS)) + out.append( + self.config.job_spec( + ['src/objective-c/tests/run_plugin_option_tests.sh'], + timeout_seconds=60 * 60, + shortname='ios-test-plugin-option-test', + cpu_cost=1e6, + environ=_FORCE_ENVIRON_FOR_WRAPPERS)) out.append( self.config.job_spec( ['test/core/iomgr/ios/CFStreamTests/build_and_run_tests.sh'],