diff --git a/BUILD b/BUILD index a7c757c7289..78f5b16f6f6 100644 --- a/BUILD +++ b/BUILD @@ -182,6 +182,8 @@ grpc_cc_library( ], hdrs = [ "src/compiler/config.h", + "src/compiler/schema_interface.h", + "src/compiler/protobuf_plugin.h", "src/compiler/cpp_generator.h", "src/compiler/cpp_generator_helpers.h", "src/compiler/csharp_generator.h", @@ -194,6 +196,8 @@ grpc_cc_library( "src/compiler/php_generator.h", "src/compiler/php_generator_helpers.h", "src/compiler/python_generator.h", + "src/compiler/python_generator_helpers.h", + "src/compiler/python_private_generator.h", "src/compiler/ruby_generator.h", "src/compiler/ruby_generator_helpers-inl.h", "src/compiler/ruby_generator_map-inl.h", diff --git a/build.yaml b/build.yaml index 2414180ffe1..383090fa6f1 100644 --- a/build.yaml +++ b/build.yaml @@ -1333,11 +1333,15 @@ libs: - src/compiler/objective_c_generator_helpers.h - src/compiler/php_generator.h - src/compiler/php_generator_helpers.h + - src/compiler/protobuf_plugin.h - src/compiler/python_generator.h + - src/compiler/python_generator_helpers.h + - src/compiler/python_private_generator.h - src/compiler/ruby_generator.h - src/compiler/ruby_generator_helpers-inl.h - src/compiler/ruby_generator_map-inl.h - src/compiler/ruby_generator_string-inl.h + - src/compiler/schema_interface.h src: - src/compiler/cpp_generator.cc - src/compiler/csharp_generator.cc diff --git a/src/compiler/cpp_generator.cc b/src/compiler/cpp_generator.cc index 2908b639f39..c01e830cd68 100644 --- a/src/compiler/cpp_generator.cc +++ b/src/compiler/cpp_generator.cc @@ -40,6 +40,9 @@ namespace grpc_cpp_generator { namespace { +grpc::string message_header_ext() { return ".pb.h"; } +grpc::string service_header_ext() { return ".grpc.pb.h"; } + template grpc::string as_string(T x) { std::ostringstream out; @@ -47,6 +50,14 @@ grpc::string as_string(T x) { return out.str(); } +inline bool ClientOnlyStreaming(const grpc_generator::Method *method) { + return method->ClientStreaming() && !method->ServerStreaming(); +} + +inline bool ServerOnlyStreaming(const grpc_generator::Method *method) { + return !method->ClientStreaming() && method->ServerStreaming(); +} + grpc::string FilenameIdentifier(const grpc::string &filename) { grpc::string result; for (unsigned i = 0; i < filename.size(); i++) { @@ -69,7 +80,8 @@ T *array_end(T (&array)[N]) { return array + N; } -void PrintIncludes(Printer *printer, const std::vector &headers, +void PrintIncludes(grpc_generator::Printer *printer, + const std::vector &headers, const Parameters ¶ms) { std::map vars; @@ -90,7 +102,8 @@ void PrintIncludes(Printer *printer, const std::vector &headers, } } -grpc::string GetHeaderPrologue(File *file, const Parameters & /*params*/) { +grpc::string GetHeaderPrologue(grpc_generator::File *file, + const Parameters & /*params*/) { grpc::string output; { // Scope the output stream so it closes and finalizes output to the string. @@ -100,13 +113,13 @@ grpc::string GetHeaderPrologue(File *file, const Parameters & /*params*/) { vars["filename"] = file->filename(); vars["filename_identifier"] = FilenameIdentifier(file->filename()); vars["filename_base"] = file->filename_without_ext(); - vars["message_header_ext"] = file->message_header_ext(); + vars["message_header_ext"] = message_header_ext(); printer->Print(vars, "// Generated by the gRPC C++ plugin.\n"); printer->Print(vars, "// If you make any local change, they will be lost.\n"); printer->Print(vars, "// source: $filename$\n"); - grpc::string leading_comments = file->GetLeadingComments(); + grpc::string leading_comments = file->GetLeadingComments("//"); if (!leading_comments.empty()) { printer->Print(vars, "// Original file comments:\n"); printer->Print(leading_comments.c_str()); @@ -120,7 +133,8 @@ grpc::string GetHeaderPrologue(File *file, const Parameters & /*params*/) { return output; } -grpc::string GetHeaderIncludes(File *file, const Parameters ¶ms) { +grpc::string GetHeaderIncludes(grpc_generator::File *file, + const Parameters ¶ms) { grpc::string output; { // Scope the output stream so it closes and finalizes output to the string. @@ -162,7 +176,7 @@ grpc::string GetHeaderIncludes(File *file, const Parameters ¶ms) { } void PrintHeaderClientMethodInterfaces( - Printer *printer, const Method *method, + grpc_generator::Printer *printer, const grpc_generator::Method *method, std::map *vars, bool is_public) { (*vars)["Method"] = method->name(); (*vars)["Request"] = method->input_type_name(); @@ -187,7 +201,7 @@ void PrintHeaderClientMethodInterfaces( "Async$Method$Raw(context, request, cq));\n"); printer->Outdent(); printer->Print("}\n"); - } else if (method->ClientOnlyStreaming()) { + } else if (ClientOnlyStreaming(method)) { printer->Print( *vars, "std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>" @@ -213,7 +227,7 @@ void PrintHeaderClientMethodInterfaces( "Async$Method$Raw(context, response, cq, tag));\n"); printer->Outdent(); printer->Print("}\n"); - } else if (method->ServerOnlyStreaming()) { + } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, "std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>" @@ -275,7 +289,7 @@ void PrintHeaderClientMethodInterfaces( "Async$Method$Raw(::grpc::ClientContext* context, " "const $Request$& request, " "::grpc::CompletionQueue* cq) = 0;\n"); - } else if (method->ClientOnlyStreaming()) { + } else if (ClientOnlyStreaming(method)) { printer->Print( *vars, "virtual ::grpc::ClientWriterInterface< $Request$>*" @@ -286,7 +300,7 @@ void PrintHeaderClientMethodInterfaces( " Async$Method$Raw(::grpc::ClientContext* context, " "$Response$* response, " "::grpc::CompletionQueue* cq, void* tag) = 0;\n"); - } else if (method->ServerOnlyStreaming()) { + } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, "virtual ::grpc::ClientReaderInterface< $Response$>* $Method$Raw(" @@ -311,7 +325,8 @@ void PrintHeaderClientMethodInterfaces( } } -void PrintHeaderClientMethod(Printer *printer, const Method *method, +void PrintHeaderClientMethod(grpc_generator::Printer *printer, + const grpc_generator::Method *method, std::map *vars, bool is_public) { (*vars)["Method"] = method->name(); @@ -336,7 +351,7 @@ void PrintHeaderClientMethod(Printer *printer, const Method *method, "Async$Method$Raw(context, request, cq));\n"); printer->Outdent(); printer->Print("}\n"); - } else if (method->ClientOnlyStreaming()) { + } else if (ClientOnlyStreaming(method)) { printer->Print( *vars, "std::unique_ptr< ::grpc::ClientWriter< $Request$>>" @@ -360,7 +375,7 @@ void PrintHeaderClientMethod(Printer *printer, const Method *method, "Async$Method$Raw(context, response, cq, tag));\n"); printer->Outdent(); printer->Print("}\n"); - } else if (method->ServerOnlyStreaming()) { + } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, "std::unique_ptr< ::grpc::ClientReader< $Response$>>" @@ -418,7 +433,7 @@ void PrintHeaderClientMethod(Printer *printer, const Method *method, "Async$Method$Raw(::grpc::ClientContext* context, " "const $Request$& request, " "::grpc::CompletionQueue* cq) override;\n"); - } else if (method->ClientOnlyStreaming()) { + } else if (ClientOnlyStreaming(method)) { printer->Print(*vars, "::grpc::ClientWriter< $Request$>* $Method$Raw(" "::grpc::ClientContext* context, $Response$* response) " @@ -427,7 +442,7 @@ void PrintHeaderClientMethod(Printer *printer, const Method *method, "::grpc::ClientAsyncWriter< $Request$>* Async$Method$Raw(" "::grpc::ClientContext* context, $Response$* response, " "::grpc::CompletionQueue* cq, void* tag) override;\n"); - } else if (method->ServerOnlyStreaming()) { + } else if (ServerOnlyStreaming(method)) { printer->Print(*vars, "::grpc::ClientReader< $Response$>* $Method$Raw(" "::grpc::ClientContext* context, const $Request$& request)" @@ -449,30 +464,32 @@ void PrintHeaderClientMethod(Printer *printer, const Method *method, } } -void PrintHeaderClientMethodData(Printer *printer, const Method *method, +void PrintHeaderClientMethodData(grpc_generator::Printer *printer, + const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); printer->Print(*vars, "const ::grpc::RpcMethod rpcmethod_$Method$_;\n"); } -void PrintHeaderServerMethodSync(Printer *printer, const Method *method, +void PrintHeaderServerMethodSync(grpc_generator::Printer *printer, + const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); (*vars)["Request"] = method->input_type_name(); (*vars)["Response"] = method->output_type_name(); - printer->Print(method->GetLeadingComments().c_str()); + printer->Print(method->GetLeadingComments("//").c_str()); if (method->NoStreaming()) { printer->Print(*vars, "virtual ::grpc::Status $Method$(" "::grpc::ServerContext* context, const $Request$* request, " "$Response$* response);\n"); - } else if (method->ClientOnlyStreaming()) { + } else if (ClientOnlyStreaming(method)) { printer->Print(*vars, "virtual ::grpc::Status $Method$(" "::grpc::ServerContext* context, " "::grpc::ServerReader< $Request$>* reader, " "$Response$* response);\n"); - } else if (method->ServerOnlyStreaming()) { + } else if (ServerOnlyStreaming(method)) { printer->Print(*vars, "virtual ::grpc::Status $Method$(" "::grpc::ServerContext* context, const $Request$* request, " @@ -485,10 +502,11 @@ void PrintHeaderServerMethodSync(Printer *printer, const Method *method, "::grpc::ServerReaderWriter< $Response$, $Request$>* stream);" "\n"); } - printer->Print(method->GetTrailingComments().c_str()); + printer->Print(method->GetTrailingComments("//").c_str()); } -void PrintHeaderServerMethodAsync(Printer *printer, const Method *method, +void PrintHeaderServerMethodAsync(grpc_generator::Printer *printer, + const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); (*vars)["Request"] = method->input_type_name(); @@ -530,7 +548,7 @@ void PrintHeaderServerMethodAsync(Printer *printer, const Method *method, " ::grpc::Service::RequestAsyncUnary($Idx$, context, " "request, response, new_call_cq, notification_cq, tag);\n"); printer->Print("}\n"); - } else if (method->ClientOnlyStreaming()) { + } else if (ClientOnlyStreaming(method)) { printer->Print( *vars, "// disable synchronous version of this method\n" @@ -552,7 +570,7 @@ void PrintHeaderServerMethodAsync(Printer *printer, const Method *method, " ::grpc::Service::RequestAsyncClientStreaming($Idx$, " "context, reader, new_call_cq, notification_cq, tag);\n"); printer->Print("}\n"); - } else if (method->ServerOnlyStreaming()) { + } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, "// disable synchronous version of this method\n" @@ -603,7 +621,7 @@ void PrintHeaderServerMethodAsync(Printer *printer, const Method *method, } void PrintHeaderServerMethodStreamedUnary( - Printer *printer, const Method *method, + grpc_generator::Printer *printer, const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); (*vars)["Request"] = method->input_type_name(); @@ -654,12 +672,12 @@ void PrintHeaderServerMethodStreamedUnary( } void PrintHeaderServerMethodSplitStreaming( - Printer *printer, const Method *method, + grpc_generator::Printer *printer, const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); (*vars)["Request"] = method->input_type_name(); (*vars)["Response"] = method->output_type_name(); - if (method->ServerOnlyStreaming()) { + if (ServerOnlyStreaming(method)) { printer->Print(*vars, "template \n"); printer->Print(*vars, "class WithSplitStreamingMethod_$Method$ : " @@ -706,7 +724,7 @@ void PrintHeaderServerMethodSplitStreaming( } void PrintHeaderServerMethodGeneric( - Printer *printer, const Method *method, + grpc_generator::Printer *printer, const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); (*vars)["Request"] = method->input_type_name(); @@ -737,7 +755,7 @@ void PrintHeaderServerMethodGeneric( " abort();\n" " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" "}\n"); - } else if (method->ClientOnlyStreaming()) { + } else if (ClientOnlyStreaming(method)) { printer->Print( *vars, "// disable synchronous version of this method\n" @@ -748,7 +766,7 @@ void PrintHeaderServerMethodGeneric( " abort();\n" " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" "}\n"); - } else if (method->ServerOnlyStreaming()) { + } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, "// disable synchronous version of this method\n" @@ -775,11 +793,12 @@ void PrintHeaderServerMethodGeneric( printer->Print(*vars, "};\n"); } -void PrintHeaderService(Printer *printer, const Service *service, +void PrintHeaderService(grpc_generator::Printer *printer, + const grpc_generator::Service *service, std::map *vars) { (*vars)["Service"] = service->name(); - printer->Print(service->GetLeadingComments().c_str()); + printer->Print(service->GetLeadingComments("//").c_str()); printer->Print(*vars, "class $Service$ final {\n" " public:\n"); @@ -792,10 +811,10 @@ void PrintHeaderService(Printer *printer, const Service *service, printer->Indent(); printer->Print("virtual ~StubInterface() {}\n"); for (int i = 0; i < service->method_count(); ++i) { - printer->Print(service->method(i)->GetLeadingComments().c_str()); + printer->Print(service->method(i)->GetLeadingComments("//").c_str()); PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars, true); - printer->Print(service->method(i)->GetTrailingComments().c_str()); + printer->Print(service->method(i)->GetTrailingComments("//").c_str()); } printer->Outdent(); printer->Print("private:\n"); @@ -903,13 +922,15 @@ void PrintHeaderService(Printer *printer, const Service *service, printer->Print("typedef "); for (int i = 0; i < service->method_count(); ++i) { (*vars)["method_name"] = service->method(i).get()->name(); - if (service->method(i)->ServerOnlyStreaming()) { + auto method = service->method(i); + if (ServerOnlyStreaming(method.get())) { printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<"); } } printer->Print("Service"); for (int i = 0; i < service->method_count(); ++i) { - if (service->method(i)->ServerOnlyStreaming()) { + auto method = service->method(i); + if (ServerOnlyStreaming(method.get())) { printer->Print(" >"); } } @@ -919,7 +940,8 @@ void PrintHeaderService(Printer *printer, const Service *service, printer->Print("typedef "); for (int i = 0; i < service->method_count(); ++i) { (*vars)["method_name"] = service->method(i).get()->name(); - if (service->method(i)->ServerOnlyStreaming()) { + auto method = service->method(i); + if (ServerOnlyStreaming(method.get())) { printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<"); } if (service->method(i)->NoStreaming()) { @@ -928,8 +950,9 @@ void PrintHeaderService(Printer *printer, const Service *service, } printer->Print("Service"); for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); if (service->method(i)->NoStreaming() || - service->method(i)->ServerOnlyStreaming()) { + ServerOnlyStreaming(method.get())) { printer->Print(" >"); } } @@ -937,10 +960,11 @@ void PrintHeaderService(Printer *printer, const Service *service, printer->Outdent(); printer->Print("};\n"); - printer->Print(service->GetTrailingComments().c_str()); + printer->Print(service->GetTrailingComments("//").c_str()); } -grpc::string GetHeaderServices(File *file, const Parameters ¶ms) { +grpc::string GetHeaderServices(grpc_generator::File *file, + const Parameters ¶ms) { grpc::string output; { // Scope the output stream so it closes and finalizes output to the string. @@ -970,7 +994,8 @@ grpc::string GetHeaderServices(File *file, const Parameters ¶ms) { return output; } -grpc::string GetHeaderEpilogue(File *file, const Parameters & /*params*/) { +grpc::string GetHeaderEpilogue(grpc_generator::File *file, + const Parameters & /*params*/) { grpc::string output; { // Scope the output stream so it closes and finalizes output to the string. @@ -993,12 +1018,13 @@ grpc::string GetHeaderEpilogue(File *file, const Parameters & /*params*/) { printer->Print(vars, "\n"); printer->Print(vars, "#endif // GRPC_$filename_identifier$__INCLUDED\n"); - printer->Print(file->GetTrailingComments().c_str()); + printer->Print(file->GetTrailingComments("//").c_str()); } return output; } -grpc::string GetSourcePrologue(File *file, const Parameters & /*params*/) { +grpc::string GetSourcePrologue(grpc_generator::File *file, + const Parameters & /*params*/) { grpc::string output; { // Scope the output stream so it closes and finalizes output to the string. @@ -1007,8 +1033,8 @@ grpc::string GetSourcePrologue(File *file, const Parameters & /*params*/) { vars["filename"] = file->filename(); vars["filename_base"] = file->filename_without_ext(); - vars["message_header_ext"] = file->message_header_ext(); - vars["service_header_ext"] = file->service_header_ext(); + vars["message_header_ext"] = message_header_ext(); + vars["service_header_ext"] = service_header_ext(); printer->Print(vars, "// Generated by the gRPC C++ plugin.\n"); printer->Print(vars, @@ -1023,7 +1049,8 @@ grpc::string GetSourcePrologue(File *file, const Parameters & /*params*/) { return output; } -grpc::string GetSourceIncludes(File *file, const Parameters ¶ms) { +grpc::string GetSourceIncludes(grpc_generator::File *file, + const Parameters ¶ms) { grpc::string output; { // Scope the output stream so it closes and finalizes output to the string. @@ -1056,7 +1083,8 @@ grpc::string GetSourceIncludes(File *file, const Parameters ¶ms) { return output; } -void PrintSourceClientMethod(Printer *printer, const Method *method, +void PrintSourceClientMethod(grpc_generator::Printer *printer, + const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); (*vars)["Request"] = method->input_type_name(); @@ -1084,7 +1112,7 @@ void PrintSourceClientMethod(Printer *printer, const Method *method, "rpcmethod_$Method$_, " "context, request);\n" "}\n\n"); - } else if (method->ClientOnlyStreaming()) { + } else if (ClientOnlyStreaming(method)) { printer->Print(*vars, "::grpc::ClientWriter< $Request$>* " "$ns$$Service$::Stub::$Method$Raw(" @@ -1106,7 +1134,7 @@ void PrintSourceClientMethod(Printer *printer, const Method *method, "rpcmethod_$Method$_, " "context, response, tag);\n" "}\n\n"); - } else if (method->ServerOnlyStreaming()) { + } else if (ServerOnlyStreaming(method)) { printer->Print( *vars, "::grpc::ClientReader< $Response$>* " @@ -1156,7 +1184,8 @@ void PrintSourceClientMethod(Printer *printer, const Method *method, } } -void PrintSourceServerMethod(Printer *printer, const Method *method, +void PrintSourceServerMethod(grpc_generator::Printer *printer, + const grpc_generator::Method *method, std::map *vars) { (*vars)["Method"] = method->name(); (*vars)["Request"] = method->input_type_name(); @@ -1173,7 +1202,7 @@ void PrintSourceServerMethod(Printer *printer, const Method *method, " return ::grpc::Status(" "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"); printer->Print("}\n\n"); - } else if (method->ClientOnlyStreaming()) { + } else if (ClientOnlyStreaming(method)) { printer->Print(*vars, "::grpc::Status $ns$$Service$::Service::$Method$(" "::grpc::ServerContext* context, " @@ -1186,7 +1215,7 @@ void PrintSourceServerMethod(Printer *printer, const Method *method, " return ::grpc::Status(" "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"); printer->Print("}\n\n"); - } else if (method->ServerOnlyStreaming()) { + } else if (ServerOnlyStreaming(method)) { printer->Print(*vars, "::grpc::Status $ns$$Service$::Service::$Method$(" "::grpc::ServerContext* context, " @@ -1214,7 +1243,8 @@ void PrintSourceServerMethod(Printer *printer, const Method *method, } } -void PrintSourceService(Printer *printer, const Service *service, +void PrintSourceService(grpc_generator::Printer *printer, + const grpc_generator::Service *service, std::map *vars) { (*vars)["Service"] = service->name(); @@ -1250,9 +1280,9 @@ void PrintSourceService(Printer *printer, const Service *service, // NOTE: There is no reason to consider streamed-unary as a separate // category here since this part is setting up the client-side stub // and this appears as a NORMAL_RPC from the client-side. - } else if (method->ClientOnlyStreaming()) { + } else if (ClientOnlyStreaming(method.get())) { (*vars)["StreamingType"] = "CLIENT_STREAMING"; - } else if (method->ServerOnlyStreaming()) { + } else if (ServerOnlyStreaming(method.get())) { (*vars)["StreamingType"] = "SERVER_STREAMING"; } else { (*vars)["StreamingType"] = "BIDI_STREAMING"; @@ -1290,7 +1320,7 @@ void PrintSourceService(Printer *printer, const Service *service, "$Request$, " "$Response$>(\n" " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n"); - } else if (method->ClientOnlyStreaming()) { + } else if (ClientOnlyStreaming(method.get())) { printer->Print( *vars, "AddMethod(new ::grpc::RpcServiceMethod(\n" @@ -1299,7 +1329,7 @@ void PrintSourceService(Printer *printer, const Service *service, " new ::grpc::ClientStreamingHandler< " "$ns$$Service$::Service, $Request$, $Response$>(\n" " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n"); - } else if (method->ServerOnlyStreaming()) { + } else if (ServerOnlyStreaming(method.get())) { printer->Print( *vars, "AddMethod(new ::grpc::RpcServiceMethod(\n" @@ -1330,7 +1360,8 @@ void PrintSourceService(Printer *printer, const Service *service, } } -grpc::string GetSourceServices(File *file, const Parameters ¶ms) { +grpc::string GetSourceServices(grpc_generator::File *file, + const Parameters ¶ms) { grpc::string output; { // Scope the output stream so it closes and finalizes output to the string. @@ -1358,7 +1389,8 @@ grpc::string GetSourceServices(File *file, const Parameters ¶ms) { return output; } -grpc::string GetSourceEpilogue(File *file, const Parameters & /*params*/) { +grpc::string GetSourceEpilogue(grpc_generator::File *file, + const Parameters & /*params*/) { grpc::string temp; if (!file->package().empty()) { diff --git a/src/compiler/cpp_generator.h b/src/compiler/cpp_generator.h index d0343e9978b..69fd8a93e93 100644 --- a/src/compiler/cpp_generator.h +++ b/src/compiler/cpp_generator.h @@ -42,6 +42,7 @@ #include #include "src/compiler/config.h" +#include "src/compiler/schema_interface.h" #ifndef GRPC_CUSTOM_STRING #include @@ -66,91 +67,37 @@ struct Parameters { grpc::string grpc_search_path; }; -// A common interface for objects having comments in the source. -// Return formatted comments to be inserted in generated code. -struct CommentHolder { - virtual ~CommentHolder() {} - virtual grpc::string GetLeadingComments() const = 0; - virtual grpc::string GetTrailingComments() const = 0; -}; - -// An abstract interface representing a method. -struct Method : public CommentHolder { - virtual ~Method() {} - - virtual grpc::string name() const = 0; - - virtual grpc::string input_type_name() const = 0; - virtual grpc::string output_type_name() const = 0; - - virtual bool NoStreaming() const = 0; - virtual bool ClientOnlyStreaming() const = 0; - virtual bool ServerOnlyStreaming() const = 0; - virtual bool BidiStreaming() const = 0; -}; - -// An abstract interface representing a service. -struct Service : public CommentHolder { - virtual ~Service() {} - - virtual grpc::string name() const = 0; - - virtual int method_count() const = 0; - virtual std::unique_ptr method(int i) const = 0; -}; - -struct Printer { - virtual ~Printer() {} - - virtual void Print(const std::map &vars, - const char *template_string) = 0; - virtual void Print(const char *string) = 0; - virtual void Indent() = 0; - virtual void Outdent() = 0; -}; - -// An interface that allows the source generated to be output using various -// libraries/idls/serializers. -struct File : public CommentHolder { - virtual ~File() {} - - virtual grpc::string filename() const = 0; - virtual grpc::string filename_without_ext() const = 0; - virtual grpc::string message_header_ext() const = 0; - virtual grpc::string service_header_ext() const = 0; - virtual grpc::string package() const = 0; - virtual std::vector package_parts() const = 0; - virtual grpc::string additional_headers() const = 0; - - virtual int service_count() const = 0; - virtual std::unique_ptr service(int i) const = 0; - - virtual std::unique_ptr CreatePrinter(grpc::string *str) const = 0; -}; - // Return the prologue of the generated header file. -grpc::string GetHeaderPrologue(File *file, const Parameters ¶ms); +grpc::string GetHeaderPrologue(grpc_generator::File *file, + const Parameters ¶ms); // Return the includes needed for generated header file. -grpc::string GetHeaderIncludes(File *file, const Parameters ¶ms); +grpc::string GetHeaderIncludes(grpc_generator::File *file, + const Parameters ¶ms); // Return the includes needed for generated source file. -grpc::string GetSourceIncludes(File *file, const Parameters ¶ms); +grpc::string GetSourceIncludes(grpc_generator::File *file, + const Parameters ¶ms); // Return the epilogue of the generated header file. -grpc::string GetHeaderEpilogue(File *file, const Parameters ¶ms); +grpc::string GetHeaderEpilogue(grpc_generator::File *file, + const Parameters ¶ms); // Return the prologue of the generated source file. -grpc::string GetSourcePrologue(File *file, const Parameters ¶ms); +grpc::string GetSourcePrologue(grpc_generator::File *file, + const Parameters ¶ms); // Return the services for generated header file. -grpc::string GetHeaderServices(File *file, const Parameters ¶ms); +grpc::string GetHeaderServices(grpc_generator::File *file, + const Parameters ¶ms); // Return the services for generated source file. -grpc::string GetSourceServices(File *file, const Parameters ¶ms); +grpc::string GetSourceServices(grpc_generator::File *file, + const Parameters ¶ms); // Return the epilogue of the generated source file. -grpc::string GetSourceEpilogue(File *file, const Parameters ¶ms); +grpc::string GetSourceEpilogue(grpc_generator::File *file, + const Parameters ¶ms); } // namespace grpc_cpp_generator diff --git a/src/compiler/cpp_generator_helpers.h b/src/compiler/cpp_generator_helpers.h index 87e278f1b9f..83932a09bb8 100644 --- a/src/compiler/cpp_generator_helpers.h +++ b/src/compiler/cpp_generator_helpers.h @@ -35,6 +35,7 @@ #define GRPC_INTERNAL_COMPILER_CPP_GENERATOR_HELPERS_H #include + #include "src/compiler/config.h" #include "src/compiler/generator_helpers.h" diff --git a/src/compiler/cpp_plugin.cc b/src/compiler/cpp_plugin.cc index 38f8f738ed9..4ee05ee0370 100644 --- a/src/compiler/cpp_plugin.cc +++ b/src/compiler/cpp_plugin.cc @@ -40,139 +40,8 @@ #include "src/compiler/config.h" #include "src/compiler/cpp_generator.h" -#include "src/compiler/cpp_generator_helpers.h" #include "src/compiler/generator_helpers.h" - -using grpc_cpp_generator::GetCppComments; - -class ProtoBufMethod : public grpc_cpp_generator::Method { - public: - ProtoBufMethod(const grpc::protobuf::MethodDescriptor *method) - : method_(method) {} - - grpc::string name() const { return method_->name(); } - - grpc::string input_type_name() const { - return grpc_cpp_generator::ClassName(method_->input_type(), true); - } - grpc::string output_type_name() const { - return grpc_cpp_generator::ClassName(method_->output_type(), true); - } - - bool NoStreaming() const { - return !method_->client_streaming() && !method_->server_streaming(); - } - - bool ClientOnlyStreaming() const { - return method_->client_streaming() && !method_->server_streaming(); - } - - bool ServerOnlyStreaming() const { - return !method_->client_streaming() && method_->server_streaming(); - } - - bool BidiStreaming() const { - return method_->client_streaming() && method_->server_streaming(); - } - - grpc::string GetLeadingComments() const { - return GetCppComments(method_, true); - } - - grpc::string GetTrailingComments() const { - return GetCppComments(method_, false); - } - - private: - const grpc::protobuf::MethodDescriptor *method_; -}; - -class ProtoBufService : public grpc_cpp_generator::Service { - public: - ProtoBufService(const grpc::protobuf::ServiceDescriptor *service) - : service_(service) {} - - grpc::string name() const { return service_->name(); } - - int method_count() const { return service_->method_count(); }; - std::unique_ptr method(int i) const { - return std::unique_ptr( - new ProtoBufMethod(service_->method(i))); - }; - - grpc::string GetLeadingComments() const { - return GetCppComments(service_, true); - } - - grpc::string GetTrailingComments() const { - return GetCppComments(service_, false); - } - - private: - const grpc::protobuf::ServiceDescriptor *service_; -}; - -class ProtoBufPrinter : public grpc_cpp_generator::Printer { - public: - ProtoBufPrinter(grpc::string *str) - : output_stream_(str), printer_(&output_stream_, '$') {} - - void Print(const std::map &vars, - const char *string_template) { - printer_.Print(vars, string_template); - } - - void Print(const char *string) { printer_.Print(string); } - void Indent() { printer_.Indent(); } - void Outdent() { printer_.Outdent(); } - - private: - grpc::protobuf::io::StringOutputStream output_stream_; - grpc::protobuf::io::Printer printer_; -}; - -class ProtoBufFile : public grpc_cpp_generator::File { - public: - ProtoBufFile(const grpc::protobuf::FileDescriptor *file) : file_(file) {} - - grpc::string filename() const { return file_->name(); } - grpc::string filename_without_ext() const { - return grpc_generator::StripProto(filename()); - } - - grpc::string message_header_ext() const { return ".pb.h"; } - grpc::string service_header_ext() const { return ".grpc.pb.h"; } - - grpc::string package() const { return file_->package(); } - std::vector package_parts() const { - return grpc_generator::tokenize(package(), "."); - } - - grpc::string additional_headers() const { return ""; } - - int service_count() const { return file_->service_count(); }; - std::unique_ptr service(int i) const { - return std::unique_ptr( - new ProtoBufService(file_->service(i))); - } - - std::unique_ptr CreatePrinter( - grpc::string *str) const { - return std::unique_ptr( - new ProtoBufPrinter(str)); - } - - grpc::string GetLeadingComments() const { - return GetCppComments(file_, true); - } - - grpc::string GetTrailingComments() const { - return GetCppComments(file_, false); - } - - private: - const grpc::protobuf::FileDescriptor *file_; -}; +#include "src/compiler/protobuf_plugin.h" class CppGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { public: diff --git a/src/compiler/protobuf_plugin.h b/src/compiler/protobuf_plugin.h new file mode 100644 index 00000000000..cb01bd34987 --- /dev/null +++ b/src/compiler/protobuf_plugin.h @@ -0,0 +1,210 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_PROTOBUF_PLUGIN_H +#define GRPC_INTERNAL_COMPILER_PROTOBUF_PLUGIN_H + +#include "src/compiler/config.h" +#include "src/compiler/cpp_generator_helpers.h" +#include "src/compiler/python_generator_helpers.h" +#include "src/compiler/python_private_generator.h" +#include "src/compiler/schema_interface.h" + +#include + +// Get leading or trailing comments in a string. +template +inline grpc::string GetCommentsHelper(const DescriptorType *desc, bool leading, + const grpc::string &prefix) { + return grpc_generator::GetPrefixedComments(desc, leading, prefix); +} + +class ProtoBufMethod : public grpc_generator::Method { + public: + ProtoBufMethod(const grpc::protobuf::MethodDescriptor *method) + : method_(method) {} + + grpc::string name() const { return method_->name(); } + + grpc::string input_type_name() const { + return grpc_cpp_generator::ClassName(method_->input_type(), true); + } + grpc::string output_type_name() const { + return grpc_cpp_generator::ClassName(method_->output_type(), true); + } + + grpc::string get_input_type_name() const { + return method_->input_type()->file()->name(); + } + grpc::string get_output_type_name() const { + return method_->output_type()->file()->name(); + } + + bool get_module_and_message_path_input(grpc::string *str, + grpc::string generator_file_name, + bool generate_in_pb2_grpc, + grpc::string import_prefix) const { + return grpc_python_generator::GetModuleAndMessagePath( + method_->input_type(), str, generator_file_name, generate_in_pb2_grpc, + import_prefix); + } + + bool get_module_and_message_path_output(grpc::string *str, + grpc::string generator_file_name, + bool generate_in_pb2_grpc, + grpc::string import_prefix) const { + return grpc_python_generator::GetModuleAndMessagePath( + method_->output_type(), str, generator_file_name, generate_in_pb2_grpc, + import_prefix); + } + + bool NoStreaming() const { + return !method_->client_streaming() && !method_->server_streaming(); + } + + bool ClientStreaming() const { return method_->client_streaming(); } + + bool ServerStreaming() const { return method_->server_streaming(); } + + bool BidiStreaming() const { + return method_->client_streaming() && method_->server_streaming(); + } + + grpc::string GetLeadingComments(const grpc::string prefix) const { + return GetCommentsHelper(method_, true, prefix); + } + + grpc::string GetTrailingComments(const grpc::string prefix) const { + return GetCommentsHelper(method_, false, prefix); + } + + vector GetAllComments() const { + return grpc_python_generator::get_all_comments(method_); + } + + private: + const grpc::protobuf::MethodDescriptor *method_; +}; + +class ProtoBufService : public grpc_generator::Service { + public: + ProtoBufService(const grpc::protobuf::ServiceDescriptor *service) + : service_(service) {} + + grpc::string name() const { return service_->name(); } + + int method_count() const { return service_->method_count(); }; + std::unique_ptr method(int i) const { + return std::unique_ptr( + new ProtoBufMethod(service_->method(i))); + }; + + grpc::string GetLeadingComments(const grpc::string prefix) const { + return GetCommentsHelper(service_, true, prefix); + } + + grpc::string GetTrailingComments(const grpc::string prefix) const { + return GetCommentsHelper(service_, false, prefix); + } + + vector GetAllComments() const { + return grpc_python_generator::get_all_comments(service_); + } + + private: + const grpc::protobuf::ServiceDescriptor *service_; +}; + +class ProtoBufPrinter : public grpc_generator::Printer { + public: + ProtoBufPrinter(grpc::string *str) + : output_stream_(str), printer_(&output_stream_, '$') {} + + void Print(const std::map &vars, + const char *string_template) { + printer_.Print(vars, string_template); + } + + void Print(const char *string) { printer_.Print(string); } + void Indent() { printer_.Indent(); } + void Outdent() { printer_.Outdent(); } + + private: + grpc::protobuf::io::StringOutputStream output_stream_; + grpc::protobuf::io::Printer printer_; +}; + +class ProtoBufFile : public grpc_generator::File { + public: + ProtoBufFile(const grpc::protobuf::FileDescriptor *file) : file_(file) {} + + grpc::string filename() const { return file_->name(); } + grpc::string filename_without_ext() const { + return grpc_generator::StripProto(filename()); + } + + grpc::string package() const { return file_->package(); } + std::vector package_parts() const { + return grpc_generator::tokenize(package(), "."); + } + + grpc::string additional_headers() const { return ""; } + + int service_count() const { return file_->service_count(); }; + std::unique_ptr service(int i) const { + return std::unique_ptr( + new ProtoBufService(file_->service(i))); + } + + std::unique_ptr CreatePrinter( + grpc::string *str) const { + return std::unique_ptr(new ProtoBufPrinter(str)); + } + + grpc::string GetLeadingComments(const grpc::string prefix) const { + return GetCommentsHelper(file_, true, prefix); + } + + grpc::string GetTrailingComments(const grpc::string prefix) const { + return GetCommentsHelper(file_, false, prefix); + } + + vector GetAllComments() const { + return grpc_python_generator::get_all_comments(file_); + } + + private: + const grpc::protobuf::FileDescriptor *file_; +}; + +#endif // GRPC_INTERNAL_COMPILER_PROTOBUF_PLUGIN_H diff --git a/src/compiler/python_generator.cc b/src/compiler/python_generator.cc index 49d90fd36e2..2649c1688d4 100644 --- a/src/compiler/python_generator.cc +++ b/src/compiler/python_generator.cc @@ -47,20 +47,15 @@ #include "src/compiler/config.h" #include "src/compiler/generator_helpers.h" +#include "src/compiler/protobuf_plugin.h" #include "src/compiler/python_generator.h" +#include "src/compiler/python_generator_helpers.h" +#include "src/compiler/python_private_generator.h" -using grpc_generator::StringReplace; -using grpc_generator::StripProto; -using grpc::protobuf::Descriptor; using grpc::protobuf::FileDescriptor; -using grpc::protobuf::MethodDescriptor; -using grpc::protobuf::ServiceDescriptor; using grpc::protobuf::compiler::GeneratorContext; using grpc::protobuf::io::CodedOutputStream; -using grpc::protobuf::io::Printer; -using grpc::protobuf::io::StringOutputStream; using grpc::protobuf::io::ZeroCopyOutputStream; -using std::initializer_list; using std::make_pair; using std::map; using std::pair; @@ -71,9 +66,10 @@ using std::set; namespace grpc_python_generator { +grpc::string generator_file_name; + namespace { -typedef vector DescriptorVector; typedef map StringMap; typedef vector StringVector; typedef tuple StringPair; @@ -88,133 +84,22 @@ typedef set StringPairSet; // } class IndentScope { public: - explicit IndentScope(Printer* printer) : printer_(printer) { + explicit IndentScope(grpc_generator::Printer* printer) : printer_(printer) { printer_->Indent(); } ~IndentScope() { printer_->Outdent(); } private: - Printer* printer_; -}; - -// TODO(https://github.com/google/protobuf/issues/888): -// Export `ModuleName` from protobuf's -// `src/google/protobuf/compiler/python/python_generator.cc` file. -grpc::string ModuleName(const grpc::string& filename, - const grpc::string& import_prefix) { - grpc::string basename = StripProto(filename); - basename = StringReplace(basename, "-", "_"); - basename = StringReplace(basename, "/", "."); - return import_prefix + basename + "_pb2"; -} - -// TODO(https://github.com/google/protobuf/issues/888): -// Export `ModuleAlias` from protobuf's -// `src/google/protobuf/compiler/python/python_generator.cc` file. -grpc::string ModuleAlias(const grpc::string& filename, - const grpc::string& import_prefix) { - grpc::string module_name = ModuleName(filename, import_prefix); - // We can't have dots in the module name, so we replace each with _dot_. - // But that could lead to a collision between a.b and a_dot_b, so we also - // duplicate each underscore. - module_name = StringReplace(module_name, "_", "__"); - module_name = StringReplace(module_name, ".", "_dot_"); - return module_name; -} - -// Tucks all generator state in an anonymous namespace away from -// PythonGrpcGenerator and the header file, mostly to encourage future changes -// to not require updates to the grpcio-tools C++ code part. Assumes that it is -// only ever used from a single thread. -struct PrivateGenerator { - const GeneratorConfiguration& config; - const FileDescriptor* file; - - bool generate_in_pb2_grpc; - - Printer* out; - - PrivateGenerator(const GeneratorConfiguration& config, - const FileDescriptor* file); - - std::pair GetGrpcServices(); - - private: - bool PrintPreamble(); - bool PrintBetaPreamble(); - bool PrintGAServices(); - bool PrintBetaServices(); - - bool PrintAddServicerToServer( - const grpc::string& package_qualified_service_name, - const ServiceDescriptor* service); - bool PrintServicer(const ServiceDescriptor* service); - bool PrintStub(const grpc::string& package_qualified_service_name, - const ServiceDescriptor* service); - - bool PrintBetaServicer(const ServiceDescriptor* service); - bool PrintBetaServerFactory( - const grpc::string& package_qualified_service_name, - const ServiceDescriptor* service); - bool PrintBetaStub(const ServiceDescriptor* service); - bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name, - const ServiceDescriptor* service); - - // Get all comments (leading, leading_detached, trailing) and print them as a - // docstring. Any leading space of a line will be removed, but the line - // wrapping will not be changed. - template - void PrintAllComments(const DescriptorType* descriptor); - - bool GetModuleAndMessagePath(const Descriptor* type, grpc::string* out); + grpc_generator::Printer* printer_; }; PrivateGenerator::PrivateGenerator(const GeneratorConfiguration& config, - const FileDescriptor* file) + const grpc_generator::File* file) : config(config), file(file) {} -bool PrivateGenerator::GetModuleAndMessagePath(const Descriptor* type, - grpc::string* out) { - const Descriptor* path_elem_type = type; - DescriptorVector message_path; - do { - message_path.push_back(path_elem_type); - path_elem_type = path_elem_type->containing_type(); - } while (path_elem_type); // implicit nullptr comparison; don't be explicit - grpc::string file_name = type->file()->name(); - static const int proto_suffix_length = strlen(".proto"); - if (!(file_name.size() > static_cast(proto_suffix_length) && - file_name.find_last_of(".proto") == file_name.size() - 1)) { - return false; - } - grpc::string generator_file_name = file->name(); - grpc::string module; - if (generator_file_name != file_name || generate_in_pb2_grpc) { - module = ModuleAlias(file_name, config.import_prefix) + "."; - } else { - module = ""; - } - grpc::string message_type; - for (DescriptorVector::reverse_iterator path_iter = message_path.rbegin(); - path_iter != message_path.rend(); ++path_iter) { - message_type += (*path_iter)->name() + "."; - } - // no pop_back prior to C++11 - message_type.resize(message_type.size() - 1); - *out = module + message_type; - return true; -} - -template -void PrivateGenerator::PrintAllComments(const DescriptorType* descriptor) { - StringVector comments; - grpc_generator::GetComment( - descriptor, grpc_generator::COMMENTTYPE_LEADING_DETACHED, &comments); - grpc_generator::GetComment(descriptor, grpc_generator::COMMENTTYPE_LEADING, - &comments); - grpc_generator::GetComment(descriptor, grpc_generator::COMMENTTYPE_TRAILING, - &comments); +void PrivateGenerator::PrintAllComments(StringVector comments, + grpc_generator::Printer* out) { if (comments.empty()) { return; } @@ -230,10 +115,12 @@ void PrivateGenerator::PrintAllComments(const DescriptorType* descriptor) { out->Print("\"\"\"\n"); } -bool PrivateGenerator::PrintBetaServicer(const ServiceDescriptor* service) { +bool PrivateGenerator::PrintBetaServicer(const grpc_generator::Service* service, + grpc_generator::Printer* out) { + StringMap service_dict; + service_dict["Service"] = service->name(); out->Print("\n\n"); - out->Print("class Beta$Service$Servicer(object):\n", "Service", - service->name()); + out->Print(service_dict, "class Beta$Service$Servicer(object):\n"); { IndentScope raii_class_indent(out); out->Print( @@ -243,16 +130,20 @@ bool PrivateGenerator::PrintBetaServicer(const ServiceDescriptor* service) { "generated\n" "only to ease transition from grpcio<0.15.0 to " "grpcio>=0.15.0.\"\"\"\n"); - PrintAllComments(service); + StringVector service_comments = service->GetAllComments(); + PrintAllComments(service_comments, out); for (int i = 0; i < service->method_count(); ++i) { - const MethodDescriptor* method = service->method(i); + auto method = service->method(i); grpc::string arg_name = - method->client_streaming() ? "request_iterator" : "request"; - out->Print("def $Method$(self, $ArgName$, context):\n", "Method", - method->name(), "ArgName", arg_name); + method->ClientStreaming() ? "request_iterator" : "request"; + StringMap method_dict; + method_dict["Method"] = method->name(); + method_dict["ArgName"] = arg_name; + out->Print(method_dict, "def $Method$(self, $ArgName$, context):\n"); { IndentScope raii_method_indent(out); - PrintAllComments(method); + StringVector method_comments = method->GetAllComments(); + PrintAllComments(method_comments, out); out->Print("context.code(beta_interfaces.StatusCode.UNIMPLEMENTED)\n"); } } @@ -260,9 +151,12 @@ bool PrivateGenerator::PrintBetaServicer(const ServiceDescriptor* service) { return true; } -bool PrivateGenerator::PrintBetaStub(const ServiceDescriptor* service) { +bool PrivateGenerator::PrintBetaStub(const grpc_generator::Service* service, + grpc_generator::Printer* out) { + StringMap service_dict; + service_dict["Service"] = service->name(); out->Print("\n\n"); - out->Print("class Beta$Service$Stub(object):\n", "Service", service->name()); + out->Print(service_dict, "class Beta$Service$Stub(object):\n"); { IndentScope raii_class_indent(out); out->Print( @@ -272,11 +166,12 @@ bool PrivateGenerator::PrintBetaStub(const ServiceDescriptor* service) { "generated\n" "only to ease transition from grpcio<0.15.0 to " "grpcio>=0.15.0.\"\"\"\n"); - PrintAllComments(service); + StringVector service_comments = service->GetAllComments(); + PrintAllComments(service_comments, out); for (int i = 0; i < service->method_count(); ++i) { - const MethodDescriptor* method = service->method(i); + auto method = service->method(i); grpc::string arg_name = - method->client_streaming() ? "request_iterator" : "request"; + method->ClientStreaming() ? "request_iterator" : "request"; StringMap method_dict; method_dict["Method"] = method->name(); method_dict["ArgName"] = arg_name; @@ -285,10 +180,11 @@ bool PrivateGenerator::PrintBetaStub(const ServiceDescriptor* service) { "with_call=False, protocol_options=None):\n"); { IndentScope raii_method_indent(out); - PrintAllComments(method); + StringVector method_comments = method->GetAllComments(); + PrintAllComments(method_comments, out); out->Print("raise NotImplementedError()\n"); } - if (!method->server_streaming()) { + if (!method->ServerStreaming()) { out->Print(method_dict, "$Method$.future = None\n"); } } @@ -298,12 +194,13 @@ bool PrivateGenerator::PrintBetaStub(const ServiceDescriptor* service) { bool PrivateGenerator::PrintBetaServerFactory( const grpc::string& package_qualified_service_name, - const ServiceDescriptor* service) { + const grpc_generator::Service* service, grpc_generator::Printer* out) { + StringMap service_dict; + service_dict["Service"] = service->name(); out->Print("\n\n"); - out->Print( - "def beta_create_$Service$_server(servicer, pool=None, " - "pool_size=None, default_timeout=None, maximum_timeout=None):\n", - "Service", service->name()); + out->Print(service_dict, + "def beta_create_$Service$_server(servicer, pool=None, " + "pool_size=None, default_timeout=None, maximum_timeout=None):\n"); { IndentScope raii_create_server_indent(out); out->Print( @@ -316,19 +213,21 @@ bool PrivateGenerator::PrintBetaServerFactory( StringMap input_message_modules_and_classes; StringMap output_message_modules_and_classes; for (int i = 0; i < service->method_count(); ++i) { - const MethodDescriptor* method = service->method(i); + auto method = service->method(i); const grpc::string method_implementation_constructor = - grpc::string(method->client_streaming() ? "stream_" : "unary_") + - grpc::string(method->server_streaming() ? "stream_" : "unary_") + + grpc::string(method->ClientStreaming() ? "stream_" : "unary_") + + grpc::string(method->ServerStreaming() ? "stream_" : "unary_") + "inline"; grpc::string input_message_module_and_class; - if (!GetModuleAndMessagePath(method->input_type(), - &input_message_module_and_class)) { + if (!method->get_module_and_message_path_input( + &input_message_module_and_class, generator_file_name, + generate_in_pb2_grpc, config.import_prefix)) { return false; } grpc::string output_message_module_and_class; - if (!GetModuleAndMessagePath(method->output_type(), - &output_message_module_and_class)) { + if (!method->get_module_and_message_path_output( + &output_message_module_and_class, generator_file_name, + generate_in_pb2_grpc, config.import_prefix)) { return false; } method_implementation_constructors.insert( @@ -338,19 +237,21 @@ bool PrivateGenerator::PrintBetaServerFactory( output_message_modules_and_classes.insert( make_pair(method->name(), output_message_module_and_class)); } + StringMap method_dict; + method_dict["PackageQualifiedServiceName"] = package_qualified_service_name; out->Print("request_deserializers = {\n"); for (StringMap::iterator name_and_input_module_class_pair = input_message_modules_and_classes.begin(); name_and_input_module_class_pair != input_message_modules_and_classes.end(); name_and_input_module_class_pair++) { + method_dict["MethodName"] = name_and_input_module_class_pair->first; + method_dict["InputTypeModuleAndClass"] = + name_and_input_module_class_pair->second; IndentScope raii_indent(out); - out->Print( - "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " - "$InputTypeModuleAndClass$.FromString,\n", - "PackageQualifiedServiceName", package_qualified_service_name, - "MethodName", name_and_input_module_class_pair->first, - "InputTypeModuleAndClass", name_and_input_module_class_pair->second); + out->Print(method_dict, + "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " + "$InputTypeModuleAndClass$.FromString,\n"); } out->Print("}\n"); out->Print("response_serializers = {\n"); @@ -359,14 +260,13 @@ bool PrivateGenerator::PrintBetaServerFactory( name_and_output_module_class_pair != output_message_modules_and_classes.end(); name_and_output_module_class_pair++) { + method_dict["MethodName"] = name_and_output_module_class_pair->first; + method_dict["OutputTypeModuleAndClass"] = + name_and_output_module_class_pair->second; IndentScope raii_indent(out); - out->Print( - "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " - "$OutputTypeModuleAndClass$.SerializeToString,\n", - "PackageQualifiedServiceName", package_qualified_service_name, - "MethodName", name_and_output_module_class_pair->first, - "OutputTypeModuleAndClass", - name_and_output_module_class_pair->second); + out->Print(method_dict, + "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " + "$OutputTypeModuleAndClass$.SerializeToString,\n"); } out->Print("}\n"); out->Print("method_implementations = {\n"); @@ -375,15 +275,14 @@ bool PrivateGenerator::PrintBetaServerFactory( name_and_implementation_constructor != method_implementation_constructors.end(); name_and_implementation_constructor++) { + method_dict["Method"] = name_and_implementation_constructor->first; + method_dict["Constructor"] = name_and_implementation_constructor->second; IndentScope raii_descriptions_indent(out); const grpc::string method_name = name_and_implementation_constructor->first; - out->Print( - "(\'$PackageQualifiedServiceName$\', \'$Method$\'): " - "face_utilities.$Constructor$(servicer.$Method$),\n", - "PackageQualifiedServiceName", package_qualified_service_name, - "Method", name_and_implementation_constructor->first, "Constructor", - name_and_implementation_constructor->second); + out->Print(method_dict, + "(\'$PackageQualifiedServiceName$\', \'$Method$\'): " + "face_utilities.$Constructor$(servicer.$Method$),\n"); } out->Print("}\n"); out->Print( @@ -402,7 +301,7 @@ bool PrivateGenerator::PrintBetaServerFactory( bool PrivateGenerator::PrintBetaStubFactory( const grpc::string& package_qualified_service_name, - const ServiceDescriptor* service) { + const grpc_generator::Service* service, grpc_generator::Printer* out) { StringMap dict; dict["Service"] = service->name(); out->Print("\n\n"); @@ -421,18 +320,20 @@ bool PrivateGenerator::PrintBetaStubFactory( StringMap input_message_modules_and_classes; StringMap output_message_modules_and_classes; for (int i = 0; i < service->method_count(); ++i) { - const MethodDescriptor* method = service->method(i); + auto method = service->method(i); const grpc::string method_cardinality = - grpc::string(method->client_streaming() ? "STREAM" : "UNARY") + "_" + - grpc::string(method->server_streaming() ? "STREAM" : "UNARY"); + grpc::string(method->ClientStreaming() ? "STREAM" : "UNARY") + "_" + + grpc::string(method->ServerStreaming() ? "STREAM" : "UNARY"); grpc::string input_message_module_and_class; - if (!GetModuleAndMessagePath(method->input_type(), - &input_message_module_and_class)) { + if (!method->get_module_and_message_path_input( + &input_message_module_and_class, generator_file_name, + generate_in_pb2_grpc, config.import_prefix)) { return false; } grpc::string output_message_module_and_class; - if (!GetModuleAndMessagePath(method->output_type(), - &output_message_module_and_class)) { + if (!method->get_module_and_message_path_output( + &output_message_module_and_class, generator_file_name, + generate_in_pb2_grpc, config.import_prefix)) { return false; } method_cardinalities.insert( @@ -442,19 +343,21 @@ bool PrivateGenerator::PrintBetaStubFactory( output_message_modules_and_classes.insert( make_pair(method->name(), output_message_module_and_class)); } + StringMap method_dict; + method_dict["PackageQualifiedServiceName"] = package_qualified_service_name; out->Print("request_serializers = {\n"); for (StringMap::iterator name_and_input_module_class_pair = input_message_modules_and_classes.begin(); name_and_input_module_class_pair != input_message_modules_and_classes.end(); name_and_input_module_class_pair++) { + method_dict["MethodName"] = name_and_input_module_class_pair->first; + method_dict["InputTypeModuleAndClass"] = + name_and_input_module_class_pair->second; IndentScope raii_indent(out); - out->Print( - "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " - "$InputTypeModuleAndClass$.SerializeToString,\n", - "PackageQualifiedServiceName", package_qualified_service_name, - "MethodName", name_and_input_module_class_pair->first, - "InputTypeModuleAndClass", name_and_input_module_class_pair->second); + out->Print(method_dict, + "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " + "$InputTypeModuleAndClass$.SerializeToString,\n"); } out->Print("}\n"); out->Print("response_deserializers = {\n"); @@ -463,14 +366,13 @@ bool PrivateGenerator::PrintBetaStubFactory( name_and_output_module_class_pair != output_message_modules_and_classes.end(); name_and_output_module_class_pair++) { + method_dict["MethodName"] = name_and_output_module_class_pair->first; + method_dict["OutputTypeModuleAndClass"] = + name_and_output_module_class_pair->second; IndentScope raii_indent(out); - out->Print( - "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " - "$OutputTypeModuleAndClass$.FromString,\n", - "PackageQualifiedServiceName", package_qualified_service_name, - "MethodName", name_and_output_module_class_pair->first, - "OutputTypeModuleAndClass", - name_and_output_module_class_pair->second); + out->Print(method_dict, + "(\'$PackageQualifiedServiceName$\', \'$MethodName$\'): " + "$OutputTypeModuleAndClass$.FromString,\n"); } out->Print("}\n"); out->Print("cardinalities = {\n"); @@ -478,10 +380,11 @@ bool PrivateGenerator::PrintBetaStubFactory( method_cardinalities.begin(); name_and_cardinality != method_cardinalities.end(); name_and_cardinality++) { + method_dict["Method"] = name_and_cardinality->first; + method_dict["Cardinality"] = name_and_cardinality->second; IndentScope raii_descriptions_indent(out); - out->Print("\'$Method$\': cardinality.Cardinality.$Cardinality$,\n", - "Method", name_and_cardinality->first, "Cardinality", - name_and_cardinality->second); + out->Print(method_dict, + "\'$Method$\': cardinality.Cardinality.$Cardinality$,\n"); } out->Print("}\n"); out->Print( @@ -490,23 +393,25 @@ bool PrivateGenerator::PrintBetaStubFactory( "request_serializers=request_serializers, " "response_deserializers=response_deserializers, " "thread_pool=pool, thread_pool_size=pool_size)\n"); - out->Print( - "return beta_implementations.dynamic_stub(channel, " - "\'$PackageQualifiedServiceName$\', " - "cardinalities, options=stub_options)\n", - "PackageQualifiedServiceName", package_qualified_service_name); + out->Print(method_dict, + "return beta_implementations.dynamic_stub(channel, " + "\'$PackageQualifiedServiceName$\', " + "cardinalities, options=stub_options)\n"); } return true; } bool PrivateGenerator::PrintStub( const grpc::string& package_qualified_service_name, - const ServiceDescriptor* service) { + const grpc_generator::Service* service, grpc_generator::Printer* out) { + StringMap dict; + dict["Service"] = service->name(); out->Print("\n\n"); - out->Print("class $Service$Stub(object):\n", "Service", service->name()); + out->Print(dict, "class $Service$Stub(object):\n"); { IndentScope raii_class_indent(out); - PrintAllComments(service); + StringVector service_comments = service->GetAllComments(); + PrintAllComments(service_comments, out); out->Print("\n"); out->Print("def __init__(self, channel):\n"); { @@ -520,35 +425,41 @@ bool PrivateGenerator::PrintStub( } out->Print("\"\"\"\n"); for (int i = 0; i < service->method_count(); ++i) { - const MethodDescriptor* method = service->method(i); + auto method = service->method(i); grpc::string multi_callable_constructor = - grpc::string(method->client_streaming() ? "stream" : "unary") + - "_" + grpc::string(method->server_streaming() ? "stream" : "unary"); + grpc::string(method->ClientStreaming() ? "stream" : "unary") + "_" + + grpc::string(method->ServerStreaming() ? "stream" : "unary"); grpc::string request_module_and_class; - if (!GetModuleAndMessagePath(method->input_type(), - &request_module_and_class)) { + if (!method->get_module_and_message_path_input( + &request_module_and_class, generator_file_name, + generate_in_pb2_grpc, config.import_prefix)) { return false; } grpc::string response_module_and_class; - if (!GetModuleAndMessagePath(method->output_type(), - &response_module_and_class)) { + if (!method->get_module_and_message_path_output( + &response_module_and_class, generator_file_name, + generate_in_pb2_grpc, config.import_prefix)) { return false; } - out->Print("self.$Method$ = channel.$MultiCallableConstructor$(\n", - "Method", method->name(), "MultiCallableConstructor", - multi_callable_constructor); + StringMap method_dict; + method_dict["Method"] = method->name(); + method_dict["MultiCallableConstructor"] = multi_callable_constructor; + out->Print(method_dict, + "self.$Method$ = channel.$MultiCallableConstructor$(\n"); { + method_dict["PackageQualifiedService"] = + package_qualified_service_name; + method_dict["RequestModuleAndClass"] = request_module_and_class; + method_dict["ResponseModuleAndClass"] = response_module_and_class; IndentScope raii_first_attribute_indent(out); IndentScope raii_second_attribute_indent(out); - out->Print("'/$PackageQualifiedService$/$Method$',\n", - "PackageQualifiedService", package_qualified_service_name, - "Method", method->name()); - out->Print( - "request_serializer=$RequestModuleAndClass$.SerializeToString,\n", - "RequestModuleAndClass", request_module_and_class); + out->Print(method_dict, "'/$PackageQualifiedService$/$Method$',\n"); + out->Print(method_dict, + "request_serializer=$RequestModuleAndClass$." + "SerializeToString,\n"); out->Print( - "response_deserializer=$ResponseModuleAndClass$.FromString,\n", - "ResponseModuleAndClass", response_module_and_class); + method_dict, + "response_deserializer=$ResponseModuleAndClass$.FromString,\n"); out->Print(")\n"); } } @@ -557,22 +468,29 @@ bool PrivateGenerator::PrintStub( return true; } -bool PrivateGenerator::PrintServicer(const ServiceDescriptor* service) { +bool PrivateGenerator::PrintServicer(const grpc_generator::Service* service, + grpc_generator::Printer* out) { + StringMap service_dict; + service_dict["Service"] = service->name(); out->Print("\n\n"); - out->Print("class $Service$Servicer(object):\n", "Service", service->name()); + out->Print(service_dict, "class $Service$Servicer(object):\n"); { IndentScope raii_class_indent(out); - PrintAllComments(service); + StringVector service_comments = service->GetAllComments(); + PrintAllComments(service_comments, out); for (int i = 0; i < service->method_count(); ++i) { - const MethodDescriptor* method = service->method(i); + auto method = service->method(i); grpc::string arg_name = - method->client_streaming() ? "request_iterator" : "request"; + method->ClientStreaming() ? "request_iterator" : "request"; + StringMap method_dict; + method_dict["Method"] = method->name(); + method_dict["ArgName"] = arg_name; out->Print("\n"); - out->Print("def $Method$(self, $ArgName$, context):\n", "Method", - method->name(), "ArgName", arg_name); + out->Print(method_dict, "def $Method$(self, $ArgName$, context):\n"); { IndentScope raii_method_indent(out); - PrintAllComments(method); + StringVector method_comments = method->GetAllComments(); + PrintAllComments(method_comments, out); out->Print("context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n"); out->Print("context.set_details('Method not implemented!')\n"); out->Print("raise NotImplementedError('Method not implemented!')\n"); @@ -584,10 +502,12 @@ bool PrivateGenerator::PrintServicer(const ServiceDescriptor* service) { bool PrivateGenerator::PrintAddServicerToServer( const grpc::string& package_qualified_service_name, - const ServiceDescriptor* service) { + const grpc_generator::Service* service, grpc_generator::Printer* out) { + StringMap service_dict; + service_dict["Service"] = service->name(); out->Print("\n\n"); - out->Print("def add_$Service$Servicer_to_server(servicer, server):\n", - "Service", service->name()); + out->Print(service_dict, + "def add_$Service$Servicer_to_server(servicer, server):\n"); { IndentScope raii_class_indent(out); out->Print("rpc_method_handlers = {\n"); @@ -595,58 +515,66 @@ bool PrivateGenerator::PrintAddServicerToServer( IndentScope raii_dict_first_indent(out); IndentScope raii_dict_second_indent(out); for (int i = 0; i < service->method_count(); ++i) { - const MethodDescriptor* method = service->method(i); + auto method = service->method(i); grpc::string method_handler_constructor = - grpc::string(method->client_streaming() ? "stream" : "unary") + - "_" + - grpc::string(method->server_streaming() ? "stream" : "unary") + + grpc::string(method->ClientStreaming() ? "stream" : "unary") + "_" + + grpc::string(method->ServerStreaming() ? "stream" : "unary") + "_rpc_method_handler"; grpc::string request_module_and_class; - if (!GetModuleAndMessagePath(method->input_type(), - &request_module_and_class)) { + if (!method->get_module_and_message_path_input( + &request_module_and_class, generator_file_name, + generate_in_pb2_grpc, config.import_prefix)) { return false; } grpc::string response_module_and_class; - if (!GetModuleAndMessagePath(method->output_type(), - &response_module_and_class)) { + if (!method->get_module_and_message_path_output( + &response_module_and_class, generator_file_name, + generate_in_pb2_grpc, config.import_prefix)) { return false; } - out->Print("'$Method$': grpc.$MethodHandlerConstructor$(\n", "Method", - method->name(), "MethodHandlerConstructor", - method_handler_constructor); + StringMap method_dict; + method_dict["Method"] = method->name(); + method_dict["MethodHandlerConstructor"] = method_handler_constructor; + method_dict["RequestModuleAndClass"] = request_module_and_class; + method_dict["ResponseModuleAndClass"] = response_module_and_class; + out->Print(method_dict, + "'$Method$': grpc.$MethodHandlerConstructor$(\n"); { IndentScope raii_call_first_indent(out); IndentScope raii_call_second_indent(out); - out->Print("servicer.$Method$,\n", "Method", method->name()); + out->Print(method_dict, "servicer.$Method$,\n"); out->Print( - "request_deserializer=$RequestModuleAndClass$.FromString,\n", - "RequestModuleAndClass", request_module_and_class); + method_dict, + "request_deserializer=$RequestModuleAndClass$.FromString,\n"); out->Print( + method_dict, "response_serializer=$ResponseModuleAndClass$.SerializeToString," - "\n", - "ResponseModuleAndClass", response_module_and_class); + "\n"); } out->Print("),\n"); } } + StringMap method_dict; + method_dict["PackageQualifiedServiceName"] = package_qualified_service_name; out->Print("}\n"); out->Print("generic_handler = grpc.method_handlers_generic_handler(\n"); { IndentScope raii_call_first_indent(out); IndentScope raii_call_second_indent(out); - out->Print("'$PackageQualifiedServiceName$', rpc_method_handlers)\n", - "PackageQualifiedServiceName", package_qualified_service_name); + out->Print(method_dict, + "'$PackageQualifiedServiceName$', rpc_method_handlers)\n"); } out->Print("server.add_generic_rpc_handlers((generic_handler,))\n"); } return true; } -bool PrivateGenerator::PrintBetaPreamble() { - out->Print("from $Package$ import implementations as beta_implementations\n", - "Package", config.beta_package_root); - out->Print("from $Package$ import interfaces as beta_interfaces\n", "Package", - config.beta_package_root); +bool PrivateGenerator::PrintBetaPreamble(grpc_generator::Printer* out) { + StringMap var; + var["Package"] = config.beta_package_root; + out->Print(var, + "from $Package$ import implementations as beta_implementations\n"); + out->Print(var, "from $Package$ import interfaces as beta_interfaces\n"); out->Print("from grpc.framework.common import cardinality\n"); out->Print( "from grpc.framework.interfaces.face import utilities as " @@ -654,65 +582,78 @@ bool PrivateGenerator::PrintBetaPreamble() { return true; } -bool PrivateGenerator::PrintPreamble() { - out->Print("import $Package$\n", "Package", config.grpc_package_root); +bool PrivateGenerator::PrintPreamble(grpc_generator::Printer* out) { + StringMap var; + var["Package"] = config.grpc_package_root; + out->Print(var, "import $Package$\n"); if (generate_in_pb2_grpc) { out->Print("\n"); StringPairSet imports_set; for (int i = 0; i < file->service_count(); ++i) { - const ServiceDescriptor* service = file->service(i); + auto service = file->service(i); for (int j = 0; j < service->method_count(); ++j) { - const MethodDescriptor* method = service->method(j); - const Descriptor* types[2] = {method->input_type(), - method->output_type()}; - for (int k = 0; k < 2; ++k) { - const Descriptor* type = types[k]; - grpc::string type_file_name = type->file()->name(); - grpc::string module_name = - ModuleName(type_file_name, config.import_prefix); - grpc::string module_alias = - ModuleAlias(type_file_name, config.import_prefix); - imports_set.insert(std::make_tuple(module_name, module_alias)); - } + auto method = service.get()->method(j); + + grpc::string input_type_file_name = method->get_input_type_name(); + grpc::string input_module_name = + ModuleName(input_type_file_name, config.import_prefix); + grpc::string input_module_alias = + ModuleAlias(input_type_file_name, config.import_prefix); + imports_set.insert( + std::make_tuple(input_module_name, input_module_alias)); + + grpc::string output_type_file_name = method->get_output_type_name(); + grpc::string output_module_name = + ModuleName(output_type_file_name, config.import_prefix); + grpc::string output_module_alias = + ModuleAlias(output_type_file_name, config.import_prefix); + imports_set.insert( + std::make_tuple(output_module_name, output_module_alias)); } } + for (StringPairSet::iterator it = imports_set.begin(); it != imports_set.end(); ++it) { - out->Print("import $ModuleName$ as $ModuleAlias$\n", "ModuleName", - std::get<0>(*it), "ModuleAlias", std::get<1>(*it)); + var["ModuleName"] = std::get<0>(*it); + var["ModuleAlias"] = std::get<1>(*it); + out->Print(var, "import $ModuleName$ as $ModuleAlias$\n"); } } return true; } -bool PrivateGenerator::PrintGAServices() { +bool PrivateGenerator::PrintGAServices(grpc_generator::Printer* out) { grpc::string package = file->package(); if (!package.empty()) { package = package.append("."); } for (int i = 0; i < file->service_count(); ++i) { - const ServiceDescriptor* service = file->service(i); + auto service = file->service(i); grpc::string package_qualified_service_name = package + service->name(); - if (!(PrintStub(package_qualified_service_name, service) && - PrintServicer(service) && - PrintAddServicerToServer(package_qualified_service_name, service))) { + if (!(PrintStub(package_qualified_service_name, service.get(), out) && + PrintServicer(service.get(), out) && + PrintAddServicerToServer(package_qualified_service_name, + service.get(), out))) { return false; } } return true; } -bool PrivateGenerator::PrintBetaServices() { +bool PrivateGenerator::PrintBetaServices(grpc_generator::Printer* out) { grpc::string package = file->package(); if (!package.empty()) { package = package.append("."); } for (int i = 0; i < file->service_count(); ++i) { - const ServiceDescriptor* service = file->service(i); + auto service = file->service(i); grpc::string package_qualified_service_name = package + service->name(); - if (!(PrintBetaServicer(service) && PrintBetaStub(service) && - PrintBetaServerFactory(package_qualified_service_name, service) && - PrintBetaStubFactory(package_qualified_service_name, service))) { + if (!(PrintBetaServicer(service.get(), out) && + PrintBetaStub(service.get(), out) && + PrintBetaServerFactory(package_qualified_service_name, service.get(), + out) && + PrintBetaStubFactory(package_qualified_service_name, service.get(), + out))) { return false; } } @@ -723,43 +664,40 @@ pair PrivateGenerator::GetGrpcServices() { grpc::string output; { // Scope the output stream so it closes and finalizes output to the string. - StringOutputStream output_stream(&output); - Printer out_printer(&output_stream, '$'); - out = &out_printer; - + auto out = file->CreatePrinter(&output); if (generate_in_pb2_grpc) { out->Print( "# Generated by the gRPC Python protocol compiler plugin. " "DO NOT EDIT!\n"); - if (!PrintPreamble()) { + if (!PrintPreamble(out.get())) { return make_pair(false, ""); } - if (!PrintGAServices()) { + if (!PrintGAServices(out.get())) { return make_pair(false, ""); } } else { out->Print("try:\n"); { - IndentScope raii_dict_try_indent(out); + IndentScope raii_dict_try_indent(out.get()); out->Print( "# THESE ELEMENTS WILL BE DEPRECATED.\n" "# Please use the generated *_pb2_grpc.py files instead.\n"); - if (!PrintPreamble()) { + if (!PrintPreamble(out.get())) { return make_pair(false, ""); } - if (!PrintBetaPreamble()) { + if (!PrintBetaPreamble(out.get())) { return make_pair(false, ""); } - if (!PrintGAServices()) { + if (!PrintGAServices(out.get())) { return make_pair(false, ""); } - if (!PrintBetaServices()) { + if (!PrintBetaServices(out.get())) { return make_pair(false, ""); } } out->Print("except ImportError:\n"); { - IndentScope raii_dict_except_indent(out); + IndentScope raii_dict_except_indent(out.get()); out->Print("pass"); } } @@ -823,8 +761,10 @@ bool PythonGrpcGenerator::Generate(const FileDescriptor* file, *error = "Invalid proto file name. Proto file must end with .proto"; return false; } + generator_file_name = file->name(); - PrivateGenerator generator(config_, file); + ProtoBufFile pbfile(file); + PrivateGenerator generator(config_, &pbfile); if (parameter == "grpc_2_0") { return GenerateGrpc(context, generator, pb2_grpc_file_name, true); } else if (parameter == "") { diff --git a/src/compiler/python_generator.h b/src/compiler/python_generator.h index b91059fad77..0c0d7449b56 100644 --- a/src/compiler/python_generator.h +++ b/src/compiler/python_generator.h @@ -37,6 +37,7 @@ #include #include "src/compiler/config.h" +#include "src/compiler/schema_interface.h" namespace grpc_python_generator { diff --git a/src/compiler/python_generator_helpers.h b/src/compiler/python_generator_helpers.h new file mode 100644 index 00000000000..9fca711c183 --- /dev/null +++ b/src/compiler/python_generator_helpers.h @@ -0,0 +1,142 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_HELPERS_H +#define GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_HELPERS_H + +#include +#include +#include +#include + +#include "src/compiler/config.h" +#include "src/compiler/generator_helpers.h" +#include "src/compiler/python_generator.h" +#include "src/compiler/python_private_generator.h" + +using std::vector; +using grpc_generator::StringReplace; +using grpc_generator::StripProto; +using grpc::protobuf::Descriptor; +using grpc::protobuf::FileDescriptor; +using grpc::protobuf::MethodDescriptor; +using grpc::protobuf::ServiceDescriptor; +using grpc::protobuf::compiler::GeneratorContext; +using grpc::protobuf::io::CodedOutputStream; +using grpc::protobuf::io::Printer; +using grpc::protobuf::io::StringOutputStream; +using grpc::protobuf::io::ZeroCopyOutputStream; + +namespace grpc_python_generator { + +namespace { + +typedef vector DescriptorVector; +typedef vector StringVector; + +// TODO(https://github.com/google/protobuf/issues/888): +// Export `ModuleName` from protobuf's +// `src/google/protobuf/compiler/python/python_generator.cc` file. +grpc::string ModuleName(const grpc::string& filename, + const grpc::string& import_prefix) { + grpc::string basename = StripProto(filename); + basename = StringReplace(basename, "-", "_"); + basename = StringReplace(basename, "/", "."); + return import_prefix + basename + "_pb2"; +} + +// TODO(https://github.com/google/protobuf/issues/888): +// Export `ModuleAlias` from protobuf's +// `src/google/protobuf/compiler/python/python_generator.cc` file. +grpc::string ModuleAlias(const grpc::string& filename, + const grpc::string& import_prefix) { + grpc::string module_name = ModuleName(filename, import_prefix); + // We can't have dots in the module name, so we replace each with _dot_. + // But that could lead to a collision between a.b and a_dot_b, so we also + // duplicate each underscore. + module_name = StringReplace(module_name, "_", "__"); + module_name = StringReplace(module_name, ".", "_dot_"); + return module_name; +} + +bool GetModuleAndMessagePath(const Descriptor* type, grpc::string* out, + grpc::string generator_file_name, + bool generate_in_pb2_grpc, + grpc::string& import_prefix) { + const Descriptor* path_elem_type = type; + DescriptorVector message_path; + do { + message_path.push_back(path_elem_type); + path_elem_type = path_elem_type->containing_type(); + } while (path_elem_type); // implicit nullptr comparison; don't be explicit + grpc::string file_name = type->file()->name(); + static const int proto_suffix_length = strlen(".proto"); + if (!(file_name.size() > static_cast(proto_suffix_length) && + file_name.find_last_of(".proto") == file_name.size() - 1)) { + return false; + } + + grpc::string module; + if (generator_file_name != file_name || generate_in_pb2_grpc) { + module = ModuleAlias(file_name, import_prefix) + "."; + } else { + module = ""; + } + grpc::string message_type; + for (DescriptorVector::reverse_iterator path_iter = message_path.rbegin(); + path_iter != message_path.rend(); ++path_iter) { + message_type += (*path_iter)->name() + "."; + } + // no pop_back prior to C++11 + message_type.resize(message_type.size() - 1); + *out = module + message_type; + return true; +} + +template +StringVector get_all_comments(const DescriptorType* descriptor) { + StringVector comments; + grpc_generator::GetComment( + descriptor, grpc_generator::COMMENTTYPE_LEADING_DETACHED, &comments); + grpc_generator::GetComment(descriptor, grpc_generator::COMMENTTYPE_LEADING, + &comments); + grpc_generator::GetComment(descriptor, grpc_generator::COMMENTTYPE_TRAILING, + &comments); + return comments; +} + +} // namespace + +} // namespace grpc_python_generator + +#endif // GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_HELPERS_H diff --git a/src/compiler/python_plugin.cc b/src/compiler/python_plugin.cc index 3457aa631a3..f34abcc3139 100644 --- a/src/compiler/python_plugin.cc +++ b/src/compiler/python_plugin.cc @@ -34,6 +34,7 @@ // Generates a Python gRPC service interface out of Protobuf IDL. #include "src/compiler/config.h" +#include "src/compiler/protobuf_plugin.h" #include "src/compiler/python_generator.h" int main(int argc, char* argv[]) { diff --git a/src/compiler/python_private_generator.h b/src/compiler/python_private_generator.h new file mode 100644 index 00000000000..d20ff51b204 --- /dev/null +++ b/src/compiler/python_private_generator.h @@ -0,0 +1,99 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_PYTHON_PRIVATE_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_PYTHON_PRIVATE_GENERATOR_H + +#include +#include + +#include "src/compiler/python_generator.h" +#include "src/compiler/schema_interface.h" + +namespace grpc_python_generator { + +namespace { + +// Tucks all generator state in an anonymous namespace away from +// PythonGrpcGenerator and the header file, mostly to encourage future changes +// to not require updates to the grpcio-tools C++ code part. Assumes that it is +// only ever used from a single thread. +struct PrivateGenerator { + const GeneratorConfiguration& config; + const grpc_generator::File* file; + + bool generate_in_pb2_grpc; + + PrivateGenerator(const GeneratorConfiguration& config, + const grpc_generator::File* file); + + std::pair GetGrpcServices(); + + private: + bool PrintPreamble(grpc_generator::Printer* out); + bool PrintBetaPreamble(grpc_generator::Printer* out); + bool PrintGAServices(grpc_generator::Printer* out); + bool PrintBetaServices(grpc_generator::Printer* out); + + bool PrintAddServicerToServer( + const grpc::string& package_qualified_service_name, + const grpc_generator::Service* service, grpc_generator::Printer* out); + bool PrintServicer(const grpc_generator::Service* service, + grpc_generator::Printer* out); + bool PrintStub(const grpc::string& package_qualified_service_name, + const grpc_generator::Service* service, + grpc_generator::Printer* out); + + bool PrintBetaServicer(const grpc_generator::Service* service, + grpc_generator::Printer* out); + bool PrintBetaServerFactory( + const grpc::string& package_qualified_service_name, + const grpc_generator::Service* service, grpc_generator::Printer* out); + bool PrintBetaStub(const grpc_generator::Service* service, + grpc_generator::Printer* out); + bool PrintBetaStubFactory(const grpc::string& package_qualified_service_name, + const grpc_generator::Service* service, + grpc_generator::Printer* out); + + // Get all comments (leading, leading_detached, trailing) and print them as a + // docstring. Any leading space of a line will be removed, but the line + // wrapping will not be changed. + void PrintAllComments(std::vector comments, + grpc_generator::Printer* out); +}; + +} // namespace + +} // namespace grpc_python_generator + +#endif // GRPC_INTERNAL_COMPILER_PYTHON_PRIVATE_GENERATOR_H diff --git a/src/compiler/schema_interface.h b/src/compiler/schema_interface.h new file mode 100644 index 00000000000..25bbdb51420 --- /dev/null +++ b/src/compiler/schema_interface.h @@ -0,0 +1,126 @@ +/* + * + * Copyright 2015, Google Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H +#define GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H + +#include "src/compiler/config.h" + +#include +#include + +#ifndef GRPC_CUSTOM_STRING +#include +#define GRPC_CUSTOM_STRING std::string +#endif + +namespace grpc { + +typedef GRPC_CUSTOM_STRING string; + +} // namespace grpc + +namespace grpc_generator { + +// A common interface for objects having comments in the source. +// Return formatted comments to be inserted in generated code. +struct CommentHolder { + virtual ~CommentHolder() {} + virtual grpc::string GetLeadingComments(const grpc::string prefix) const = 0; + virtual grpc::string GetTrailingComments(const grpc::string prefix) const = 0; + virtual std::vector GetAllComments() const = 0; +}; + +// An abstract interface representing a method. +struct Method : public CommentHolder { + virtual ~Method() {} + + virtual grpc::string name() const = 0; + + virtual grpc::string input_type_name() const = 0; + virtual grpc::string output_type_name() const = 0; + + virtual bool get_module_and_message_path_input( + grpc::string *str, grpc::string generator_file_name, + bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0; + virtual bool get_module_and_message_path_output( + grpc::string *str, grpc::string generator_file_name, + bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0; + + virtual grpc::string get_input_type_name() const = 0; + virtual grpc::string get_output_type_name() const = 0; + virtual bool NoStreaming() const = 0; + virtual bool ClientStreaming() const = 0; + virtual bool ServerStreaming() const = 0; + virtual bool BidiStreaming() const = 0; +}; + +// An abstract interface representing a service. +struct Service : public CommentHolder { + virtual ~Service() {} + + virtual grpc::string name() const = 0; + + virtual int method_count() const = 0; + virtual std::unique_ptr method(int i) const = 0; +}; + +struct Printer { + virtual ~Printer() {} + + virtual void Print(const std::map &vars, + const char *template_string) = 0; + virtual void Print(const char *string) = 0; + virtual void Indent() = 0; + virtual void Outdent() = 0; +}; + +// An interface that allows the source generated to be output using various +// libraries/idls/serializers. +struct File : public CommentHolder { + virtual ~File() {} + + virtual grpc::string filename() const = 0; + virtual grpc::string filename_without_ext() const = 0; + virtual grpc::string package() const = 0; + virtual std::vector package_parts() const = 0; + virtual grpc::string additional_headers() const = 0; + + virtual int service_count() const = 0; + virtual std::unique_ptr service(int i) const = 0; + + virtual std::unique_ptr CreatePrinter(grpc::string *str) const = 0; +}; +} // namespace grpc_generator + +#endif // GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H diff --git a/tools/run_tests/generated/sources_and_headers.json b/tools/run_tests/generated/sources_and_headers.json index 894a8953de0..0718c4160a3 100644 --- a/tools/run_tests/generated/sources_and_headers.json +++ b/tools/run_tests/generated/sources_and_headers.json @@ -6014,11 +6014,15 @@ "src/compiler/objective_c_generator_helpers.h", "src/compiler/php_generator.h", "src/compiler/php_generator_helpers.h", + "src/compiler/protobuf_plugin.h", "src/compiler/python_generator.h", + "src/compiler/python_generator_helpers.h", + "src/compiler/python_private_generator.h", "src/compiler/ruby_generator.h", "src/compiler/ruby_generator_helpers-inl.h", "src/compiler/ruby_generator_map-inl.h", - "src/compiler/ruby_generator_string-inl.h" + "src/compiler/ruby_generator_string-inl.h", + "src/compiler/schema_interface.h" ], "is_filegroup": false, "language": "c++", @@ -6041,13 +6045,17 @@ "src/compiler/php_generator.cc", "src/compiler/php_generator.h", "src/compiler/php_generator_helpers.h", + "src/compiler/protobuf_plugin.h", "src/compiler/python_generator.cc", "src/compiler/python_generator.h", + "src/compiler/python_generator_helpers.h", + "src/compiler/python_private_generator.h", "src/compiler/ruby_generator.cc", "src/compiler/ruby_generator.h", "src/compiler/ruby_generator_helpers-inl.h", "src/compiler/ruby_generator_map-inl.h", - "src/compiler/ruby_generator_string-inl.h" + "src/compiler/ruby_generator_string-inl.h", + "src/compiler/schema_interface.h" ], "third_party": false, "type": "lib" diff --git a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj index 05165d6fb80..a3d5b26be47 100644 --- a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj +++ b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj @@ -163,11 +163,15 @@ + + + + diff --git a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters index c8b893221d3..8fa3a0fa72c 100644 --- a/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters +++ b/vsprojects/vcxproj/grpc_plugin_support/grpc_plugin_support.vcxproj.filters @@ -65,9 +65,18 @@ src\compiler + + src\compiler + src\compiler + + src\compiler + + + src\compiler + src\compiler @@ -80,6 +89,9 @@ src\compiler + + src\compiler +