123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201 |
- // Protocol Buffers for Go with Gadgets
- //
- // Copyright (c) 2013, The GoGo Authors. All rights reserved.
- // http://github.com/gogo/protobuf
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are
- // met:
- //
- // * Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following disclaimer
- // in the documentation and/or other materials provided with the
- // distribution.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- /*
- The description (experimental) plugin generates a Description method for each message.
- The Description method returns a populated google_protobuf.FileDescriptorSet struct.
- This contains the description of the files used to generate this message.
- It is enabled by the following extensions:
- - description
- - description_all
- The description plugin also generates a test given it is enabled using one of the following extensions:
- - testgen
- - testgen_all
- Let us look at:
- github.com/gogo/protobuf/test/example/example.proto
- Btw all the output can be seen at:
- github.com/gogo/protobuf/test/example/*
- The following message:
- message B {
- option (gogoproto.description) = true;
- optional A A = 1 [(gogoproto.nullable) = false, (gogoproto.embed) = true];
- repeated bytes G = 2 [(gogoproto.customtype) = "github.com/gogo/protobuf/test/custom.Uint128", (gogoproto.nullable) = false];
- }
- given to the description plugin, will generate the following code:
- func (this *B) Description() (desc *google_protobuf.FileDescriptorSet) {
- return ExampleDescription()
- }
- and the following test code:
- func TestDescription(t *testing9.T) {
- ExampleDescription()
- }
- The hope is to use this struct in some way instead of reflect.
- This package is subject to change, since a use has not been figured out yet.
- */
- package description
- import (
- "bytes"
- "compress/gzip"
- "fmt"
- "github.com/gogo/protobuf/gogoproto"
- "github.com/gogo/protobuf/proto"
- descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
- "github.com/gogo/protobuf/protoc-gen-gogo/generator"
- )
- type plugin struct {
- *generator.Generator
- generator.PluginImports
- }
- func NewPlugin() *plugin {
- return &plugin{}
- }
- func (p *plugin) Name() string {
- return "description"
- }
- func (p *plugin) Init(g *generator.Generator) {
- p.Generator = g
- }
- func (p *plugin) Generate(file *generator.FileDescriptor) {
- used := false
- localName := generator.FileName(file)
- p.PluginImports = generator.NewPluginImports(p.Generator)
- descriptorPkg := p.NewImport("github.com/gogo/protobuf/protoc-gen-gogo/descriptor")
- protoPkg := p.NewImport("github.com/gogo/protobuf/proto")
- gzipPkg := p.NewImport("compress/gzip")
- bytesPkg := p.NewImport("bytes")
- ioutilPkg := p.NewImport("io/ioutil")
- for _, message := range file.Messages() {
- if !gogoproto.HasDescription(file.FileDescriptorProto, message.DescriptorProto) {
- continue
- }
- if message.DescriptorProto.GetOptions().GetMapEntry() {
- continue
- }
- used = true
- ccTypeName := generator.CamelCaseSlice(message.TypeName())
- p.P(`func (this *`, ccTypeName, `) Description() (desc *`, descriptorPkg.Use(), `.FileDescriptorSet) {`)
- p.In()
- p.P(`return `, localName, `Description()`)
- p.Out()
- p.P(`}`)
- }
- if used {
- p.P(`func `, localName, `Description() (desc *`, descriptorPkg.Use(), `.FileDescriptorSet) {`)
- p.In()
- //Don't generate SourceCodeInfo, since it will create too much code.
- ss := make([]*descriptor.SourceCodeInfo, 0)
- for _, f := range p.Generator.AllFiles().GetFile() {
- ss = append(ss, f.SourceCodeInfo)
- f.SourceCodeInfo = nil
- }
- b, err := proto.Marshal(p.Generator.AllFiles())
- if err != nil {
- panic(err)
- }
- for i, f := range p.Generator.AllFiles().GetFile() {
- f.SourceCodeInfo = ss[i]
- }
- p.P(`d := &`, descriptorPkg.Use(), `.FileDescriptorSet{}`)
- var buf bytes.Buffer
- w, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression)
- w.Write(b)
- w.Close()
- b = buf.Bytes()
- p.P("var gzipped = []byte{")
- p.In()
- p.P("// ", len(b), " bytes of a gzipped FileDescriptorSet")
- for len(b) > 0 {
- n := 16
- if n > len(b) {
- n = len(b)
- }
- s := ""
- for _, c := range b[:n] {
- s += fmt.Sprintf("0x%02x,", c)
- }
- p.P(s)
- b = b[n:]
- }
- p.Out()
- p.P("}")
- p.P(`r := `, bytesPkg.Use(), `.NewReader(gzipped)`)
- p.P(`gzipr, err := `, gzipPkg.Use(), `.NewReader(r)`)
- p.P(`if err != nil {`)
- p.In()
- p.P(`panic(err)`)
- p.Out()
- p.P(`}`)
- p.P(`ungzipped, err := `, ioutilPkg.Use(), `.ReadAll(gzipr)`)
- p.P(`if err != nil {`)
- p.In()
- p.P(`panic(err)`)
- p.Out()
- p.P(`}`)
- p.P(`if err := `, protoPkg.Use(), `.Unmarshal(ungzipped, d); err != nil {`)
- p.In()
- p.P(`panic(err)`)
- p.Out()
- p.P(`}`)
- p.P(`return d`)
- p.Out()
- p.P(`}`)
- }
- }
- func init() {
- generator.RegisterPlugin(NewPlugin())
- }
|