github.com/gogo/protobuf@v1.3.2/plugin/description/description.go (about) 1 // Protocol Buffers for Go with Gadgets 2 // 3 // Copyright (c) 2013, The GoGo Authors. All rights reserved. 4 // http://github.com/gogo/protobuf 5 // 6 // Redistribution and use in source and binary forms, with or without 7 // modification, are permitted provided that the following conditions are 8 // met: 9 // 10 // * Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // * Redistributions in binary form must reproduce the above 13 // copyright notice, this list of conditions and the following disclaimer 14 // in the documentation and/or other materials provided with the 15 // distribution. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 /* 30 The description (experimental) plugin generates a Description method for each message. 31 The Description method returns a populated google_protobuf.FileDescriptorSet struct. 32 This contains the description of the files used to generate this message. 33 34 It is enabled by the following extensions: 35 36 - description 37 - description_all 38 39 The description plugin also generates a test given it is enabled using one of the following extensions: 40 41 - testgen 42 - testgen_all 43 44 Let us look at: 45 46 github.com/gogo/protobuf/test/example/example.proto 47 48 Btw all the output can be seen at: 49 50 github.com/gogo/protobuf/test/example/* 51 52 The following message: 53 54 message B { 55 option (gogoproto.description) = true; 56 optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true]; 57 repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false]; 58 } 59 60 given to the description plugin, will generate the following code: 61 62 func (this *B) Description() (desc *google_protobuf.FileDescriptorSet) { 63 return ExampleDescription() 64 } 65 66 and the following test code: 67 68 func TestDescription(t *testing9.T) { 69 ExampleDescription() 70 } 71 72 The hope is to use this struct in some way instead of reflect. 73 This package is subject to change, since a use has not been figured out yet. 74 75 */ 76 package description 77 78 import ( 79 "bytes" 80 "compress/gzip" 81 "fmt" 82 "github.com/gogo/protobuf/gogoproto" 83 "github.com/gogo/protobuf/proto" 84 descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor" 85 "github.com/gogo/protobuf/protoc-gen-gogo/generator" 86 ) 87 88 type plugin struct { 89 *generator.Generator 90 generator.PluginImports 91 } 92 93 func NewPlugin() *plugin { 94 return &plugin{} 95 } 96 97 func (p *plugin) Name() string { 98 return "description" 99 } 100 101 func (p *plugin) Init(g *generator.Generator) { 102 p.Generator = g 103 } 104 105 func (p *plugin) Generate(file *generator.FileDescriptor) { 106 used := false 107 localName := generator.FileName(file) 108 109 p.PluginImports = generator.NewPluginImports(p.Generator) 110 descriptorPkg := p.NewImport("github.com/gogo/protobuf/protoc-gen-gogo/descriptor") 111 protoPkg := p.NewImport("github.com/gogo/protobuf/proto") 112 gzipPkg := p.NewImport("compress/gzip") 113 bytesPkg := p.NewImport("bytes") 114 ioutilPkg := p.NewImport("io/ioutil") 115 116 for _, message := range file.Messages() { 117 if !gogoproto.HasDescription(file.FileDescriptorProto, message.DescriptorProto) { 118 continue 119 } 120 if message.DescriptorProto.GetOptions().GetMapEntry() { 121 continue 122 } 123 used = true 124 ccTypeName := generator.CamelCaseSlice(message.TypeName()) 125 p.P(`func (this *`, ccTypeName, `) Description() (desc *`, descriptorPkg.Use(), `.FileDescriptorSet) {`) 126 p.In() 127 p.P(`return `, localName, `Description()`) 128 p.Out() 129 p.P(`}`) 130 } 131 132 if used { 133 134 p.P(`func `, localName, `Description() (desc *`, descriptorPkg.Use(), `.FileDescriptorSet) {`) 135 p.In() 136 //Don't generate SourceCodeInfo, since it will create too much code. 137 138 ss := make([]*descriptor.SourceCodeInfo, 0) 139 for _, f := range p.Generator.AllFiles().GetFile() { 140 ss = append(ss, f.SourceCodeInfo) 141 f.SourceCodeInfo = nil 142 } 143 b, err := proto.Marshal(p.Generator.AllFiles()) 144 if err != nil { 145 panic(err) 146 } 147 for i, f := range p.Generator.AllFiles().GetFile() { 148 f.SourceCodeInfo = ss[i] 149 } 150 p.P(`d := &`, descriptorPkg.Use(), `.FileDescriptorSet{}`) 151 var buf bytes.Buffer 152 w, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression) 153 w.Write(b) 154 w.Close() 155 b = buf.Bytes() 156 p.P("var gzipped = []byte{") 157 p.In() 158 p.P("// ", len(b), " bytes of a gzipped FileDescriptorSet") 159 for len(b) > 0 { 160 n := 16 161 if n > len(b) { 162 n = len(b) 163 } 164 165 s := "" 166 for _, c := range b[:n] { 167 s += fmt.Sprintf("0x%02x,", c) 168 } 169 p.P(s) 170 171 b = b[n:] 172 } 173 p.Out() 174 p.P("}") 175 p.P(`r := `, bytesPkg.Use(), `.NewReader(gzipped)`) 176 p.P(`gzipr, err := `, gzipPkg.Use(), `.NewReader(r)`) 177 p.P(`if err != nil {`) 178 p.In() 179 p.P(`panic(err)`) 180 p.Out() 181 p.P(`}`) 182 p.P(`ungzipped, err := `, ioutilPkg.Use(), `.ReadAll(gzipr)`) 183 p.P(`if err != nil {`) 184 p.In() 185 p.P(`panic(err)`) 186 p.Out() 187 p.P(`}`) 188 p.P(`if err := `, protoPkg.Use(), `.Unmarshal(ungzipped, d); err != nil {`) 189 p.In() 190 p.P(`panic(err)`) 191 p.Out() 192 p.P(`}`) 193 p.P(`return d`) 194 p.Out() 195 p.P(`}`) 196 } 197 } 198 199 func init() { 200 generator.RegisterPlugin(NewPlugin()) 201 }