use proto syntax for describe (#57)
This commit is contained in:
parent
a337c1afcf
commit
58cd93280e
|
|
@ -165,7 +165,7 @@ func TestHandler(t *testing.T) {
|
||||||
|
|
||||||
out := buf.String()
|
out := buf.String()
|
||||||
if !compare(out, expectedOutput) {
|
if !compare(out, expectedOutput) {
|
||||||
t.Errorf("%s: Incorrect output.", name) // Expected:\n%s\nGot:\n%s", name, expectedOutput, out)
|
t.Errorf("%s: Incorrect output. Expected:\n%s\nGot:\n%s", name, expectedOutput, out)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -209,14 +209,7 @@ func makeProto() (proto.Message, error) {
|
||||||
var (
|
var (
|
||||||
verbosePrefix = `
|
verbosePrefix = `
|
||||||
Resolved method descriptor:
|
Resolved method descriptor:
|
||||||
{
|
rpc GetFiles ( .TestRequest ) returns ( .TestResponse );
|
||||||
"name": "GetFiles",
|
|
||||||
"inputType": ".TestRequest",
|
|
||||||
"outputType": ".TestResponse",
|
|
||||||
"options": {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Request metadata to send:
|
Request metadata to send:
|
||||||
bar: 456
|
bar: 456
|
||||||
|
|
|
||||||
|
|
@ -406,30 +406,61 @@ func main() {
|
||||||
fail(err, "Failed to resolve symbol %q", s)
|
fail(err, "Failed to resolve symbol %q", s)
|
||||||
}
|
}
|
||||||
|
|
||||||
txt, err := grpcurl.GetDescriptorText(dsc, descSource)
|
fqn := dsc.GetFullyQualifiedName()
|
||||||
if err != nil {
|
var elementType string
|
||||||
fail(err, "Failed to describe symbol %q", s)
|
switch d := dsc.(type) {
|
||||||
}
|
|
||||||
|
|
||||||
switch dsc.(type) {
|
|
||||||
case *desc.MessageDescriptor:
|
case *desc.MessageDescriptor:
|
||||||
fmt.Printf("%s is a message:\n", dsc.GetFullyQualifiedName())
|
elementType = "a message"
|
||||||
|
parent, ok := d.GetParent().(*desc.MessageDescriptor)
|
||||||
|
if ok {
|
||||||
|
if d.IsMapEntry() {
|
||||||
|
for _, f := range parent.GetFields() {
|
||||||
|
if f.IsMap() && f.GetMessageType() == d {
|
||||||
|
// found it: describe the map field instead
|
||||||
|
elementType = "the entry type for a map field"
|
||||||
|
dsc = f
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// see if it's a group
|
||||||
|
for _, f := range parent.GetFields() {
|
||||||
|
if f.GetType() == descpb.FieldDescriptorProto_TYPE_GROUP && f.GetMessageType() == d {
|
||||||
|
// found it: describe the map field instead
|
||||||
|
elementType = "the type of a group field"
|
||||||
|
dsc = f
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
case *desc.FieldDescriptor:
|
case *desc.FieldDescriptor:
|
||||||
fmt.Printf("%s is a field:\n", dsc.GetFullyQualifiedName())
|
elementType = "a field"
|
||||||
|
if d.GetType() == descpb.FieldDescriptorProto_TYPE_GROUP {
|
||||||
|
elementType = "a group field"
|
||||||
|
} else if d.IsExtension() {
|
||||||
|
elementType = "an extension"
|
||||||
|
}
|
||||||
case *desc.OneOfDescriptor:
|
case *desc.OneOfDescriptor:
|
||||||
fmt.Printf("%s is a one-of:\n", dsc.GetFullyQualifiedName())
|
elementType = "a one-of"
|
||||||
case *desc.EnumDescriptor:
|
case *desc.EnumDescriptor:
|
||||||
fmt.Printf("%s is an enum:\n", dsc.GetFullyQualifiedName())
|
elementType = "an enum"
|
||||||
case *desc.EnumValueDescriptor:
|
case *desc.EnumValueDescriptor:
|
||||||
fmt.Printf("%s is an enum value:\n", dsc.GetFullyQualifiedName())
|
elementType = "an enum value"
|
||||||
case *desc.ServiceDescriptor:
|
case *desc.ServiceDescriptor:
|
||||||
fmt.Printf("%s is a service:\n", dsc.GetFullyQualifiedName())
|
elementType = "a service"
|
||||||
case *desc.MethodDescriptor:
|
case *desc.MethodDescriptor:
|
||||||
fmt.Printf("%s is a method:\n", dsc.GetFullyQualifiedName())
|
elementType = "a method"
|
||||||
default:
|
default:
|
||||||
err = fmt.Errorf("descriptor has unrecognized type %T", dsc)
|
err = fmt.Errorf("descriptor has unrecognized type %T", dsc)
|
||||||
fail(err, "Failed to describe symbol %q", s)
|
fail(err, "Failed to describe symbol %q", s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
txt, err := grpcurl.GetDescriptorText(dsc, descSource)
|
||||||
|
if err != nil {
|
||||||
|
fail(err, "Failed to describe symbol %q", s)
|
||||||
|
}
|
||||||
|
fmt.Printf("%s is %s:\n", fqn, elementType)
|
||||||
fmt.Println(txt)
|
fmt.Println(txt)
|
||||||
|
|
||||||
if dsc, ok := dsc.(*desc.MessageDescriptor); ok && *msgTemplate {
|
if dsc, ok := dsc.(*desc.MessageDescriptor); ok && *msgTemplate {
|
||||||
|
|
|
||||||
2
go.mod
2
go.mod
|
|
@ -2,7 +2,7 @@ module github.com/fullstorydev/grpcurl
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang/protobuf v1.1.0
|
github.com/golang/protobuf v1.1.0
|
||||||
github.com/jhump/protoreflect v1.0.0
|
github.com/jhump/protoreflect v1.1.0
|
||||||
golang.org/x/net v0.0.0-20180530234432-1e491301e022
|
golang.org/x/net v0.0.0-20180530234432-1e491301e022
|
||||||
google.golang.org/grpc v1.12.0
|
google.golang.org/grpc v1.12.0
|
||||||
)
|
)
|
||||||
|
|
|
||||||
4
go.sum
4
go.sum
|
|
@ -1,7 +1,7 @@
|
||||||
github.com/golang/protobuf v1.1.0 h1:0iH4Ffd/meGoXqF2lSAhZHt8X+cPgkfn/cb6Cce5Vpc=
|
github.com/golang/protobuf v1.1.0 h1:0iH4Ffd/meGoXqF2lSAhZHt8X+cPgkfn/cb6Cce5Vpc=
|
||||||
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/jhump/protoreflect v1.0.0 h1:l94KtQ6gRI3ouKVcXNdofCQJWoHATzcI6tDizOgUaf0=
|
github.com/jhump/protoreflect v1.1.0 h1:h+zsMrsiq0vIl7yWmeowmd8e8VtnWk75U04GgXA2s6Y=
|
||||||
github.com/jhump/protoreflect v1.0.0/go.mod h1:kG/zRVeS2M91gYaCvvUbPkMjjtFQS4qqjcPFzFkh2zE=
|
github.com/jhump/protoreflect v1.1.0/go.mod h1:kG/zRVeS2M91gYaCvvUbPkMjjtFQS4qqjcPFzFkh2zE=
|
||||||
golang.org/x/net v0.0.0-20180530234432-1e491301e022 h1:MVYFTUmVD3/+ERcvRRI+P/C2+WOUimXh+Pd8LVsklZ4=
|
golang.org/x/net v0.0.0-20180530234432-1e491301e022 h1:MVYFTUmVD3/+ERcvRRI+P/C2+WOUimXh+Pd8LVsklZ4=
|
||||||
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
|
|
|
||||||
36
grpcurl.go
36
grpcurl.go
|
|
@ -24,9 +24,10 @@ import (
|
||||||
|
|
||||||
"github.com/golang/protobuf/jsonpb"
|
"github.com/golang/protobuf/jsonpb"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
"github.com/golang/protobuf/protoc-gen-go/descriptor"
|
descpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
|
||||||
"github.com/jhump/protoreflect/desc"
|
"github.com/jhump/protoreflect/desc"
|
||||||
"github.com/jhump/protoreflect/desc/protoparse"
|
"github.com/jhump/protoreflect/desc/protoparse"
|
||||||
|
"github.com/jhump/protoreflect/desc/protoprint"
|
||||||
"github.com/jhump/protoreflect/dynamic"
|
"github.com/jhump/protoreflect/dynamic"
|
||||||
"github.com/jhump/protoreflect/dynamic/grpcdynamic"
|
"github.com/jhump/protoreflect/dynamic/grpcdynamic"
|
||||||
"github.com/jhump/protoreflect/grpcreflect"
|
"github.com/jhump/protoreflect/grpcreflect"
|
||||||
|
|
@ -59,13 +60,13 @@ type DescriptorSource interface {
|
||||||
// DescriptorSourceFromProtoSets creates a DescriptorSource that is backed by the named files, whose contents
|
// DescriptorSourceFromProtoSets creates a DescriptorSource that is backed by the named files, whose contents
|
||||||
// are encoded FileDescriptorSet protos.
|
// are encoded FileDescriptorSet protos.
|
||||||
func DescriptorSourceFromProtoSets(fileNames ...string) (DescriptorSource, error) {
|
func DescriptorSourceFromProtoSets(fileNames ...string) (DescriptorSource, error) {
|
||||||
files := &descriptor.FileDescriptorSet{}
|
files := &descpb.FileDescriptorSet{}
|
||||||
for _, fileName := range fileNames {
|
for _, fileName := range fileNames {
|
||||||
b, err := ioutil.ReadFile(fileName)
|
b, err := ioutil.ReadFile(fileName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not load protoset file %q: %v", fileName, err)
|
return nil, fmt.Errorf("could not load protoset file %q: %v", fileName, err)
|
||||||
}
|
}
|
||||||
var fs descriptor.FileDescriptorSet
|
var fs descpb.FileDescriptorSet
|
||||||
err = proto.Unmarshal(b, &fs)
|
err = proto.Unmarshal(b, &fs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not parse contents of protoset file %q: %v", fileName, err)
|
return nil, fmt.Errorf("could not parse contents of protoset file %q: %v", fileName, err)
|
||||||
|
|
@ -91,8 +92,8 @@ func DescriptorSourceFromProtoFiles(importPaths []string, fileNames ...string) (
|
||||||
}
|
}
|
||||||
|
|
||||||
// DescriptorSourceFromFileDescriptorSet creates a DescriptorSource that is backed by the FileDescriptorSet.
|
// DescriptorSourceFromFileDescriptorSet creates a DescriptorSource that is backed by the FileDescriptorSet.
|
||||||
func DescriptorSourceFromFileDescriptorSet(files *descriptor.FileDescriptorSet) (DescriptorSource, error) {
|
func DescriptorSourceFromFileDescriptorSet(files *descpb.FileDescriptorSet) (DescriptorSource, error) {
|
||||||
unresolved := map[string]*descriptor.FileDescriptorProto{}
|
unresolved := map[string]*descpb.FileDescriptorProto{}
|
||||||
for _, fd := range files.File {
|
for _, fd := range files.File {
|
||||||
unresolved[fd.GetName()] = fd
|
unresolved[fd.GetName()] = fd
|
||||||
}
|
}
|
||||||
|
|
@ -106,7 +107,7 @@ func DescriptorSourceFromFileDescriptorSet(files *descriptor.FileDescriptorSet)
|
||||||
return &fileSource{files: resolved}, nil
|
return &fileSource{files: resolved}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveFileDescriptor(unresolved map[string]*descriptor.FileDescriptorProto, resolved map[string]*desc.FileDescriptor, filename string) (*desc.FileDescriptor, error) {
|
func resolveFileDescriptor(unresolved map[string]*descpb.FileDescriptorProto, resolved map[string]*desc.FileDescriptor, filename string) (*desc.FileDescriptor, error) {
|
||||||
if r, ok := resolved[filename]; ok {
|
if r, ok := resolved[filename]; ok {
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
@ -811,10 +812,27 @@ func MetadataToString(md metadata.MD) string {
|
||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var printer = &protoprint.Printer{
|
||||||
|
Compact: true,
|
||||||
|
OmitComments: protoprint.CommentsNonDoc,
|
||||||
|
SortElements: true,
|
||||||
|
ForceFullyQualifiedNames: true,
|
||||||
|
}
|
||||||
|
|
||||||
// GetDescriptorText returns a string representation of the given descriptor.
|
// GetDescriptorText returns a string representation of the given descriptor.
|
||||||
func GetDescriptorText(dsc desc.Descriptor, descSource DescriptorSource) (string, error) {
|
// This returns a snippet of proto source that describes the given element.
|
||||||
dscProto := EnsureExtensions(descSource, dsc.AsProto())
|
func GetDescriptorText(dsc desc.Descriptor, _ DescriptorSource) (string, error) {
|
||||||
return (&jsonpb.Marshaler{Indent: " "}).MarshalToString(dscProto)
|
// Note: DescriptorSource is not used, but remains an argument for backwards
|
||||||
|
// compatibility with previous implementation.
|
||||||
|
txt, err := printer.PrintProtoToString(dsc)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// callers don't expect trailing newlines
|
||||||
|
if txt[len(txt)-1] == '\n' {
|
||||||
|
txt = txt[:len(txt)-1]
|
||||||
|
}
|
||||||
|
return txt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnsureExtensions uses the given descriptor source to download extensions for
|
// EnsureExtensions uses the given descriptor source to download extensions for
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue