1# Copyright 2020 The gRPC authors. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15from libc cimport stdlib 16from libcpp.vector cimport vector 17from libcpp.utility cimport pair 18from libcpp.string cimport string 19 20from cython.operator cimport dereference 21 22import warnings 23 24cdef extern from "grpc_tools/main.h" namespace "grpc_tools": 25 cppclass cProtocError "::grpc_tools::ProtocError": 26 string filename 27 int line 28 int column 29 string message 30 31 cppclass cProtocWarning "::grpc_tools::ProtocWarning": 32 string filename 33 int line 34 int column 35 string message 36 37 int protoc_main(int argc, char *argv[]) 38 int protoc_get_protos(char* protobuf_path, 39 vector[string]* include_path, 40 vector[pair[string, string]]* files_out, 41 vector[cProtocError]* errors, 42 vector[cProtocWarning]* wrnings) nogil except + 43 int protoc_get_services(char* protobuf_path, 44 vector[string]* include_path, 45 vector[pair[string, string]]* files_out, 46 vector[cProtocError]* errors, 47 vector[cProtocWarning]* wrnings) nogil except + 48 49def run_main(list args not None): 50 cdef char **argv = <char **>stdlib.malloc(len(args)*sizeof(char *)) 51 for i in range(len(args)): 52 argv[i] = args[i] 53 return protoc_main(len(args), argv) 54 55class ProtocError(Exception): 56 def __init__(self, filename, line, column, message): 57 self.filename = filename 58 self.line = line 59 self.column = column 60 self.message = message 61 62 def __repr__(self): 63 return "ProtocError(filename=\"{}\", line={}, column={}, message=\"{}\")".format( 64 self.filename, self.line, self.column, self.message) 65 66 def __str__(self): 67 return "{}:{}:{} error: {}".format(self.filename.decode("ascii"), 68 self.line, self.column, self.message.decode("ascii")) 69 70class ProtocWarning(Warning): 71 def __init__(self, filename, line, column, message): 72 self.filename = filename 73 self.line = line 74 self.column = column 75 self.message = message 76 77 def __repr__(self): 78 return "ProtocWarning(filename=\"{}\", line={}, column={}, message=\"{}\")".format( 79 self.filename, self.line, self.column, self.message) 80 81 __str__ = __repr__ 82 83 84class ProtocErrors(Exception): 85 def __init__(self, errors): 86 self._errors = errors 87 88 def errors(self): 89 return self._errors 90 91 def __repr__(self): 92 return "ProtocErrors[{}]".join(repr(err) for err in self._errors) 93 94 def __str__(self): 95 return "\n".join(str(err) for err in self._errors) 96 97cdef _c_protoc_error_to_protoc_error(cProtocError c_protoc_error): 98 return ProtocError(c_protoc_error.filename, c_protoc_error.line, 99 c_protoc_error.column, c_protoc_error.message) 100 101cdef _c_protoc_warning_to_protoc_warning(cProtocWarning c_protoc_warning): 102 return ProtocWarning(c_protoc_warning.filename, c_protoc_warning.line, 103 c_protoc_warning.column, c_protoc_warning.message) 104 105cdef _handle_errors(int rc, vector[cProtocError]* errors, vector[cProtocWarning]* wrnings, bytes protobuf_path): 106 for warning in dereference(wrnings): 107 warnings.warn(_c_protoc_warning_to_protoc_warning(warning)) 108 if rc != 0: 109 if dereference(errors).size() != 0: 110 py_errors = [_c_protoc_error_to_protoc_error(c_error) 111 for c_error in dereference(errors)] 112 raise ProtocErrors(py_errors) 113 raise Exception("An unknown error occurred while compiling {}".format(protobuf_path)) 114 115def get_protos(bytes protobuf_path, list include_paths): 116 cdef vector[string] c_include_paths = include_paths 117 cdef vector[pair[string, string]] files 118 cdef vector[cProtocError] errors 119 # NOTE: Abbreviated name used to avoid shadowing of the module name. 120 cdef vector[cProtocWarning] wrnings 121 rc = protoc_get_protos(protobuf_path, &c_include_paths, &files, &errors, &wrnings) 122 _handle_errors(rc, &errors, &wrnings, protobuf_path) 123 return files 124 125def get_services(bytes protobuf_path, list include_paths): 126 cdef vector[string] c_include_paths = include_paths 127 cdef vector[pair[string, string]] files 128 cdef vector[cProtocError] errors 129 # NOTE: Abbreviated name used to avoid shadowing of the module name. 130 cdef vector[cProtocWarning] wrnings 131 rc = protoc_get_services(protobuf_path, &c_include_paths, &files, &errors, &wrnings) 132 _handle_errors(rc, &errors, &wrnings, protobuf_path) 133 return files 134 135