1 /*
2 *
3 * Copyright 2015 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19 #ifndef GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_HELPERS_H
20 #define GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_HELPERS_H
21
22 #include <cstring>
23 #include <fstream>
24 #include <iostream>
25 #include <vector>
26
27 #include "src/compiler/config.h"
28 #include "src/compiler/generator_helpers.h"
29 #include "src/compiler/python_generator.h"
30 #include "src/compiler/python_private_generator.h"
31
32 using grpc::protobuf::Descriptor;
33 using grpc::protobuf::FileDescriptor;
34 using grpc::protobuf::MethodDescriptor;
35 using grpc::protobuf::ServiceDescriptor;
36 using grpc::protobuf::compiler::GeneratorContext;
37 using grpc::protobuf::io::CodedOutputStream;
38 using grpc::protobuf::io::Printer;
39 using grpc::protobuf::io::StringOutputStream;
40 using grpc::protobuf::io::ZeroCopyOutputStream;
41 using grpc_generator::StringReplace;
42 using grpc_generator::StripProto;
43 using std::vector;
44
45 namespace grpc_python_generator {
46
47 namespace {
48
49 typedef vector<const Descriptor*> DescriptorVector;
50 typedef vector<std::string> StringVector;
51
StripModulePrefixes(const std::string & raw_module_name,const std::vector<std::string> & prefixes_to_filter)52 static std::string StripModulePrefixes(
53 const std::string& raw_module_name,
54 const std::vector<std::string>& prefixes_to_filter) {
55 for (const auto& prefix : prefixes_to_filter) {
56 if (raw_module_name.rfind(prefix, 0) == 0) {
57 return raw_module_name.substr(prefix.size(),
58 raw_module_name.size() - prefix.size());
59 }
60 }
61 return raw_module_name;
62 }
63
64 // TODO(https://github.com/google/protobuf/issues/888):
65 // Export `ModuleName` from protobuf's
66 // `src/google/protobuf/compiler/python/python_generator.cc` file.
ModuleName(const std::string & filename,const std::string & import_prefix,const std::vector<std::string> & prefixes_to_filter)67 std::string ModuleName(const std::string& filename,
68 const std::string& import_prefix,
69 const std::vector<std::string>& prefixes_to_filter) {
70 std::string basename = StripProto(filename);
71 basename = StringReplace(basename, "-", "_");
72 basename = StringReplace(basename, "/", ".");
73 return StripModulePrefixes(import_prefix + basename + "_pb2",
74 prefixes_to_filter);
75 }
76
77 // TODO(https://github.com/google/protobuf/issues/888):
78 // Export `ModuleAlias` from protobuf's
79 // `src/google/protobuf/compiler/python/python_generator.cc` file.
ModuleAlias(const std::string & filename,const std::string & import_prefix,const std::vector<std::string> & prefixes_to_filter)80 std::string ModuleAlias(const std::string& filename,
81 const std::string& import_prefix,
82 const std::vector<std::string>& prefixes_to_filter) {
83 std::string module_name =
84 ModuleName(filename, import_prefix, prefixes_to_filter);
85 // We can't have dots in the module name, so we replace each with _dot_.
86 // But that could lead to a collision between a.b and a_dot_b, so we also
87 // duplicate each underscore.
88 module_name = StringReplace(module_name, "_", "__");
89 module_name = StringReplace(module_name, ".", "_dot_");
90 return module_name;
91 }
92
GetModuleAndMessagePath(const Descriptor * type,std::string * out,std::string generator_file_name,bool generate_in_pb2_grpc,std::string & import_prefix,const std::vector<std::string> & prefixes_to_filter)93 bool GetModuleAndMessagePath(
94 const Descriptor* type, std::string* out, std::string generator_file_name,
95 bool generate_in_pb2_grpc, std::string& import_prefix,
96 const std::vector<std::string>& prefixes_to_filter) {
97 const Descriptor* path_elem_type = type;
98 DescriptorVector message_path;
99 do {
100 message_path.push_back(path_elem_type);
101 path_elem_type = path_elem_type->containing_type();
102 } while (path_elem_type); // implicit nullptr comparison; don't be explicit
103 std::string file_name = type->file()->name();
104 static const int proto_suffix_length = strlen(".proto");
105 if (!(file_name.size() > static_cast<size_t>(proto_suffix_length) &&
106 file_name.find_last_of(".proto") == file_name.size() - 1)) {
107 return false;
108 }
109
110 std::string module;
111 if (generator_file_name != file_name || generate_in_pb2_grpc) {
112 module = ModuleAlias(file_name, import_prefix, prefixes_to_filter) + ".";
113 } else {
114 module = "";
115 }
116 std::string message_type;
117 for (DescriptorVector::reverse_iterator path_iter = message_path.rbegin();
118 path_iter != message_path.rend(); ++path_iter) {
119 message_type += (*path_iter)->name() + ".";
120 }
121 // no pop_back prior to C++11
122 message_type.resize(message_type.size() - 1);
123 *out = module + message_type;
124 return true;
125 }
126
127 template <typename DescriptorType>
get_all_comments(const DescriptorType * descriptor)128 StringVector get_all_comments(const DescriptorType* descriptor) {
129 StringVector comments;
130 grpc_generator::GetComment(
131 descriptor, grpc_generator::COMMENTTYPE_LEADING_DETACHED, &comments);
132 grpc_generator::GetComment(descriptor, grpc_generator::COMMENTTYPE_LEADING,
133 &comments);
134 grpc_generator::GetComment(descriptor, grpc_generator::COMMENTTYPE_TRAILING,
135 &comments);
136 return comments;
137 }
138
Split(const std::string & s,char delim,std::vector<std::string> * append_to)139 inline void Split(const std::string& s, char delim,
140 std::vector<std::string>* append_to) {
141 if (s.empty()) {
142 // splitting an empty string logically produces a single-element list
143 append_to->emplace_back();
144 } else {
145 auto current = s.begin();
146 while (current < s.end()) {
147 const auto next = std::find(current, s.end(), delim);
148 append_to->emplace_back(current, next);
149 current = next;
150 if (current != s.end()) {
151 // it was the delimiter - need to be at the start of the next entry
152 ++current;
153 }
154 }
155 }
156 }
157
158 } // namespace
159
160 } // namespace grpc_python_generator
161
162 #endif // GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_HELPERS_H
163