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
32using grpc::protobuf::Descriptor;
33using grpc::protobuf::FileDescriptor;
34using grpc::protobuf::MethodDescriptor;
35using grpc::protobuf::ServiceDescriptor;
36using grpc::protobuf::compiler::GeneratorContext;
37using grpc::protobuf::io::CodedOutputStream;
38using grpc::protobuf::io::Printer;
39using grpc::protobuf::io::StringOutputStream;
40using grpc::protobuf::io::ZeroCopyOutputStream;
41using grpc_generator::StringReplace;
42using grpc_generator::StripProto;
43using std::vector;
44
45namespace grpc_python_generator {
46
47namespace {
48
49typedef vector<const Descriptor*> DescriptorVector;
50typedef vector<grpc::string> StringVector;
51
52static grpc::string StripModulePrefixes(
53 const grpc::string& raw_module_name,
54 const std::vector<grpc::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.
67grpc::string ModuleName(const grpc::string& filename,
68 const grpc::string& import_prefix,
69 const std::vector<grpc::string>& prefixes_to_filter) {
70 grpc::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.
80grpc::string ModuleAlias(const grpc::string& filename,
81 const grpc::string& import_prefix,
82 const std::vector<grpc::string>& prefixes_to_filter) {
83 grpc::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
93bool GetModuleAndMessagePath(
94 const Descriptor* type, grpc::string* out, grpc::string generator_file_name,
95 bool generate_in_pb2_grpc, grpc::string& import_prefix,
96 const std::vector<grpc::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 grpc::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 grpc::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 grpc::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
127template <typename DescriptorType>
128StringVector 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
139inline void Split(const grpc::string& s, char delim,
140 std::vector<grpc::string>* append_to) {
141 auto current = s.begin();
142 while (current <= s.end()) {
143 auto next = std::find(current, s.end(), delim);
144 append_to->emplace_back(current, next);
145 current = next + 1;
146 }
147}
148
149} // namespace
150
151} // namespace grpc_python_generator
152
153#endif // GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_HELPERS_H
154