Add compressed file descriptor code generation.
This is fairly undocumented for now, but should be sufficiently
obvious for those wanting such an advanced feature anyway.
The only non-obvious part is that the []int returned by
Descriptor/EnumDescriptor describes the sequence of indexes used
to navigate from the FileDescriptorProto to the relevant
DescriptorProto/EnumDescriptorProto.
diff --git a/protoc-gen-go/generator/generator.go b/protoc-gen-go/generator/generator.go
index 9d987fa..1ff06b8 100644
--- a/protoc-gen-go/generator/generator.go
+++ b/protoc-gen-go/generator/generator.go
@@ -39,6 +39,7 @@
import (
"bufio"
"bytes"
+ "compress/gzip"
"fmt"
"go/parser"
"go/printer"
@@ -1133,6 +1134,8 @@
// Run the plugins before the imports so we know which imports are necessary.
g.runPlugins(file)
+ g.generateFileDescriptor(file)
+
// Generate header and imports last, though they appear first in the output.
rem := g.Buffer
g.Buffer = new(bytes.Buffer)
@@ -1393,6 +1396,14 @@
g.P("}")
}
+ var indexes []string
+ for m := enum.parent; m != nil; m = m.parent {
+ // XXX: skip groups?
+ indexes = append([]string{strconv.Itoa(m.index)}, indexes...)
+ }
+ indexes = append(indexes, strconv.Itoa(enum.index))
+ g.P("func (", ccTypeName, ") EnumDescriptor() ([]byte, []int) { return fileDescriptor", g.file.index, ", []int{", strings.Join(indexes, ", "), "} }")
+
g.P()
}
@@ -1793,6 +1804,14 @@
g.P("func (m *", ccTypeName, ") Reset() { *m = ", ccTypeName, "{} }")
g.P("func (m *", ccTypeName, ") String() string { return ", g.Pkg["proto"], ".CompactTextString(m) }")
g.P("func (*", ccTypeName, ") ProtoMessage() {}")
+ if !message.group {
+ var indexes []string
+ for m := message; m != nil; m = m.parent {
+ // XXX: skip groups?
+ indexes = append([]string{strconv.Itoa(m.index)}, indexes...)
+ }
+ g.P("func (*", ccTypeName, ") Descriptor() ([]byte, []int) { return fileDescriptor", g.file.index, ", []int{", strings.Join(indexes, ", "), "} }")
+ }
// Extension support methods
var hasExtensions, isMessageSet bool
@@ -2396,6 +2415,44 @@
g.init = nil
}
+func (g *Generator) generateFileDescriptor(file *FileDescriptor) {
+ // Make a copy and trim source_code_info data.
+ // TODO: Trim this more when we know exactly what we need.
+ pb := proto.Clone(file.FileDescriptorProto).(*descriptor.FileDescriptorProto)
+ pb.SourceCodeInfo = nil
+
+ b, err := proto.Marshal(pb)
+ if err != nil {
+ g.Fail(err.Error())
+ }
+
+ var buf bytes.Buffer
+ w, _ := gzip.NewWriterLevel(&buf, gzip.BestCompression)
+ w.Write(b)
+ w.Close()
+ b = buf.Bytes()
+
+ g.P("var fileDescriptor", file.index, " = []byte{")
+ g.In()
+ g.P("// ", len(b), " bytes of a gzipped FileDescriptorProto")
+ 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)
+ }
+ g.P(s)
+
+ b = b[n:]
+ }
+ g.Out()
+ g.P("}")
+}
+
func (g *Generator) generateEnumRegistration(enum *EnumDescriptor) {
// // We always print the full (proto-world) package name here.
pkg := enum.File().GetPackage()
diff --git a/protoc-gen-go/testdata/Makefile b/protoc-gen-go/testdata/Makefile
index eceea71..a85cc56 100644
--- a/protoc-gen-go/testdata/Makefile
+++ b/protoc-gen-go/testdata/Makefile
@@ -45,6 +45,9 @@
golden:
make -B my_test/test.pb.go
+ sed -i '/return.*fileDescriptor/d' my_test/test.pb.go
+ sed -i '/^var fileDescriptor/,/^}/d' my_test/test.pb.go
+ gofmt -w my_test/test.pb.go
diff -w my_test/test.pb.go my_test/test.pb.go.golden
nuke: clean