OLD | NEW |
(Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 |
| 5 """ |
| 6 Provides simple state-less wrappers of the proto types used by plugins. |
| 7 |
| 8 See https://developers.google.com/protocol-buffers/docs/reference/cpp/google.pro
tobuf.descriptor.pb |
| 9 and https://developers.google.com/protocol-buffers/docs/reference/cpp/google.pro
tobuf.compiler.plugin.pb |
| 10 """ |
| 11 |
| 12 import os |
| 13 import sys |
| 14 |
| 15 from google.protobuf.descriptor_pb2 import FieldDescriptorProto |
| 16 |
| 17 import plugin |
| 18 import types |
| 19 |
| 20 sys.path.insert( |
| 21 1, os.path.join(os.path.dirname(__file__), '..', '..', |
| 22 'dist', 'python')) |
| 23 import plugin_pb2 |
| 24 |
| 25 |
| 26 class PluginRequest(object): |
| 27 def __init__(self, proto): |
| 28 self.proto = proto |
| 29 |
| 30 def GetArgs(self): |
| 31 return dict((v.split('=') for v in self.proto.parameter.split(','))) |
| 32 |
| 33 def GetAllFiles(self): |
| 34 all = map(ProtoFile, self.proto.proto_file) |
| 35 for f in all: |
| 36 assert f.Filename() in self.proto.file_to_generate |
| 37 return all |
| 38 |
| 39 |
| 40 def PluginRequestFromString(data): |
| 41 request_proto = plugin_pb2.CodeGeneratorRequest() |
| 42 request_proto.ParseFromString(data) |
| 43 return PluginRequest(request_proto) |
| 44 |
| 45 |
| 46 class PluginResponse(object): |
| 47 def __init__(self): |
| 48 self.proto = plugin_pb2.CodeGeneratorResponse() |
| 49 |
| 50 def AddFileWithContent(self, filename, content): |
| 51 file_proto = self.proto.file.add() |
| 52 file_proto.name = filename |
| 53 file_proto.content = content |
| 54 |
| 55 def AddError(self, err): |
| 56 self.proto.error += err + '\n' |
| 57 |
| 58 def WriteToStdout(self): |
| 59 sys.stdout.write(self.proto.SerializeToString()) |
| 60 sys.stdout.flush() |
| 61 |
| 62 |
| 63 class ProtoFile(object): |
| 64 def __init__(self, proto): |
| 65 self.proto = proto |
| 66 self.qualified_types = types.QualifiedTypes( |
| 67 self.ProtoPackage(), |
| 68 self.JavaPackage() + '.' + self.JavaOuterClass(), |
| 69 self.CppBaseNamespace(), |
| 70 self.CppConverterNamespace() |
| 71 ) |
| 72 |
| 73 def Filename(self): |
| 74 return self.proto.name |
| 75 |
| 76 def CheckSupported(self): |
| 77 if self.proto.service: |
| 78 return 'Services are not supported' |
| 79 |
| 80 if self.proto.extension: |
| 81 return 'Extensions are not supported' |
| 82 |
| 83 for child in self.GetMessages() + self.GetEnums(): |
| 84 err = child.CheckSupported() |
| 85 if err: |
| 86 return err |
| 87 |
| 88 def ProtoPackage(self): |
| 89 return self.proto.package if self.proto.HasField('package') else '' |
| 90 |
| 91 def ProtoNamespaces(self): |
| 92 return self.ProtoPackage().split('.') |
| 93 |
| 94 def CppBaseNamespace(self): |
| 95 return '::'.join(self.ProtoNamespaces()) |
| 96 |
| 97 def CppBaseHeader(self): |
| 98 assert self.proto.name.endswith('.proto') |
| 99 return self.proto.name[:-5] + 'pb.h' |
| 100 |
| 101 def CppConverterNamespace(self): |
| 102 return self.CppBaseNamespace() + '::json' |
| 103 |
| 104 def JavaPackage(self): |
| 105 if self.proto.options.HasField('java_package'): |
| 106 return self.proto.options.java_package |
| 107 else: |
| 108 return self.ProtoPackage() |
| 109 |
| 110 def GetMessages(self): |
| 111 return [ProtoMessage(n, self.qualified_types) |
| 112 for n in self.proto.message_type] |
| 113 |
| 114 def GetEnums(self): |
| 115 return [ProtoEnum(n, self.qualified_types) for n in self.proto.enum_type] |
| 116 |
| 117 def GetDependencies(self): |
| 118 return map(plugin.GetProtoFileForFilename, self.proto.dependency) |
| 119 |
| 120 def JavaFilename(self): |
| 121 return '/'.join(self.JavaQualifiedOuterClass().split('.')) + '.java' |
| 122 |
| 123 def JavaOuterClass(self): |
| 124 if self.proto.options.HasField('java_outer_classname'): |
| 125 return self.proto.options.java_outer_classname |
| 126 basename, _ = os.path.splitext(os.path.basename(self.proto.name)) |
| 127 return plugin.TitleCase(basename) |
| 128 |
| 129 def JavaQualifiedOuterClass(self): |
| 130 return self.qualified_types.java |
| 131 |
| 132 def CppConverterFilename(self): |
| 133 assert self.proto.name.endswith('.proto') |
| 134 return self.proto.name[:-6] + '_json_converter.h' |
| 135 |
| 136 |
| 137 class ProtoMessage(object): |
| 138 def __init__(self, proto, parent_typenames): |
| 139 self.proto = proto |
| 140 self.qualified_types = types.QualifiedTypesForChild( |
| 141 proto.name, parent_typenames) |
| 142 |
| 143 def CheckSupported(self): |
| 144 if self.proto.extension_range: |
| 145 return 'Extensions are not supported: ' + self.proto.extension_range |
| 146 |
| 147 for child in self.GetFields() + self.GetMessages() + self.GetEnums(): |
| 148 err = child.CheckSupported() |
| 149 if err: |
| 150 return err |
| 151 |
| 152 def QualifiedTypes(self): |
| 153 return self.qualified_types |
| 154 |
| 155 def JavaClassName(self): |
| 156 return plugin.TitleCase(self.proto.name) |
| 157 |
| 158 def CppConverterClassName(self): |
| 159 return plugin.TitleCase(self.proto.name) |
| 160 |
| 161 def GetFields(self): |
| 162 return map(ProtoField, self.proto.field) |
| 163 |
| 164 def GetMessages(self): |
| 165 return [ProtoMessage(n, self.qualified_types) |
| 166 for n in self.proto.nested_type] |
| 167 |
| 168 def GetEnums(self): |
| 169 return [ProtoEnum(n, self.qualified_types) for n in self.proto.enum_type] |
| 170 |
| 171 |
| 172 class ProtoField(object): |
| 173 def __init__(self, field_proto): |
| 174 self.proto = field_proto |
| 175 self.name = field_proto.name |
| 176 |
| 177 if self.IsClassType() and not self.proto.HasField('type_name'): |
| 178 raise Error('expected type_name') |
| 179 |
| 180 def Extendee(self): |
| 181 return self.proto.extendee if self.proto.HasField('extendee') else None |
| 182 |
| 183 def IsOptional(self): |
| 184 return self.proto.label == FieldDescriptorProto.LABEL_OPTIONAL |
| 185 |
| 186 def IsRepeated(self): |
| 187 return self.proto.label == FieldDescriptorProto.LABEL_REPEATED |
| 188 |
| 189 def IsRequired(self): |
| 190 return self.proto.label == FieldDescriptorProto.LABEL_REQUIRED |
| 191 |
| 192 def IsClassType(self): |
| 193 return self.proto.type == FieldDescriptorProto.TYPE_MESSAGE |
| 194 |
| 195 def IsEnumType(self): |
| 196 return self.proto.type == FieldDescriptorProto.TYPE_ENUM |
| 197 |
| 198 def JavaType(self): |
| 199 if self.IsClassType(): |
| 200 return types.ResolveJavaClassType(self.proto.type_name) |
| 201 elif self.IsEnumType(): |
| 202 return 'int' |
| 203 else: |
| 204 return types.GetJavaPrimitiveType(self.proto.type) |
| 205 |
| 206 def JavaListType(self): |
| 207 return types.GetJavaObjectType(self.JavaType()) |
| 208 |
| 209 def JavascriptIndex(self): |
| 210 return self.proto.number |
| 211 |
| 212 def JavaName(self): |
| 213 return plugin.TitleCase(self.name) |
| 214 |
| 215 def CppConverterType(self): |
| 216 return types.ResolveCppConverterType(self.proto.type_name) |
| 217 |
| 218 def CppPrimitiveType(self): |
| 219 assert not self.IsClassType() |
| 220 return types.GetCppPrimitiveType(self.proto.type) |
| 221 |
| 222 def CppValueType(self): |
| 223 return types.GetCppValueType(self.CppPrimitiveType()) |
| 224 |
| 225 def CheckSupported(self): |
| 226 if self.Extendee(): |
| 227 return 'Unsupported field extension: ' + self.DebugString() |
| 228 |
| 229 if self.JavaType() is None: |
| 230 return 'Unsupported type for field: ' + self.DebugString() |
| 231 |
| 232 if self.IsRequired(): |
| 233 return 'Required fields not supported: ' + self.DebugString() |
| 234 |
| 235 if self.proto.HasField('default_value'): |
| 236 return 'Default values are not supported: ' + self.DebugString() |
| 237 |
| 238 return None |
| 239 |
| 240 def DebugString(self): |
| 241 return '{name}, {type}, {extendee}'.format( |
| 242 name=self.name, |
| 243 type=self.proto.type, |
| 244 extendee=self.Extendee()) |
| 245 |
| 246 |
| 247 class ProtoEnum(object): |
| 248 def __init__(self, proto, parent_typenames): |
| 249 self.proto = proto |
| 250 self.qualified_types = types.QualifiedTypesForChild( |
| 251 proto.name, parent_typenames) |
| 252 |
| 253 def CheckSupported(self): |
| 254 if self.proto.HasField('options'): |
| 255 return 'Enum options are not supported: ' + self.DebugString() |
| 256 for val in self.Values(): |
| 257 err = val.CheckSupported() |
| 258 if err: |
| 259 return err + ' ' + self.DebugString() |
| 260 |
| 261 def QualifiedTypes(self): |
| 262 return self.qualified_types |
| 263 |
| 264 def JavaName(self): |
| 265 return plugin.TitleCase(self.proto.name) |
| 266 |
| 267 def Values(self): |
| 268 return map(ProtoEnumValue, self.proto.value) |
| 269 |
| 270 |
| 271 class ProtoEnumValue(object): |
| 272 def __init__(self, enum_value_proto): |
| 273 self.proto = enum_value_proto |
| 274 |
| 275 def GetName(self): |
| 276 return self.proto.name |
| 277 |
| 278 def GetValue(self): |
| 279 return self.proto.number |
| 280 |
| 281 def CheckSupported(self): |
| 282 if self.proto.HasField('options'): |
| 283 return 'Enum value options are not supported: {} {}'.format( |
| 284 self.proto.name, self.proto.value) |
OLD | NEW |