Moved to google.golang.org/genproto/googleapis/api/annotations
Fixes #52
This commit is contained in:
299
vendor/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor/registry.go
generated
vendored
Normal file
299
vendor/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor/registry.go
generated
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
package descriptor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor"
|
||||
plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
|
||||
)
|
||||
|
||||
// Registry is a registry of information extracted from plugin.CodeGeneratorRequest.
|
||||
type Registry struct {
|
||||
// msgs is a mapping from fully-qualified message name to descriptor
|
||||
msgs map[string]*Message
|
||||
|
||||
// enums is a mapping from fully-qualified enum name to descriptor
|
||||
enums map[string]*Enum
|
||||
|
||||
// files is a mapping from file path to descriptor
|
||||
files map[string]*File
|
||||
|
||||
// prefix is a prefix to be inserted to golang package paths generated from proto package names.
|
||||
prefix string
|
||||
|
||||
// pkgMap is a user-specified mapping from file path to proto package.
|
||||
pkgMap map[string]string
|
||||
|
||||
// pkgAliases is a mapping from package aliases to package paths in go which are already taken.
|
||||
pkgAliases map[string]string
|
||||
|
||||
// allowDeleteBody permits http delete methods to have a body
|
||||
allowDeleteBody bool
|
||||
}
|
||||
|
||||
// NewRegistry returns a new Registry.
|
||||
func NewRegistry() *Registry {
|
||||
return &Registry{
|
||||
msgs: make(map[string]*Message),
|
||||
enums: make(map[string]*Enum),
|
||||
files: make(map[string]*File),
|
||||
pkgMap: make(map[string]string),
|
||||
pkgAliases: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
// Load loads definitions of services, methods, messages, enumerations and fields from "req".
|
||||
func (r *Registry) Load(req *plugin.CodeGeneratorRequest) error {
|
||||
for _, file := range req.GetProtoFile() {
|
||||
r.loadFile(file)
|
||||
}
|
||||
|
||||
var targetPkg string
|
||||
for _, name := range req.FileToGenerate {
|
||||
target := r.files[name]
|
||||
if target == nil {
|
||||
return fmt.Errorf("no such file: %s", name)
|
||||
}
|
||||
name := packageIdentityName(target.FileDescriptorProto)
|
||||
if targetPkg == "" {
|
||||
targetPkg = name
|
||||
} else {
|
||||
if targetPkg != name {
|
||||
return fmt.Errorf("inconsistent package names: %s %s", targetPkg, name)
|
||||
}
|
||||
}
|
||||
|
||||
if err := r.loadServices(target); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadFile loads messages, enumerations and fields from "file".
|
||||
// It does not loads services and methods in "file". You need to call
|
||||
// loadServices after loadFiles is called for all files to load services and methods.
|
||||
func (r *Registry) loadFile(file *descriptor.FileDescriptorProto) {
|
||||
pkg := GoPackage{
|
||||
Path: r.goPackagePath(file),
|
||||
Name: defaultGoPackageName(file),
|
||||
}
|
||||
if err := r.ReserveGoPackageAlias(pkg.Name, pkg.Path); err != nil {
|
||||
for i := 0; ; i++ {
|
||||
alias := fmt.Sprintf("%s_%d", pkg.Name, i)
|
||||
if err := r.ReserveGoPackageAlias(alias, pkg.Path); err == nil {
|
||||
pkg.Alias = alias
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
f := &File{
|
||||
FileDescriptorProto: file,
|
||||
GoPkg: pkg,
|
||||
}
|
||||
|
||||
r.files[file.GetName()] = f
|
||||
r.registerMsg(f, nil, file.GetMessageType())
|
||||
r.registerEnum(f, nil, file.GetEnumType())
|
||||
}
|
||||
|
||||
func (r *Registry) registerMsg(file *File, outerPath []string, msgs []*descriptor.DescriptorProto) {
|
||||
for i, md := range msgs {
|
||||
m := &Message{
|
||||
File: file,
|
||||
Outers: outerPath,
|
||||
DescriptorProto: md,
|
||||
Index: i,
|
||||
}
|
||||
for _, fd := range md.GetField() {
|
||||
m.Fields = append(m.Fields, &Field{
|
||||
Message: m,
|
||||
FieldDescriptorProto: fd,
|
||||
})
|
||||
}
|
||||
file.Messages = append(file.Messages, m)
|
||||
r.msgs[m.FQMN()] = m
|
||||
glog.V(1).Infof("register name: %s", m.FQMN())
|
||||
|
||||
var outers []string
|
||||
outers = append(outers, outerPath...)
|
||||
outers = append(outers, m.GetName())
|
||||
r.registerMsg(file, outers, m.GetNestedType())
|
||||
r.registerEnum(file, outers, m.GetEnumType())
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Registry) registerEnum(file *File, outerPath []string, enums []*descriptor.EnumDescriptorProto) {
|
||||
for i, ed := range enums {
|
||||
e := &Enum{
|
||||
File: file,
|
||||
Outers: outerPath,
|
||||
EnumDescriptorProto: ed,
|
||||
Index: i,
|
||||
}
|
||||
file.Enums = append(file.Enums, e)
|
||||
r.enums[e.FQEN()] = e
|
||||
glog.V(1).Infof("register enum name: %s", e.FQEN())
|
||||
}
|
||||
}
|
||||
|
||||
// LookupMsg looks up a message type by "name".
|
||||
// It tries to resolve "name" from "location" if "name" is a relative message name.
|
||||
func (r *Registry) LookupMsg(location, name string) (*Message, error) {
|
||||
glog.V(1).Infof("lookup %s from %s", name, location)
|
||||
if strings.HasPrefix(name, ".") {
|
||||
m, ok := r.msgs[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no message found: %s", name)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(location, ".") {
|
||||
location = fmt.Sprintf(".%s", location)
|
||||
}
|
||||
components := strings.Split(location, ".")
|
||||
for len(components) > 0 {
|
||||
fqmn := strings.Join(append(components, name), ".")
|
||||
if m, ok := r.msgs[fqmn]; ok {
|
||||
return m, nil
|
||||
}
|
||||
components = components[:len(components)-1]
|
||||
}
|
||||
return nil, fmt.Errorf("no message found: %s", name)
|
||||
}
|
||||
|
||||
// LookupEnum looks up a enum type by "name".
|
||||
// It tries to resolve "name" from "location" if "name" is a relative enum name.
|
||||
func (r *Registry) LookupEnum(location, name string) (*Enum, error) {
|
||||
glog.V(1).Infof("lookup enum %s from %s", name, location)
|
||||
if strings.HasPrefix(name, ".") {
|
||||
e, ok := r.enums[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no enum found: %s", name)
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(location, ".") {
|
||||
location = fmt.Sprintf(".%s", location)
|
||||
}
|
||||
components := strings.Split(location, ".")
|
||||
for len(components) > 0 {
|
||||
fqen := strings.Join(append(components, name), ".")
|
||||
if e, ok := r.enums[fqen]; ok {
|
||||
return e, nil
|
||||
}
|
||||
components = components[:len(components)-1]
|
||||
}
|
||||
return nil, fmt.Errorf("no enum found: %s", name)
|
||||
}
|
||||
|
||||
// LookupFile looks up a file by name.
|
||||
func (r *Registry) LookupFile(name string) (*File, error) {
|
||||
f, ok := r.files[name]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("no such file given: %s", name)
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// AddPkgMap adds a mapping from a .proto file to proto package name.
|
||||
func (r *Registry) AddPkgMap(file, protoPkg string) {
|
||||
r.pkgMap[file] = protoPkg
|
||||
}
|
||||
|
||||
// SetPrefix registeres the perfix to be added to go package paths generated from proto package names.
|
||||
func (r *Registry) SetPrefix(prefix string) {
|
||||
r.prefix = prefix
|
||||
}
|
||||
|
||||
// ReserveGoPackageAlias reserves the unique alias of go package.
|
||||
// If succeeded, the alias will be never used for other packages in generated go files.
|
||||
// If failed, the alias is already taken by another package, so you need to use another
|
||||
// alias for the package in your go files.
|
||||
func (r *Registry) ReserveGoPackageAlias(alias, pkgpath string) error {
|
||||
if taken, ok := r.pkgAliases[alias]; ok {
|
||||
if taken == pkgpath {
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("package name %s is already taken. Use another alias", alias)
|
||||
}
|
||||
r.pkgAliases[alias] = pkgpath
|
||||
return nil
|
||||
}
|
||||
|
||||
// goPackagePath returns the go package path which go files generated from "f" should have.
|
||||
// It respects the mapping registered by AddPkgMap if exists. Or use go_package as import path
|
||||
// if it includes a slash, Otherwide, it generates a path from the file name of "f".
|
||||
func (r *Registry) goPackagePath(f *descriptor.FileDescriptorProto) string {
|
||||
name := f.GetName()
|
||||
if pkg, ok := r.pkgMap[name]; ok {
|
||||
return path.Join(r.prefix, pkg)
|
||||
}
|
||||
|
||||
gopkg := f.Options.GetGoPackage()
|
||||
idx := strings.LastIndex(gopkg, "/")
|
||||
if idx >= 0 {
|
||||
return gopkg
|
||||
}
|
||||
|
||||
return path.Join(r.prefix, path.Dir(name))
|
||||
}
|
||||
|
||||
// GetAllFQMNs returns a list of all FQMNs
|
||||
func (r *Registry) GetAllFQMNs() []string {
|
||||
var keys []string
|
||||
for k := range r.msgs {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// GetAllFQENs returns a list of all FQENs
|
||||
func (r *Registry) GetAllFQENs() []string {
|
||||
var keys []string
|
||||
for k := range r.enums {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
// SetAllowDeleteBody controls whether http delete methods may have a
|
||||
// body or fail loading if encountered.
|
||||
func (r *Registry) SetAllowDeleteBody(allow bool) {
|
||||
r.allowDeleteBody = allow
|
||||
}
|
||||
|
||||
// defaultGoPackageName returns the default go package name to be used for go files generated from "f".
|
||||
// You might need to use an unique alias for the package when you import it. Use ReserveGoPackageAlias to get a unique alias.
|
||||
func defaultGoPackageName(f *descriptor.FileDescriptorProto) string {
|
||||
name := packageIdentityName(f)
|
||||
return strings.Replace(name, ".", "_", -1)
|
||||
}
|
||||
|
||||
// packageIdentityName returns the identity of packages.
|
||||
// protoc-gen-grpc-gateway rejects CodeGenerationRequests which contains more than one packages
|
||||
// as protoc-gen-go does.
|
||||
func packageIdentityName(f *descriptor.FileDescriptorProto) string {
|
||||
if f.Options != nil && f.Options.GoPackage != nil {
|
||||
gopkg := f.Options.GetGoPackage()
|
||||
idx := strings.LastIndex(gopkg, "/")
|
||||
if idx < 0 {
|
||||
return gopkg
|
||||
}
|
||||
|
||||
return gopkg[idx+1:]
|
||||
}
|
||||
|
||||
if f.Package == nil {
|
||||
base := filepath.Base(f.GetName())
|
||||
ext := filepath.Ext(base)
|
||||
return strings.TrimSuffix(base, ext)
|
||||
}
|
||||
return f.GetPackage()
|
||||
}
|
533
vendor/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor/registry_test.go
generated
vendored
Normal file
533
vendor/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor/registry_test.go
generated
vendored
Normal file
@@ -0,0 +1,533 @@
|
||||
package descriptor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor"
|
||||
plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
|
||||
)
|
||||
|
||||
func loadFile(t *testing.T, reg *Registry, src string) *descriptor.FileDescriptorProto {
|
||||
var file descriptor.FileDescriptorProto
|
||||
if err := proto.UnmarshalText(src, &file); err != nil {
|
||||
t.Fatalf("proto.UnmarshalText(%s, &file) failed with %v; want success", src, err)
|
||||
}
|
||||
reg.loadFile(&file)
|
||||
return &file
|
||||
}
|
||||
|
||||
func load(t *testing.T, reg *Registry, src string) error {
|
||||
var req plugin.CodeGeneratorRequest
|
||||
if err := proto.UnmarshalText(src, &req); err != nil {
|
||||
t.Fatalf("proto.UnmarshalText(%s, &file) failed with %v; want success", src, err)
|
||||
}
|
||||
return reg.Load(&req)
|
||||
}
|
||||
|
||||
func TestLoadFile(t *testing.T) {
|
||||
reg := NewRegistry()
|
||||
fd := loadFile(t, reg, `
|
||||
name: 'example.proto'
|
||||
package: 'example'
|
||||
message_type <
|
||||
name: 'ExampleMessage'
|
||||
field <
|
||||
name: 'str'
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
number: 1
|
||||
>
|
||||
>
|
||||
`)
|
||||
|
||||
file := reg.files["example.proto"]
|
||||
if file == nil {
|
||||
t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
|
||||
return
|
||||
}
|
||||
wantPkg := GoPackage{Path: ".", Name: "example"}
|
||||
if got, want := file.GoPkg, wantPkg; got != want {
|
||||
t.Errorf("file.GoPkg = %#v; want %#v", got, want)
|
||||
}
|
||||
|
||||
msg, err := reg.LookupMsg("", ".example.ExampleMessage")
|
||||
if err != nil {
|
||||
t.Errorf("reg.LookupMsg(%q, %q)) failed with %v; want success", "", ".example.ExampleMessage", err)
|
||||
return
|
||||
}
|
||||
if got, want := msg.DescriptorProto, fd.MessageType[0]; got != want {
|
||||
t.Errorf("reg.lookupMsg(%q, %q).DescriptorProto = %#v; want %#v", "", ".example.ExampleMessage", got, want)
|
||||
}
|
||||
if got, want := msg.File, file; got != want {
|
||||
t.Errorf("msg.File = %v; want %v", got, want)
|
||||
}
|
||||
if got := msg.Outers; got != nil {
|
||||
t.Errorf("msg.Outers = %v; want %v", got, nil)
|
||||
}
|
||||
if got, want := len(msg.Fields), 1; got != want {
|
||||
t.Errorf("len(msg.Fields) = %d; want %d", got, want)
|
||||
} else if got, want := msg.Fields[0].FieldDescriptorProto, fd.MessageType[0].Field[0]; got != want {
|
||||
t.Errorf("msg.Fields[0].FieldDescriptorProto = %v; want %v", got, want)
|
||||
} else if got, want := msg.Fields[0].Message, msg; got != want {
|
||||
t.Errorf("msg.Fields[0].Message = %v; want %v", got, want)
|
||||
}
|
||||
|
||||
if got, want := len(file.Messages), 1; got != want {
|
||||
t.Errorf("file.Meeesages = %#v; want %#v", file.Messages, []*Message{msg})
|
||||
}
|
||||
if got, want := file.Messages[0], msg; got != want {
|
||||
t.Errorf("file.Meeesages[0] = %v; want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadFileNestedPackage(t *testing.T) {
|
||||
reg := NewRegistry()
|
||||
loadFile(t, reg, `
|
||||
name: 'example.proto'
|
||||
package: 'example.nested.nested2'
|
||||
`)
|
||||
|
||||
file := reg.files["example.proto"]
|
||||
if file == nil {
|
||||
t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
|
||||
return
|
||||
}
|
||||
wantPkg := GoPackage{Path: ".", Name: "example_nested_nested2"}
|
||||
if got, want := file.GoPkg, wantPkg; got != want {
|
||||
t.Errorf("file.GoPkg = %#v; want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadFileWithDir(t *testing.T) {
|
||||
reg := NewRegistry()
|
||||
loadFile(t, reg, `
|
||||
name: 'path/to/example.proto'
|
||||
package: 'example'
|
||||
`)
|
||||
|
||||
file := reg.files["path/to/example.proto"]
|
||||
if file == nil {
|
||||
t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
|
||||
return
|
||||
}
|
||||
wantPkg := GoPackage{Path: "path/to", Name: "example"}
|
||||
if got, want := file.GoPkg, wantPkg; got != want {
|
||||
t.Errorf("file.GoPkg = %#v; want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadFileWithoutPackage(t *testing.T) {
|
||||
reg := NewRegistry()
|
||||
loadFile(t, reg, `
|
||||
name: 'path/to/example_file.proto'
|
||||
`)
|
||||
|
||||
file := reg.files["path/to/example_file.proto"]
|
||||
if file == nil {
|
||||
t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
|
||||
return
|
||||
}
|
||||
wantPkg := GoPackage{Path: "path/to", Name: "example_file"}
|
||||
if got, want := file.GoPkg, wantPkg; got != want {
|
||||
t.Errorf("file.GoPkg = %#v; want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadFileWithMapping(t *testing.T) {
|
||||
reg := NewRegistry()
|
||||
reg.AddPkgMap("path/to/example.proto", "example.com/proj/example/proto")
|
||||
loadFile(t, reg, `
|
||||
name: 'path/to/example.proto'
|
||||
package: 'example'
|
||||
`)
|
||||
|
||||
file := reg.files["path/to/example.proto"]
|
||||
if file == nil {
|
||||
t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
|
||||
return
|
||||
}
|
||||
wantPkg := GoPackage{Path: "example.com/proj/example/proto", Name: "example"}
|
||||
if got, want := file.GoPkg, wantPkg; got != want {
|
||||
t.Errorf("file.GoPkg = %#v; want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadFileWithPackageNameCollision(t *testing.T) {
|
||||
reg := NewRegistry()
|
||||
loadFile(t, reg, `
|
||||
name: 'path/to/another.proto'
|
||||
package: 'example'
|
||||
`)
|
||||
loadFile(t, reg, `
|
||||
name: 'path/to/example.proto'
|
||||
package: 'example'
|
||||
`)
|
||||
if err := reg.ReserveGoPackageAlias("ioutil", "io/ioutil"); err != nil {
|
||||
t.Fatalf("reg.ReserveGoPackageAlias(%q) failed with %v; want success", "ioutil", err)
|
||||
}
|
||||
loadFile(t, reg, `
|
||||
name: 'path/to/ioutil.proto'
|
||||
package: 'ioutil'
|
||||
`)
|
||||
|
||||
file := reg.files["path/to/another.proto"]
|
||||
if file == nil {
|
||||
t.Errorf("reg.files[%q] = nil; want non-nil", "path/to/another.proto")
|
||||
return
|
||||
}
|
||||
wantPkg := GoPackage{Path: "path/to", Name: "example"}
|
||||
if got, want := file.GoPkg, wantPkg; got != want {
|
||||
t.Errorf("file.GoPkg = %#v; want %#v", got, want)
|
||||
}
|
||||
|
||||
file = reg.files["path/to/example.proto"]
|
||||
if file == nil {
|
||||
t.Errorf("reg.files[%q] = nil; want non-nil", "path/to/example.proto")
|
||||
return
|
||||
}
|
||||
wantPkg = GoPackage{Path: "path/to", Name: "example", Alias: ""}
|
||||
if got, want := file.GoPkg, wantPkg; got != want {
|
||||
t.Errorf("file.GoPkg = %#v; want %#v", got, want)
|
||||
}
|
||||
|
||||
file = reg.files["path/to/ioutil.proto"]
|
||||
if file == nil {
|
||||
t.Errorf("reg.files[%q] = nil; want non-nil", "path/to/ioutil.proto")
|
||||
return
|
||||
}
|
||||
wantPkg = GoPackage{Path: "path/to", Name: "ioutil", Alias: "ioutil_0"}
|
||||
if got, want := file.GoPkg, wantPkg; got != want {
|
||||
t.Errorf("file.GoPkg = %#v; want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadFileWithIdenticalGoPkg(t *testing.T) {
|
||||
reg := NewRegistry()
|
||||
reg.AddPkgMap("path/to/another.proto", "example.com/example")
|
||||
reg.AddPkgMap("path/to/example.proto", "example.com/example")
|
||||
loadFile(t, reg, `
|
||||
name: 'path/to/another.proto'
|
||||
package: 'example'
|
||||
`)
|
||||
loadFile(t, reg, `
|
||||
name: 'path/to/example.proto'
|
||||
package: 'example'
|
||||
`)
|
||||
|
||||
file := reg.files["path/to/example.proto"]
|
||||
if file == nil {
|
||||
t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
|
||||
return
|
||||
}
|
||||
wantPkg := GoPackage{Path: "example.com/example", Name: "example"}
|
||||
if got, want := file.GoPkg, wantPkg; got != want {
|
||||
t.Errorf("file.GoPkg = %#v; want %#v", got, want)
|
||||
}
|
||||
|
||||
file = reg.files["path/to/another.proto"]
|
||||
if file == nil {
|
||||
t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
|
||||
return
|
||||
}
|
||||
wantPkg = GoPackage{Path: "example.com/example", Name: "example"}
|
||||
if got, want := file.GoPkg, wantPkg; got != want {
|
||||
t.Errorf("file.GoPkg = %#v; want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadFileWithPrefix(t *testing.T) {
|
||||
reg := NewRegistry()
|
||||
reg.SetPrefix("third_party")
|
||||
loadFile(t, reg, `
|
||||
name: 'path/to/example.proto'
|
||||
package: 'example'
|
||||
`)
|
||||
|
||||
file := reg.files["path/to/example.proto"]
|
||||
if file == nil {
|
||||
t.Errorf("reg.files[%q] = nil; want non-nil", "example.proto")
|
||||
return
|
||||
}
|
||||
wantPkg := GoPackage{Path: "third_party/path/to", Name: "example"}
|
||||
if got, want := file.GoPkg, wantPkg; got != want {
|
||||
t.Errorf("file.GoPkg = %#v; want %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLookupMsgWithoutPackage(t *testing.T) {
|
||||
reg := NewRegistry()
|
||||
fd := loadFile(t, reg, `
|
||||
name: 'example.proto'
|
||||
message_type <
|
||||
name: 'ExampleMessage'
|
||||
field <
|
||||
name: 'str'
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
number: 1
|
||||
>
|
||||
>
|
||||
`)
|
||||
|
||||
msg, err := reg.LookupMsg("", ".ExampleMessage")
|
||||
if err != nil {
|
||||
t.Errorf("reg.LookupMsg(%q, %q)) failed with %v; want success", "", ".ExampleMessage", err)
|
||||
return
|
||||
}
|
||||
if got, want := msg.DescriptorProto, fd.MessageType[0]; got != want {
|
||||
t.Errorf("reg.lookupMsg(%q, %q).DescriptorProto = %#v; want %#v", "", ".ExampleMessage", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLookupMsgWithNestedPackage(t *testing.T) {
|
||||
reg := NewRegistry()
|
||||
fd := loadFile(t, reg, `
|
||||
name: 'example.proto'
|
||||
package: 'nested.nested2.mypackage'
|
||||
message_type <
|
||||
name: 'ExampleMessage'
|
||||
field <
|
||||
name: 'str'
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
number: 1
|
||||
>
|
||||
>
|
||||
`)
|
||||
|
||||
for _, name := range []string{
|
||||
"nested.nested2.mypackage.ExampleMessage",
|
||||
"nested2.mypackage.ExampleMessage",
|
||||
"mypackage.ExampleMessage",
|
||||
"ExampleMessage",
|
||||
} {
|
||||
msg, err := reg.LookupMsg("nested.nested2.mypackage", name)
|
||||
if err != nil {
|
||||
t.Errorf("reg.LookupMsg(%q, %q)) failed with %v; want success", ".nested.nested2.mypackage", name, err)
|
||||
return
|
||||
}
|
||||
if got, want := msg.DescriptorProto, fd.MessageType[0]; got != want {
|
||||
t.Errorf("reg.lookupMsg(%q, %q).DescriptorProto = %#v; want %#v", ".nested.nested2.mypackage", name, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
for _, loc := range []string{
|
||||
".nested.nested2.mypackage",
|
||||
"nested.nested2.mypackage",
|
||||
".nested.nested2",
|
||||
"nested.nested2",
|
||||
".nested",
|
||||
"nested",
|
||||
".",
|
||||
"",
|
||||
"somewhere.else",
|
||||
} {
|
||||
name := "nested.nested2.mypackage.ExampleMessage"
|
||||
msg, err := reg.LookupMsg(loc, name)
|
||||
if err != nil {
|
||||
t.Errorf("reg.LookupMsg(%q, %q)) failed with %v; want success", loc, name, err)
|
||||
return
|
||||
}
|
||||
if got, want := msg.DescriptorProto, fd.MessageType[0]; got != want {
|
||||
t.Errorf("reg.lookupMsg(%q, %q).DescriptorProto = %#v; want %#v", loc, name, got, want)
|
||||
}
|
||||
}
|
||||
|
||||
for _, loc := range []string{
|
||||
".nested.nested2.mypackage",
|
||||
"nested.nested2.mypackage",
|
||||
".nested.nested2",
|
||||
"nested.nested2",
|
||||
".nested",
|
||||
"nested",
|
||||
} {
|
||||
name := "nested2.mypackage.ExampleMessage"
|
||||
msg, err := reg.LookupMsg(loc, name)
|
||||
if err != nil {
|
||||
t.Errorf("reg.LookupMsg(%q, %q)) failed with %v; want success", loc, name, err)
|
||||
return
|
||||
}
|
||||
if got, want := msg.DescriptorProto, fd.MessageType[0]; got != want {
|
||||
t.Errorf("reg.lookupMsg(%q, %q).DescriptorProto = %#v; want %#v", loc, name, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadWithInconsistentTargetPackage(t *testing.T) {
|
||||
for _, spec := range []struct {
|
||||
req string
|
||||
consistent bool
|
||||
}{
|
||||
// root package, no explicit go package
|
||||
{
|
||||
req: `
|
||||
file_to_generate: 'a.proto'
|
||||
file_to_generate: 'b.proto'
|
||||
proto_file <
|
||||
name: 'a.proto'
|
||||
message_type < name: 'A' >
|
||||
service <
|
||||
name: "AService"
|
||||
method <
|
||||
name: "Meth"
|
||||
input_type: "A"
|
||||
output_type: "A"
|
||||
options <
|
||||
[google.api.http] < post: "/v1/a" body: "*" >
|
||||
>
|
||||
>
|
||||
>
|
||||
>
|
||||
proto_file <
|
||||
name: 'b.proto'
|
||||
message_type < name: 'B' >
|
||||
service <
|
||||
name: "BService"
|
||||
method <
|
||||
name: "Meth"
|
||||
input_type: "B"
|
||||
output_type: "B"
|
||||
options <
|
||||
[google.api.http] < post: "/v1/b" body: "*" >
|
||||
>
|
||||
>
|
||||
>
|
||||
>
|
||||
`,
|
||||
consistent: false,
|
||||
},
|
||||
// named package, no explicit go package
|
||||
{
|
||||
req: `
|
||||
file_to_generate: 'a.proto'
|
||||
file_to_generate: 'b.proto'
|
||||
proto_file <
|
||||
name: 'a.proto'
|
||||
package: 'example.foo'
|
||||
message_type < name: 'A' >
|
||||
service <
|
||||
name: "AService"
|
||||
method <
|
||||
name: "Meth"
|
||||
input_type: "A"
|
||||
output_type: "A"
|
||||
options <
|
||||
[google.api.http] < post: "/v1/a" body: "*" >
|
||||
>
|
||||
>
|
||||
>
|
||||
>
|
||||
proto_file <
|
||||
name: 'b.proto'
|
||||
package: 'example.foo'
|
||||
message_type < name: 'B' >
|
||||
service <
|
||||
name: "BService"
|
||||
method <
|
||||
name: "Meth"
|
||||
input_type: "B"
|
||||
output_type: "B"
|
||||
options <
|
||||
[google.api.http] < post: "/v1/b" body: "*" >
|
||||
>
|
||||
>
|
||||
>
|
||||
>
|
||||
`,
|
||||
consistent: true,
|
||||
},
|
||||
// root package, explicit go package
|
||||
{
|
||||
req: `
|
||||
file_to_generate: 'a.proto'
|
||||
file_to_generate: 'b.proto'
|
||||
proto_file <
|
||||
name: 'a.proto'
|
||||
options < go_package: 'foo' >
|
||||
message_type < name: 'A' >
|
||||
service <
|
||||
name: "AService"
|
||||
method <
|
||||
name: "Meth"
|
||||
input_type: "A"
|
||||
output_type: "A"
|
||||
options <
|
||||
[google.api.http] < post: "/v1/a" body: "*" >
|
||||
>
|
||||
>
|
||||
>
|
||||
>
|
||||
proto_file <
|
||||
name: 'b.proto'
|
||||
options < go_package: 'foo' >
|
||||
message_type < name: 'B' >
|
||||
service <
|
||||
name: "BService"
|
||||
method <
|
||||
name: "Meth"
|
||||
input_type: "B"
|
||||
output_type: "B"
|
||||
options <
|
||||
[google.api.http] < post: "/v1/b" body: "*" >
|
||||
>
|
||||
>
|
||||
>
|
||||
>
|
||||
`,
|
||||
consistent: true,
|
||||
},
|
||||
// named package, explicit go package
|
||||
{
|
||||
req: `
|
||||
file_to_generate: 'a.proto'
|
||||
file_to_generate: 'b.proto'
|
||||
proto_file <
|
||||
name: 'a.proto'
|
||||
package: 'example.foo'
|
||||
options < go_package: 'foo' >
|
||||
message_type < name: 'A' >
|
||||
service <
|
||||
name: "AService"
|
||||
method <
|
||||
name: "Meth"
|
||||
input_type: "A"
|
||||
output_type: "A"
|
||||
options <
|
||||
[google.api.http] < post: "/v1/a" body: "*" >
|
||||
>
|
||||
>
|
||||
>
|
||||
>
|
||||
proto_file <
|
||||
name: 'b.proto'
|
||||
package: 'example.foo'
|
||||
options < go_package: 'foo' >
|
||||
message_type < name: 'B' >
|
||||
service <
|
||||
name: "BService"
|
||||
method <
|
||||
name: "Meth"
|
||||
input_type: "B"
|
||||
output_type: "B"
|
||||
options <
|
||||
[google.api.http] < post: "/v1/b" body: "*" >
|
||||
>
|
||||
>
|
||||
>
|
||||
>
|
||||
`,
|
||||
consistent: true,
|
||||
},
|
||||
} {
|
||||
reg := NewRegistry()
|
||||
err := load(t, reg, spec.req)
|
||||
if got, want := err == nil, spec.consistent; got != want {
|
||||
if want {
|
||||
t.Errorf("reg.Load(%s) failed with %v; want success", spec.req, err)
|
||||
continue
|
||||
}
|
||||
t.Errorf("reg.Load(%s) succeeded; want an package inconsistency error", spec.req)
|
||||
}
|
||||
}
|
||||
}
|
266
vendor/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor/services.go
generated
vendored
Normal file
266
vendor/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor/services.go
generated
vendored
Normal file
@@ -0,0 +1,266 @@
|
||||
package descriptor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/golang/protobuf/proto"
|
||||
descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule"
|
||||
options "google.golang.org/genproto/googleapis/api/annotations"
|
||||
)
|
||||
|
||||
// loadServices registers services and their methods from "targetFile" to "r".
|
||||
// It must be called after loadFile is called for all files so that loadServices
|
||||
// can resolve names of message types and their fields.
|
||||
func (r *Registry) loadServices(file *File) error {
|
||||
glog.V(1).Infof("Loading services from %s", file.GetName())
|
||||
var svcs []*Service
|
||||
for _, sd := range file.GetService() {
|
||||
glog.V(2).Infof("Registering %s", sd.GetName())
|
||||
svc := &Service{
|
||||
File: file,
|
||||
ServiceDescriptorProto: sd,
|
||||
}
|
||||
for _, md := range sd.GetMethod() {
|
||||
glog.V(2).Infof("Processing %s.%s", sd.GetName(), md.GetName())
|
||||
opts, err := extractAPIOptions(md)
|
||||
if err != nil {
|
||||
glog.Errorf("Failed to extract ApiMethodOptions from %s.%s: %v", svc.GetName(), md.GetName(), err)
|
||||
return err
|
||||
}
|
||||
if opts == nil {
|
||||
glog.V(1).Infof("Found non-target method: %s.%s", svc.GetName(), md.GetName())
|
||||
}
|
||||
meth, err := r.newMethod(svc, md, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
svc.Methods = append(svc.Methods, meth)
|
||||
}
|
||||
if len(svc.Methods) == 0 {
|
||||
continue
|
||||
}
|
||||
glog.V(2).Infof("Registered %s with %d method(s)", svc.GetName(), len(svc.Methods))
|
||||
svcs = append(svcs, svc)
|
||||
}
|
||||
file.Services = svcs
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Registry) newMethod(svc *Service, md *descriptor.MethodDescriptorProto, opts *options.HttpRule) (*Method, error) {
|
||||
requestType, err := r.LookupMsg(svc.File.GetPackage(), md.GetInputType())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
responseType, err := r.LookupMsg(svc.File.GetPackage(), md.GetOutputType())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
meth := &Method{
|
||||
Service: svc,
|
||||
MethodDescriptorProto: md,
|
||||
RequestType: requestType,
|
||||
ResponseType: responseType,
|
||||
}
|
||||
|
||||
newBinding := func(opts *options.HttpRule, idx int) (*Binding, error) {
|
||||
var (
|
||||
httpMethod string
|
||||
pathTemplate string
|
||||
)
|
||||
switch {
|
||||
case opts.GetGet() != "":
|
||||
httpMethod = "GET"
|
||||
pathTemplate = opts.GetGet()
|
||||
if opts.Body != "" {
|
||||
return nil, fmt.Errorf("needs request body even though http method is GET: %s", md.GetName())
|
||||
}
|
||||
|
||||
case opts.GetPut() != "":
|
||||
httpMethod = "PUT"
|
||||
pathTemplate = opts.GetPut()
|
||||
|
||||
case opts.GetPost() != "":
|
||||
httpMethod = "POST"
|
||||
pathTemplate = opts.GetPost()
|
||||
|
||||
case opts.GetDelete() != "":
|
||||
httpMethod = "DELETE"
|
||||
pathTemplate = opts.GetDelete()
|
||||
if opts.Body != "" && !r.allowDeleteBody {
|
||||
return nil, fmt.Errorf("needs request body even though http method is DELETE: %s", md.GetName())
|
||||
}
|
||||
|
||||
case opts.GetPatch() != "":
|
||||
httpMethod = "PATCH"
|
||||
pathTemplate = opts.GetPatch()
|
||||
|
||||
case opts.GetCustom() != nil:
|
||||
custom := opts.GetCustom()
|
||||
httpMethod = custom.Kind
|
||||
pathTemplate = custom.Path
|
||||
|
||||
default:
|
||||
glog.V(1).Infof("No pattern specified in google.api.HttpRule: %s", md.GetName())
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
parsed, err := httprule.Parse(pathTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tmpl := parsed.Compile()
|
||||
|
||||
if md.GetClientStreaming() && len(tmpl.Fields) > 0 {
|
||||
return nil, fmt.Errorf("cannot use path parameter in client streaming")
|
||||
}
|
||||
|
||||
b := &Binding{
|
||||
Method: meth,
|
||||
Index: idx,
|
||||
PathTmpl: tmpl,
|
||||
HTTPMethod: httpMethod,
|
||||
}
|
||||
|
||||
for _, f := range tmpl.Fields {
|
||||
param, err := r.newParam(meth, f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.PathParams = append(b.PathParams, param)
|
||||
}
|
||||
|
||||
// TODO(yugui) Handle query params
|
||||
|
||||
b.Body, err = r.newBody(meth, opts.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return b, nil
|
||||
}
|
||||
b, err := newBinding(opts, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if b != nil {
|
||||
meth.Bindings = append(meth.Bindings, b)
|
||||
}
|
||||
for i, additional := range opts.GetAdditionalBindings() {
|
||||
if len(additional.AdditionalBindings) > 0 {
|
||||
return nil, fmt.Errorf("additional_binding in additional_binding not allowed: %s.%s", svc.GetName(), meth.GetName())
|
||||
}
|
||||
b, err := newBinding(additional, i+1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
meth.Bindings = append(meth.Bindings, b)
|
||||
}
|
||||
|
||||
return meth, nil
|
||||
}
|
||||
|
||||
func extractAPIOptions(meth *descriptor.MethodDescriptorProto) (*options.HttpRule, error) {
|
||||
if meth.Options == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if !proto.HasExtension(meth.Options, options.E_Http) {
|
||||
return nil, nil
|
||||
}
|
||||
ext, err := proto.GetExtension(meth.Options, options.E_Http)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
opts, ok := ext.(*options.HttpRule)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("extension is %T; want an HttpRule", ext)
|
||||
}
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
func (r *Registry) newParam(meth *Method, path string) (Parameter, error) {
|
||||
msg := meth.RequestType
|
||||
fields, err := r.resolveFiledPath(msg, path)
|
||||
if err != nil {
|
||||
return Parameter{}, err
|
||||
}
|
||||
l := len(fields)
|
||||
if l == 0 {
|
||||
return Parameter{}, fmt.Errorf("invalid field access list for %s", path)
|
||||
}
|
||||
target := fields[l-1].Target
|
||||
switch target.GetType() {
|
||||
case descriptor.FieldDescriptorProto_TYPE_MESSAGE, descriptor.FieldDescriptorProto_TYPE_GROUP:
|
||||
return Parameter{}, fmt.Errorf("aggregate type %s in parameter of %s.%s: %s", target.Type, meth.Service.GetName(), meth.GetName(), path)
|
||||
}
|
||||
return Parameter{
|
||||
FieldPath: FieldPath(fields),
|
||||
Method: meth,
|
||||
Target: fields[l-1].Target,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *Registry) newBody(meth *Method, path string) (*Body, error) {
|
||||
msg := meth.RequestType
|
||||
switch path {
|
||||
case "":
|
||||
return nil, nil
|
||||
case "*":
|
||||
return &Body{FieldPath: nil}, nil
|
||||
}
|
||||
fields, err := r.resolveFiledPath(msg, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Body{FieldPath: FieldPath(fields)}, nil
|
||||
}
|
||||
|
||||
// lookupField looks up a field named "name" within "msg".
|
||||
// It returns nil if no such field found.
|
||||
func lookupField(msg *Message, name string) *Field {
|
||||
for _, f := range msg.Fields {
|
||||
if f.GetName() == name {
|
||||
return f
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// resolveFieldPath resolves "path" into a list of fieldDescriptor, starting from "msg".
|
||||
func (r *Registry) resolveFiledPath(msg *Message, path string) ([]FieldPathComponent, error) {
|
||||
if path == "" {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
root := msg
|
||||
var result []FieldPathComponent
|
||||
for i, c := range strings.Split(path, ".") {
|
||||
if i > 0 {
|
||||
f := result[i-1].Target
|
||||
switch f.GetType() {
|
||||
case descriptor.FieldDescriptorProto_TYPE_MESSAGE, descriptor.FieldDescriptorProto_TYPE_GROUP:
|
||||
var err error
|
||||
msg, err = r.LookupMsg(msg.FQMN(), f.GetTypeName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("not an aggregate type: %s in %s", f.GetName(), path)
|
||||
}
|
||||
}
|
||||
|
||||
glog.V(2).Infof("Lookup %s in %s", c, msg.FQMN())
|
||||
f := lookupField(msg, c)
|
||||
if f == nil {
|
||||
return nil, fmt.Errorf("no field %q found in %s", path, root.GetName())
|
||||
}
|
||||
if f.GetLabel() == descriptor.FieldDescriptorProto_LABEL_REPEATED {
|
||||
return nil, fmt.Errorf("repeated field not allowed in field path: %s in %s", f.GetName(), path)
|
||||
}
|
||||
result = append(result, FieldPathComponent{Name: c, Target: f})
|
||||
}
|
||||
return result, nil
|
||||
}
|
1210
vendor/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor/services_test.go
generated
vendored
Normal file
1210
vendor/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor/services_test.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
322
vendor/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor/types.go
generated
vendored
Normal file
322
vendor/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor/types.go
generated
vendored
Normal file
@@ -0,0 +1,322 @@
|
||||
package descriptor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor"
|
||||
gogen "github.com/golang/protobuf/protoc-gen-go/generator"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/httprule"
|
||||
)
|
||||
|
||||
// GoPackage represents a golang package
|
||||
type GoPackage struct {
|
||||
// Path is the package path to the package.
|
||||
Path string
|
||||
// Name is the package name of the package
|
||||
Name string
|
||||
// Alias is an alias of the package unique within the current invokation of grpc-gateway generator.
|
||||
Alias string
|
||||
}
|
||||
|
||||
// Standard returns whether the import is a golang standard package.
|
||||
func (p GoPackage) Standard() bool {
|
||||
return !strings.Contains(p.Path, ".")
|
||||
}
|
||||
|
||||
// String returns a string representation of this package in the form of import line in golang.
|
||||
func (p GoPackage) String() string {
|
||||
if p.Alias == "" {
|
||||
return fmt.Sprintf("%q", p.Path)
|
||||
}
|
||||
return fmt.Sprintf("%s %q", p.Alias, p.Path)
|
||||
}
|
||||
|
||||
// File wraps descriptor.FileDescriptorProto for richer features.
|
||||
type File struct {
|
||||
*descriptor.FileDescriptorProto
|
||||
// GoPkg is the go package of the go file generated from this file..
|
||||
GoPkg GoPackage
|
||||
// Messages is the list of messages defined in this file.
|
||||
Messages []*Message
|
||||
// Enums is the list of enums defined in this file.
|
||||
Enums []*Enum
|
||||
// Services is the list of services defined in this file.
|
||||
Services []*Service
|
||||
}
|
||||
|
||||
// proto2 determines if the syntax of the file is proto2.
|
||||
func (f *File) proto2() bool {
|
||||
return f.Syntax == nil || f.GetSyntax() == "proto2"
|
||||
}
|
||||
|
||||
// Message describes a protocol buffer message types
|
||||
type Message struct {
|
||||
// File is the file where the message is defined
|
||||
File *File
|
||||
// Outers is a list of outer messages if this message is a nested type.
|
||||
Outers []string
|
||||
*descriptor.DescriptorProto
|
||||
Fields []*Field
|
||||
|
||||
// Index is proto path index of this message in File.
|
||||
Index int
|
||||
}
|
||||
|
||||
// FQMN returns a fully qualified message name of this message.
|
||||
func (m *Message) FQMN() string {
|
||||
components := []string{""}
|
||||
if m.File.Package != nil {
|
||||
components = append(components, m.File.GetPackage())
|
||||
}
|
||||
components = append(components, m.Outers...)
|
||||
components = append(components, m.GetName())
|
||||
return strings.Join(components, ".")
|
||||
}
|
||||
|
||||
// GoType returns a go type name for the message type.
|
||||
// It prefixes the type name with the package alias if
|
||||
// its belonging package is not "currentPackage".
|
||||
func (m *Message) GoType(currentPackage string) string {
|
||||
var components []string
|
||||
components = append(components, m.Outers...)
|
||||
components = append(components, m.GetName())
|
||||
|
||||
name := strings.Join(components, "_")
|
||||
if m.File.GoPkg.Path == currentPackage {
|
||||
return name
|
||||
}
|
||||
pkg := m.File.GoPkg.Name
|
||||
if alias := m.File.GoPkg.Alias; alias != "" {
|
||||
pkg = alias
|
||||
}
|
||||
return fmt.Sprintf("%s.%s", pkg, name)
|
||||
}
|
||||
|
||||
// Enum describes a protocol buffer enum types
|
||||
type Enum struct {
|
||||
// File is the file where the enum is defined
|
||||
File *File
|
||||
// Outers is a list of outer messages if this enum is a nested type.
|
||||
Outers []string
|
||||
*descriptor.EnumDescriptorProto
|
||||
|
||||
Index int
|
||||
}
|
||||
|
||||
// FQEN returns a fully qualified enum name of this enum.
|
||||
func (e *Enum) FQEN() string {
|
||||
components := []string{""}
|
||||
if e.File.Package != nil {
|
||||
components = append(components, e.File.GetPackage())
|
||||
}
|
||||
components = append(components, e.Outers...)
|
||||
components = append(components, e.GetName())
|
||||
return strings.Join(components, ".")
|
||||
}
|
||||
|
||||
// Service wraps descriptor.ServiceDescriptorProto for richer features.
|
||||
type Service struct {
|
||||
// File is the file where this service is defined.
|
||||
File *File
|
||||
*descriptor.ServiceDescriptorProto
|
||||
// Methods is the list of methods defined in this service.
|
||||
Methods []*Method
|
||||
}
|
||||
|
||||
// Method wraps descriptor.MethodDescriptorProto for richer features.
|
||||
type Method struct {
|
||||
// Service is the service which this method belongs to.
|
||||
Service *Service
|
||||
*descriptor.MethodDescriptorProto
|
||||
|
||||
// RequestType is the message type of requests to this method.
|
||||
RequestType *Message
|
||||
// ResponseType is the message type of responses from this method.
|
||||
ResponseType *Message
|
||||
Bindings []*Binding
|
||||
}
|
||||
|
||||
// Binding describes how an HTTP endpoint is bound to a gRPC method.
|
||||
type Binding struct {
|
||||
// Method is the method which the endpoint is bound to.
|
||||
Method *Method
|
||||
// Index is a zero-origin index of the binding in the target method
|
||||
Index int
|
||||
// PathTmpl is path template where this method is mapped to.
|
||||
PathTmpl httprule.Template
|
||||
// HTTPMethod is the HTTP method which this method is mapped to.
|
||||
HTTPMethod string
|
||||
// PathParams is the list of parameters provided in HTTP request paths.
|
||||
PathParams []Parameter
|
||||
// Body describes parameters provided in HTTP request body.
|
||||
Body *Body
|
||||
}
|
||||
|
||||
// ExplicitParams returns a list of explicitly bound parameters of "b",
|
||||
// i.e. a union of field path for body and field paths for path parameters.
|
||||
func (b *Binding) ExplicitParams() []string {
|
||||
var result []string
|
||||
if b.Body != nil {
|
||||
result = append(result, b.Body.FieldPath.String())
|
||||
}
|
||||
for _, p := range b.PathParams {
|
||||
result = append(result, p.FieldPath.String())
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Field wraps descriptor.FieldDescriptorProto for richer features.
|
||||
type Field struct {
|
||||
// Message is the message type which this field belongs to.
|
||||
Message *Message
|
||||
// FieldMessage is the message type of the field.
|
||||
FieldMessage *Message
|
||||
*descriptor.FieldDescriptorProto
|
||||
}
|
||||
|
||||
// Parameter is a parameter provided in http requests
|
||||
type Parameter struct {
|
||||
// FieldPath is a path to a proto field which this parameter is mapped to.
|
||||
FieldPath
|
||||
// Target is the proto field which this parameter is mapped to.
|
||||
Target *Field
|
||||
// Method is the method which this parameter is used for.
|
||||
Method *Method
|
||||
}
|
||||
|
||||
// ConvertFuncExpr returns a go expression of a converter function.
|
||||
// The converter function converts a string into a value for the parameter.
|
||||
func (p Parameter) ConvertFuncExpr() (string, error) {
|
||||
tbl := proto3ConvertFuncs
|
||||
if p.Target.Message.File.proto2() {
|
||||
tbl = proto2ConvertFuncs
|
||||
}
|
||||
typ := p.Target.GetType()
|
||||
conv, ok := tbl[typ]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("unsupported field type %s of parameter %s in %s.%s", typ, p.FieldPath, p.Method.Service.GetName(), p.Method.GetName())
|
||||
}
|
||||
return conv, nil
|
||||
}
|
||||
|
||||
// Body describes a http requtest body to be sent to the method.
|
||||
type Body struct {
|
||||
// FieldPath is a path to a proto field which the request body is mapped to.
|
||||
// The request body is mapped to the request type itself if FieldPath is empty.
|
||||
FieldPath FieldPath
|
||||
}
|
||||
|
||||
// RHS returns a right-hand-side expression in go to be used to initialize method request object.
|
||||
// It starts with "msgExpr", which is the go expression of the method request object.
|
||||
func (b Body) RHS(msgExpr string) string {
|
||||
return b.FieldPath.RHS(msgExpr)
|
||||
}
|
||||
|
||||
// FieldPath is a path to a field from a request message.
|
||||
type FieldPath []FieldPathComponent
|
||||
|
||||
// String returns a string representation of the field path.
|
||||
func (p FieldPath) String() string {
|
||||
var components []string
|
||||
for _, c := range p {
|
||||
components = append(components, c.Name)
|
||||
}
|
||||
return strings.Join(components, ".")
|
||||
}
|
||||
|
||||
// IsNestedProto3 indicates whether the FieldPath is a nested Proto3 path.
|
||||
func (p FieldPath) IsNestedProto3() bool {
|
||||
if len(p) > 1 && !p[0].Target.Message.File.proto2() {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RHS is a right-hand-side expression in go to be used to assign a value to the target field.
|
||||
// It starts with "msgExpr", which is the go expression of the method request object.
|
||||
func (p FieldPath) RHS(msgExpr string) string {
|
||||
l := len(p)
|
||||
if l == 0 {
|
||||
return msgExpr
|
||||
}
|
||||
components := []string{msgExpr}
|
||||
for i, c := range p {
|
||||
if i == l-1 {
|
||||
components = append(components, c.RHS())
|
||||
continue
|
||||
}
|
||||
components = append(components, c.LHS())
|
||||
}
|
||||
return strings.Join(components, ".")
|
||||
}
|
||||
|
||||
// FieldPathComponent is a path component in FieldPath
|
||||
type FieldPathComponent struct {
|
||||
// Name is a name of the proto field which this component corresponds to.
|
||||
// TODO(yugui) is this necessary?
|
||||
Name string
|
||||
// Target is the proto field which this component corresponds to.
|
||||
Target *Field
|
||||
}
|
||||
|
||||
// RHS returns a right-hand-side expression in go for this field.
|
||||
func (c FieldPathComponent) RHS() string {
|
||||
return gogen.CamelCase(c.Name)
|
||||
}
|
||||
|
||||
// LHS returns a left-hand-side expression in go for this field.
|
||||
func (c FieldPathComponent) LHS() string {
|
||||
if c.Target.Message.File.proto2() {
|
||||
return fmt.Sprintf("Get%s()", gogen.CamelCase(c.Name))
|
||||
}
|
||||
return gogen.CamelCase(c.Name)
|
||||
}
|
||||
|
||||
var (
|
||||
proto3ConvertFuncs = map[descriptor.FieldDescriptorProto_Type]string{
|
||||
descriptor.FieldDescriptorProto_TYPE_DOUBLE: "runtime.Float64",
|
||||
descriptor.FieldDescriptorProto_TYPE_FLOAT: "runtime.Float32",
|
||||
descriptor.FieldDescriptorProto_TYPE_INT64: "runtime.Int64",
|
||||
descriptor.FieldDescriptorProto_TYPE_UINT64: "runtime.Uint64",
|
||||
descriptor.FieldDescriptorProto_TYPE_INT32: "runtime.Int32",
|
||||
descriptor.FieldDescriptorProto_TYPE_FIXED64: "runtime.Uint64",
|
||||
descriptor.FieldDescriptorProto_TYPE_FIXED32: "runtime.Uint32",
|
||||
descriptor.FieldDescriptorProto_TYPE_BOOL: "runtime.Bool",
|
||||
descriptor.FieldDescriptorProto_TYPE_STRING: "runtime.String",
|
||||
// FieldDescriptorProto_TYPE_GROUP
|
||||
// FieldDescriptorProto_TYPE_MESSAGE
|
||||
// FieldDescriptorProto_TYPE_BYTES
|
||||
// TODO(yugui) Handle bytes
|
||||
descriptor.FieldDescriptorProto_TYPE_UINT32: "runtime.Uint32",
|
||||
// FieldDescriptorProto_TYPE_ENUM
|
||||
// TODO(yugui) Handle Enum
|
||||
descriptor.FieldDescriptorProto_TYPE_SFIXED32: "runtime.Int32",
|
||||
descriptor.FieldDescriptorProto_TYPE_SFIXED64: "runtime.Int64",
|
||||
descriptor.FieldDescriptorProto_TYPE_SINT32: "runtime.Int32",
|
||||
descriptor.FieldDescriptorProto_TYPE_SINT64: "runtime.Int64",
|
||||
}
|
||||
|
||||
proto2ConvertFuncs = map[descriptor.FieldDescriptorProto_Type]string{
|
||||
descriptor.FieldDescriptorProto_TYPE_DOUBLE: "runtime.Float64P",
|
||||
descriptor.FieldDescriptorProto_TYPE_FLOAT: "runtime.Float32P",
|
||||
descriptor.FieldDescriptorProto_TYPE_INT64: "runtime.Int64P",
|
||||
descriptor.FieldDescriptorProto_TYPE_UINT64: "runtime.Uint64P",
|
||||
descriptor.FieldDescriptorProto_TYPE_INT32: "runtime.Int32P",
|
||||
descriptor.FieldDescriptorProto_TYPE_FIXED64: "runtime.Uint64P",
|
||||
descriptor.FieldDescriptorProto_TYPE_FIXED32: "runtime.Uint32P",
|
||||
descriptor.FieldDescriptorProto_TYPE_BOOL: "runtime.BoolP",
|
||||
descriptor.FieldDescriptorProto_TYPE_STRING: "runtime.StringP",
|
||||
// FieldDescriptorProto_TYPE_GROUP
|
||||
// FieldDescriptorProto_TYPE_MESSAGE
|
||||
// FieldDescriptorProto_TYPE_BYTES
|
||||
// TODO(yugui) Handle bytes
|
||||
descriptor.FieldDescriptorProto_TYPE_UINT32: "runtime.Uint32P",
|
||||
// FieldDescriptorProto_TYPE_ENUM
|
||||
// TODO(yugui) Handle Enum
|
||||
descriptor.FieldDescriptorProto_TYPE_SFIXED32: "runtime.Int32P",
|
||||
descriptor.FieldDescriptorProto_TYPE_SFIXED64: "runtime.Int64P",
|
||||
descriptor.FieldDescriptorProto_TYPE_SINT32: "runtime.Int32P",
|
||||
descriptor.FieldDescriptorProto_TYPE_SINT64: "runtime.Int64P",
|
||||
}
|
||||
)
|
206
vendor/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor/types_test.go
generated
vendored
Normal file
206
vendor/github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway/descriptor/types_test.go
generated
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
package descriptor
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor"
|
||||
)
|
||||
|
||||
func TestGoPackageStandard(t *testing.T) {
|
||||
for _, spec := range []struct {
|
||||
pkg GoPackage
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
pkg: GoPackage{Path: "fmt", Name: "fmt"},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
pkg: GoPackage{Path: "encoding/json", Name: "json"},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
pkg: GoPackage{Path: "github.com/golang/protobuf/jsonpb", Name: "jsonpb"},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
pkg: GoPackage{Path: "golang.org/x/net/context", Name: "context"},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
pkg: GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway", Name: "main"},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
pkg: GoPackage{Path: "github.com/google/googleapis/google/api/http.pb", Name: "http_pb", Alias: "htpb"},
|
||||
want: false,
|
||||
},
|
||||
} {
|
||||
if got, want := spec.pkg.Standard(), spec.want; got != want {
|
||||
t.Errorf("%#v.Standard() = %v; want %v", spec.pkg, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestGoPackageString(t *testing.T) {
|
||||
for _, spec := range []struct {
|
||||
pkg GoPackage
|
||||
want string
|
||||
}{
|
||||
{
|
||||
pkg: GoPackage{Path: "fmt", Name: "fmt"},
|
||||
want: `"fmt"`,
|
||||
},
|
||||
{
|
||||
pkg: GoPackage{Path: "encoding/json", Name: "json"},
|
||||
want: `"encoding/json"`,
|
||||
},
|
||||
{
|
||||
pkg: GoPackage{Path: "github.com/golang/protobuf/jsonpb", Name: "jsonpb"},
|
||||
want: `"github.com/golang/protobuf/jsonpb"`,
|
||||
},
|
||||
{
|
||||
pkg: GoPackage{Path: "golang.org/x/net/context", Name: "context"},
|
||||
want: `"golang.org/x/net/context"`,
|
||||
},
|
||||
{
|
||||
pkg: GoPackage{Path: "github.com/grpc-ecosystem/grpc-gateway", Name: "main"},
|
||||
want: `"github.com/grpc-ecosystem/grpc-gateway"`,
|
||||
},
|
||||
{
|
||||
pkg: GoPackage{Path: "github.com/google/googleapis/google/api/http.pb", Name: "http_pb", Alias: "htpb"},
|
||||
want: `htpb "github.com/google/googleapis/google/api/http.pb"`,
|
||||
},
|
||||
} {
|
||||
if got, want := spec.pkg.String(), spec.want; got != want {
|
||||
t.Errorf("%#v.String() = %q; want %q", spec.pkg, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFieldPath(t *testing.T) {
|
||||
var fds []*descriptor.FileDescriptorProto
|
||||
for _, src := range []string{
|
||||
`
|
||||
name: 'example.proto'
|
||||
package: 'example'
|
||||
message_type <
|
||||
name: 'Nest'
|
||||
field <
|
||||
name: 'nest2_field'
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: 'Nest2'
|
||||
number: 1
|
||||
>
|
||||
field <
|
||||
name: 'terminal_field'
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
number: 2
|
||||
>
|
||||
>
|
||||
syntax: "proto3"
|
||||
`, `
|
||||
name: 'another.proto'
|
||||
package: 'example'
|
||||
message_type <
|
||||
name: 'Nest2'
|
||||
field <
|
||||
name: 'nest_field'
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_MESSAGE
|
||||
type_name: 'Nest'
|
||||
number: 1
|
||||
>
|
||||
field <
|
||||
name: 'terminal_field'
|
||||
label: LABEL_OPTIONAL
|
||||
type: TYPE_STRING
|
||||
number: 2
|
||||
>
|
||||
>
|
||||
syntax: "proto2"
|
||||
`,
|
||||
} {
|
||||
var fd descriptor.FileDescriptorProto
|
||||
if err := proto.UnmarshalText(src, &fd); err != nil {
|
||||
t.Fatalf("proto.UnmarshalText(%s, &fd) failed with %v; want success", src, err)
|
||||
}
|
||||
fds = append(fds, &fd)
|
||||
}
|
||||
nest := &Message{
|
||||
DescriptorProto: fds[0].MessageType[0],
|
||||
Fields: []*Field{
|
||||
{FieldDescriptorProto: fds[0].MessageType[0].Field[0]},
|
||||
{FieldDescriptorProto: fds[0].MessageType[0].Field[1]},
|
||||
},
|
||||
}
|
||||
nest2 := &Message{
|
||||
DescriptorProto: fds[1].MessageType[0],
|
||||
Fields: []*Field{
|
||||
{FieldDescriptorProto: fds[1].MessageType[0].Field[0]},
|
||||
{FieldDescriptorProto: fds[1].MessageType[0].Field[1]},
|
||||
},
|
||||
}
|
||||
file1 := &File{
|
||||
FileDescriptorProto: fds[0],
|
||||
GoPkg: GoPackage{Path: "example", Name: "example"},
|
||||
Messages: []*Message{nest},
|
||||
}
|
||||
file2 := &File{
|
||||
FileDescriptorProto: fds[1],
|
||||
GoPkg: GoPackage{Path: "example", Name: "example"},
|
||||
Messages: []*Message{nest2},
|
||||
}
|
||||
crossLinkFixture(file1)
|
||||
crossLinkFixture(file2)
|
||||
|
||||
c1 := FieldPathComponent{
|
||||
Name: "nest_field",
|
||||
Target: nest2.Fields[0],
|
||||
}
|
||||
if got, want := c1.LHS(), "GetNestField()"; got != want {
|
||||
t.Errorf("c1.LHS() = %q; want %q", got, want)
|
||||
}
|
||||
if got, want := c1.RHS(), "NestField"; got != want {
|
||||
t.Errorf("c1.RHS() = %q; want %q", got, want)
|
||||
}
|
||||
|
||||
c2 := FieldPathComponent{
|
||||
Name: "nest2_field",
|
||||
Target: nest.Fields[0],
|
||||
}
|
||||
if got, want := c2.LHS(), "Nest2Field"; got != want {
|
||||
t.Errorf("c2.LHS() = %q; want %q", got, want)
|
||||
}
|
||||
if got, want := c2.LHS(), "Nest2Field"; got != want {
|
||||
t.Errorf("c2.LHS() = %q; want %q", got, want)
|
||||
}
|
||||
|
||||
fp := FieldPath{
|
||||
c1, c2, c1, FieldPathComponent{
|
||||
Name: "terminal_field",
|
||||
Target: nest.Fields[1],
|
||||
},
|
||||
}
|
||||
if got, want := fp.RHS("resp"), "resp.GetNestField().Nest2Field.GetNestField().TerminalField"; got != want {
|
||||
t.Errorf("fp.RHS(%q) = %q; want %q", "resp", got, want)
|
||||
}
|
||||
|
||||
fp2 := FieldPath{
|
||||
c2, c1, c2, FieldPathComponent{
|
||||
Name: "terminal_field",
|
||||
Target: nest2.Fields[1],
|
||||
},
|
||||
}
|
||||
if got, want := fp2.RHS("resp"), "resp.Nest2Field.GetNestField().Nest2Field.TerminalField"; got != want {
|
||||
t.Errorf("fp2.RHS(%q) = %q; want %q", "resp", got, want)
|
||||
}
|
||||
|
||||
var fpEmpty FieldPath
|
||||
if got, want := fpEmpty.RHS("resp"), "resp"; got != want {
|
||||
t.Errorf("fpEmpty.RHS(%q) = %q; want %q", "resp", got, want)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user