| 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 package main |
| 6 |
| 7 import ( |
| 8 "fmt" |
| 9 "io" |
| 10 "strings" |
| 11 |
| 12 "github.com/luci/luci-go/common/indented" |
| 13 "github.com/luci/luci-go/common/proto/google/descriptor" |
| 14 ) |
| 15 |
| 16 // printer prints a proto3 definition from a description. |
| 17 // Does not support options. |
| 18 type printer struct { |
| 19 // File is the file containing the desriptors being printed. |
| 20 // Used to relativize names and print comments. |
| 21 File *descriptor.FileDescriptorProto |
| 22 Out indented.Writer |
| 23 |
| 24 // Err is not nil if writing to Out failed. |
| 25 Err error |
| 26 } |
| 27 |
| 28 func newPrinter(out io.Writer) *printer { |
| 29 return &printer{Out: indented.Writer{Writer: out}} |
| 30 } |
| 31 |
| 32 // Printf prints to p.Out unless there was an error. |
| 33 func (p *printer) Printf(format string, a ...interface{}) { |
| 34 if p.Err == nil { |
| 35 _, p.Err = fmt.Fprintf(&p.Out, format, a...) |
| 36 } |
| 37 } |
| 38 |
| 39 // Package prints package declaration. |
| 40 func (p *printer) Package(name string) { |
| 41 p.Printf("package %s;\n", name) |
| 42 } |
| 43 |
| 44 // open prints a string, followed by " {\n" and increases indentation level. |
| 45 // Returns a function that decreases indentation level and closes the brace. |
| 46 // Usage: defer open("package x")() |
| 47 func (p *printer) open(format string, a ...interface{}) func() { |
| 48 p.Printf(format, a...) |
| 49 p.Printf(" {\n") |
| 50 p.Out.Level++ |
| 51 return func() { |
| 52 p.Out.Level-- |
| 53 p.Printf("}\n") |
| 54 } |
| 55 } |
| 56 |
| 57 // MaybeLeadingComments prints leading comments of the protobuf entity |
| 58 // at path, if found. |
| 59 // |
| 60 // For path, see comment in SourceCodeInfo.Location message in |
| 61 // common/proto/google/descriptor/descriptor.proto. |
| 62 func (p *printer) MaybeLeadingComments(path []int) { |
| 63 if p.File == nil || p.File.SourceCodeInfo == nil || len(path) == 0 { |
| 64 return |
| 65 } |
| 66 |
| 67 loc := p.File.SourceCodeInfo.FindLocation(path) |
| 68 if loc == nil { |
| 69 return |
| 70 } |
| 71 |
| 72 comments := loc.GetLeadingComments() |
| 73 // print comments, but insert "//" before each newline. |
| 74 for len(comments) > 0 { |
| 75 var toPrint string |
| 76 if lineEnd := strings.Index(comments, "\n"); lineEnd >= 0 { |
| 77 toPrint = comments[:lineEnd+1] // includes newline |
| 78 comments = comments[lineEnd+1:] |
| 79 } else { |
| 80 // actually this does not happen, because comments alway
s end with |
| 81 // newline, but just in case. |
| 82 toPrint = comments + "\n" |
| 83 comments = "" |
| 84 } |
| 85 p.Printf("//%s", toPrint) |
| 86 } |
| 87 } |
| 88 |
| 89 // shorten removes leading "." and trims package name if it matches p.File. |
| 90 func (p *printer) shorten(name string) string { |
| 91 name = strings.TrimPrefix(name, ".") |
| 92 if p.File != nil && p.File.GetPackage() != "" { |
| 93 name = strings.TrimPrefix(name, p.File.GetPackage()+".") |
| 94 } |
| 95 return name |
| 96 } |
| 97 |
| 98 // Service prints a service definition. |
| 99 // If methodIndex != -1, only one method is printed. |
| 100 // If serviceIndex != -1, leading comments are printed if found. |
| 101 func (p *printer) Service(service *descriptor.ServiceDescriptorProto, serviceInd
ex, methodIndex int) { |
| 102 var path []int |
| 103 if serviceIndex != -1 { |
| 104 path = []int{descriptor.NumberFileDescriptorProto_Service, servi
ceIndex} |
| 105 p.MaybeLeadingComments(path) |
| 106 } |
| 107 defer p.open("service %s", service.GetName())() |
| 108 |
| 109 printMethod := func(i int) { |
| 110 var methodPath []int |
| 111 if path != nil { |
| 112 methodPath = append(path, descriptor.NumberServiceDescri
ptorProto_Method, i) |
| 113 } |
| 114 p.Method(service.Method[i], methodPath) |
| 115 } |
| 116 |
| 117 if methodIndex < 0 { |
| 118 for i := range service.Method { |
| 119 printMethod(i) |
| 120 } |
| 121 } else { |
| 122 printMethod(methodIndex) |
| 123 if len(service.Method) > 1 { |
| 124 p.Printf("// other methods were omitted.\n") |
| 125 } |
| 126 } |
| 127 } |
| 128 |
| 129 // Method prints a service method definition. |
| 130 // |
| 131 // If path is specified, leading comments are printed if found. |
| 132 // See also comment in SourceCodeInfo.Location message in |
| 133 // common/proto/google/descriptor/descriptor.proto. |
| 134 func (p *printer) Method(method *descriptor.MethodDescriptorProto, path []int) { |
| 135 p.MaybeLeadingComments(path) |
| 136 p.Printf( |
| 137 "rpc %s(%s) returns (%s) {};\n", |
| 138 method.GetName(), |
| 139 p.shorten(method.GetInputType()), |
| 140 p.shorten(method.GetOutputType()), |
| 141 ) |
| 142 } |
| 143 |
| 144 var fieldTypeName = map[descriptor.FieldDescriptorProto_Type]string{ |
| 145 descriptor.FieldDescriptorProto_TYPE_DOUBLE: "double", |
| 146 descriptor.FieldDescriptorProto_TYPE_FLOAT: "float", |
| 147 descriptor.FieldDescriptorProto_TYPE_INT64: "int64", |
| 148 descriptor.FieldDescriptorProto_TYPE_UINT64: "uint64", |
| 149 descriptor.FieldDescriptorProto_TYPE_INT32: "int32", |
| 150 descriptor.FieldDescriptorProto_TYPE_FIXED64: "fixed64", |
| 151 descriptor.FieldDescriptorProto_TYPE_FIXED32: "fixed32", |
| 152 descriptor.FieldDescriptorProto_TYPE_BOOL: "bool", |
| 153 descriptor.FieldDescriptorProto_TYPE_STRING: "string", |
| 154 descriptor.FieldDescriptorProto_TYPE_BYTES: "bytes", |
| 155 descriptor.FieldDescriptorProto_TYPE_UINT32: "uint32", |
| 156 descriptor.FieldDescriptorProto_TYPE_SFIXED32: "sfixed32", |
| 157 descriptor.FieldDescriptorProto_TYPE_SFIXED64: "sfixed64", |
| 158 descriptor.FieldDescriptorProto_TYPE_SINT32: "sint32", |
| 159 descriptor.FieldDescriptorProto_TYPE_SINT64: "sint64", |
| 160 } |
| 161 |
| 162 // Field prints a field definition. |
| 163 // |
| 164 // If path is specified, leading comments are printed if found. |
| 165 // See also comment in SourceCodeInfo.Location message in |
| 166 // common/proto/google/descriptor/descriptor.proto. |
| 167 func (p *printer) Field(field *descriptor.FieldDescriptorProto, path []int) { |
| 168 p.MaybeLeadingComments(path) |
| 169 if field.GetLabel() == descriptor.FieldDescriptorProto_LABEL_REPEATED { |
| 170 p.Printf("repeated ") |
| 171 } |
| 172 |
| 173 typeName := fieldTypeName[field.GetType()] |
| 174 if typeName == "" { |
| 175 typeName = p.shorten(field.GetTypeName()) |
| 176 } |
| 177 if typeName == "" { |
| 178 typeName = "<unsupported type>" |
| 179 } |
| 180 p.Printf("%s %s = %d;\n", typeName, field.GetName(), field.GetNumber()) |
| 181 } |
| 182 |
| 183 // Message prints a message definition. |
| 184 // |
| 185 // If path is specified, leading comments are printed if found. |
| 186 // See also comment in SourceCodeInfo.Location message in |
| 187 // common/proto/google/descriptor/descriptor.proto. |
| 188 func (p *printer) Message(msg *descriptor.DescriptorProto, path []int) { |
| 189 p.MaybeLeadingComments(path) |
| 190 defer p.open("message %s", msg.GetName())() |
| 191 |
| 192 for i := range msg.GetOneofDecl() { |
| 193 p.OneOf(msg, i, path) |
| 194 } |
| 195 |
| 196 for i, f := range msg.Field { |
| 197 if f.OneofIndex == nil { |
| 198 var fieldPath []int |
| 199 if len(path) > 0 { |
| 200 fieldPath = append(path, descriptor.NumberDescri
ptorProto_Field, i) |
| 201 } |
| 202 p.Field(msg.Field[i], fieldPath) |
| 203 } |
| 204 } |
| 205 } |
| 206 |
| 207 // OneOf prints a oneof definition. |
| 208 // |
| 209 // If path is specified, leading comments are printed if found. |
| 210 // See also comment in SourceCodeInfo.Location message in |
| 211 // common/proto/google/descriptor/descriptor.proto. |
| 212 func (p *printer) OneOf(msg *descriptor.DescriptorProto, oneOfIndex int, msgPath
[]int) { |
| 213 of := msg.GetOneofDecl()[oneOfIndex] |
| 214 if len(msgPath) > 0 { |
| 215 p.MaybeLeadingComments(append(msgPath, descriptor.NumberDescript
orProto_OneOf, oneOfIndex)) |
| 216 } |
| 217 defer p.open("oneof %s", of.GetName())() |
| 218 |
| 219 for i, f := range msg.Field { |
| 220 if f.OneofIndex != nil && int(f.GetOneofIndex()) == oneOfIndex { |
| 221 var fieldPath []int |
| 222 if len(msgPath) > 0 { |
| 223 fieldPath = append(msgPath, descriptor.NumberDes
criptorProto_Field, i) |
| 224 } |
| 225 p.Field(msg.Field[i], fieldPath) |
| 226 } |
| 227 } |
| 228 } |
| 229 |
| 230 // Enum prints an enum definition. |
| 231 // |
| 232 // If path is specified, leading comments are printed if found. |
| 233 // See also comment in SourceCodeInfo.Location message in |
| 234 // common/proto/google/descriptor/descriptor.proto. |
| 235 func (p *printer) Enum(enum *descriptor.EnumDescriptorProto, path []int) { |
| 236 p.MaybeLeadingComments(path) |
| 237 defer p.open("enum %s", enum.GetName())() |
| 238 |
| 239 for i, v := range enum.Value { |
| 240 var valuePath []int |
| 241 if len(path) > 0 { |
| 242 valuePath = append(path, descriptor.NumberEnumDescriptor
Proto_Value, i) |
| 243 } |
| 244 p.EnumValue(v, valuePath) |
| 245 } |
| 246 } |
| 247 |
| 248 // EnumValue prints an enum value definition. |
| 249 // |
| 250 // If path is specified, leading comments are printed if found. |
| 251 // See also comment in SourceCodeInfo.Location message in |
| 252 // common/proto/google/descriptor/descriptor.proto. |
| 253 func (p *printer) EnumValue(v *descriptor.EnumValueDescriptorProto, path []int)
{ |
| 254 p.MaybeLeadingComments(path) |
| 255 p.Printf("%s = %d;\n", v.GetName(), v.GetNumber()) |
| 256 } |
| OLD | NEW |