Как отобразить прото c -ген- go сжатый FileDescriptorProto в виде открытого текста? - PullRequest
1 голос
/ 05 марта 2020

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,
...
}

Я хочу прочитать его в виде открытого текста для целей отладки. Как это сделать?

Почему я хочу это - небольшое изменение, которое не должно произвести изменение в этом сгенерированном файле делает , и я выясняю, почему (и его трудно отладить, поскольку это просто двоичный двоичный объект).

Ответы [ 2 ]

1 голос
/ 05 марта 2020

Я написал такой код, чтобы проанализировать и распечатать BLOB-объект.

Ключи logi c на самом деле получены из https://github.com/grpc/grpc-go/blob/759de4dd00c25745b6f3d7a9fdfb32beaf1d838e/reflection/serverreflection.go#L202 -L226

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
}

Это печатает данные из файла прото, как JSON.

. Как Мар c Гравелл упоминает в комментарии к другому ответу, сжатие gzip недетерминировано c, поэтому один и тот же файл прото может создать разные сжатые FileDescriptorProto на двух разных компьютерах.

0 голосов
/ 05 марта 2020

a FileDescriptorProto - не простой текст ; он не содержит исходную схему в виде текста , а скорее: это экземпляр двоичного кода protobuf FileDescriptorProto, как определено descriptor.proto, содержащий обработанный значение исходной схемы.

Итак; Вы можете десериализовать эту полезную нагрузку (после разархивирования) как a FileDescriptorProto и использовать любой API-интерфейс отражения / метаданных, доступный в "go", чтобы получить его в какой-либо текстовой форме. Если реализация go protobuf включает API protobuf json (а не двоичный), вы можете просто вызвать API write- json для экземпляра FileDescriptorProto. Примечание: не все реализации protobuf реализуют API json.

...