如何将 protoc-gen-go gzipped FileDescriptorProto 显示为纯文本?
How to display protoc-gen-go gzipped FileDescriptorProto as plaintext?
protoc-gen-go
生成类似这样的东西,在生成的 go 文件的末尾:
var fileDescriptor_13c75530f718feb4 = []byte{
// 2516 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0xdf, 0x6f, 0x1c, 0x47,
...
}
出于调试目的,我想以明文形式阅读它。怎么做?
为什么我想要它 - 应该 不会 在这个生成的文件中产生变化的小变化 会 ,我正在弄清楚为什么(而且很难调试,因为它只是一个二进制 blob)。
a FileDescriptorProto
不是纯文本;它不包含原始模式 作为文本 ,而是:它是 descriptor.proto
定义的 FileDescriptorProto
的 protobuf 二进制编码实例,包含 原始模式的处理意义。
所以;您可以反序列化该有效负载(一旦 de-gzip 压缩)as a FileDescriptorProto
,并使用 "go" 中可用的任何 reflection/metadata API以某种文本形式获得它。如果 protobuf 的 go 实现包含 protobuf json(而不是二进制)API,您可以在 FileDescriptorProto
实例上调用 write-json API .注意:并非所有 protobuf 实现都实现 json API.
我写了这样的代码来解析和打印 blob。
package main
import (
"bytes"
"compress/gzip"
"encoding/json"
"fmt"
"io/ioutil"
proto "github.com/golang/protobuf/proto"
dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
_ [here write path to your generated go source]
// include the line above if you want to use proto.FileDescriptor,
// leave if you just copy-paste the bytes below
)
func main() {
// here write the path that is used in the generated file
// in init(), as an argument to proto.RegisterFile
// (or just copypaste the bytes instead of using proto.FileDescriptor)
bytes := proto.FileDescriptor(XXX)
fd, err := decodeFileDesc(bytes)
if err != nil {
panic(err)
}
b, err := json.MarshalIndent(fd,""," ")
if err != nil {
panic(err)
}
fmt.Println(string(b))
}
// decompress does gzip decompression.
func decompress(b []byte) ([]byte, error) {
r, err := gzip.NewReader(bytes.NewReader(b))
if err != nil {
return nil, fmt.Errorf("bad gzipped descriptor: %v", err)
}
out, err := ioutil.ReadAll(r)
if err != nil {
return nil, fmt.Errorf("bad gzipped descriptor: %v", err)
}
return out, nil
}
func decodeFileDesc(enc []byte) (*dpb.FileDescriptorProto, error) {
raw, err := decompress(enc)
if err != nil {
return nil, fmt.Errorf("failed to decompress enc: %v", err)
}
fd := new(dpb.FileDescriptorProto)
if err := proto.Unmarshal(raw, fd); err != nil {
return nil, fmt.Errorf("bad descriptor: %v", err)
}
return fd, nil
}
这会打印 proto 文件中的数据,作为 JSON。
正如 Marc Gravell 在对其他答案的评论中提到的那样,gzip 压缩是不确定的,因此同一个原型文件可以在两台不同的计算机上创建不同的 gzip 文件描述符原型。
protoc-gen-go
生成类似这样的东西,在生成的 go 文件的末尾:
var fileDescriptor_13c75530f718feb4 = []byte{
// 2516 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0xdf, 0x6f, 0x1c, 0x47,
...
}
出于调试目的,我想以明文形式阅读它。怎么做?
为什么我想要它 - 应该 不会 在这个生成的文件中产生变化的小变化 会 ,我正在弄清楚为什么(而且很难调试,因为它只是一个二进制 blob)。
a FileDescriptorProto
不是纯文本;它不包含原始模式 作为文本 ,而是:它是 descriptor.proto
定义的 FileDescriptorProto
的 protobuf 二进制编码实例,包含 原始模式的处理意义。
所以;您可以反序列化该有效负载(一旦 de-gzip 压缩)as a FileDescriptorProto
,并使用 "go" 中可用的任何 reflection/metadata API以某种文本形式获得它。如果 protobuf 的 go 实现包含 protobuf json(而不是二进制)API,您可以在 FileDescriptorProto
实例上调用 write-json API .注意:并非所有 protobuf 实现都实现 json API.
我写了这样的代码来解析和打印 blob。
package main
import (
"bytes"
"compress/gzip"
"encoding/json"
"fmt"
"io/ioutil"
proto "github.com/golang/protobuf/proto"
dpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
_ [here write path to your generated go source]
// include the line above if you want to use proto.FileDescriptor,
// leave if you just copy-paste the bytes below
)
func main() {
// here write the path that is used in the generated file
// in init(), as an argument to proto.RegisterFile
// (or just copypaste the bytes instead of using proto.FileDescriptor)
bytes := proto.FileDescriptor(XXX)
fd, err := decodeFileDesc(bytes)
if err != nil {
panic(err)
}
b, err := json.MarshalIndent(fd,""," ")
if err != nil {
panic(err)
}
fmt.Println(string(b))
}
// decompress does gzip decompression.
func decompress(b []byte) ([]byte, error) {
r, err := gzip.NewReader(bytes.NewReader(b))
if err != nil {
return nil, fmt.Errorf("bad gzipped descriptor: %v", err)
}
out, err := ioutil.ReadAll(r)
if err != nil {
return nil, fmt.Errorf("bad gzipped descriptor: %v", err)
}
return out, nil
}
func decodeFileDesc(enc []byte) (*dpb.FileDescriptorProto, error) {
raw, err := decompress(enc)
if err != nil {
return nil, fmt.Errorf("failed to decompress enc: %v", err)
}
fd := new(dpb.FileDescriptorProto)
if err := proto.Unmarshal(raw, fd); err != nil {
return nil, fmt.Errorf("bad descriptor: %v", err)
}
return fd, nil
}
这会打印 proto 文件中的数据,作为 JSON。
正如 Marc Gravell 在对其他答案的评论中提到的那样,gzip 压缩是不确定的,因此同一个原型文件可以在两台不同的计算机上创建不同的 gzip 文件描述符原型。