bump(github.com/googleapis/gnostic):0c5108395e2de

Pick up performance improvements to OpenAPI serialization.
This commit is contained in:
Clayton Coleman 2017-07-31 01:24:19 -04:00
parent d8205661b7
commit 7a458730d7
No known key found for this signature in database
GPG Key ID: 3D16906B4F1C5CB3
18 changed files with 2099 additions and 309 deletions

6
Godeps/Godeps.json generated
View File

@ -1565,15 +1565,15 @@
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/OpenAPIv2", "ImportPath": "github.com/googleapis/gnostic/OpenAPIv2",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/compiler", "ImportPath": "github.com/googleapis/gnostic/compiler",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/extensions", "ImportPath": "github.com/googleapis/gnostic/extensions",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud", "ImportPath": "github.com/gophercloud/gophercloud",

View File

@ -168,15 +168,15 @@
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/OpenAPIv2", "ImportPath": "github.com/googleapis/gnostic/OpenAPIv2",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/compiler", "ImportPath": "github.com/googleapis/gnostic/compiler",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/extensions", "ImportPath": "github.com/googleapis/gnostic/extensions",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/grpc-ecosystem/go-grpc-prometheus", "ImportPath": "github.com/grpc-ecosystem/go-grpc-prometheus",

View File

@ -392,15 +392,15 @@
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/OpenAPIv2", "ImportPath": "github.com/googleapis/gnostic/OpenAPIv2",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/compiler", "ImportPath": "github.com/googleapis/gnostic/compiler",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/extensions", "ImportPath": "github.com/googleapis/gnostic/extensions",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/gophercloud/gophercloud", "ImportPath": "github.com/gophercloud/gophercloud",

View File

@ -160,15 +160,15 @@
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/OpenAPIv2", "ImportPath": "github.com/googleapis/gnostic/OpenAPIv2",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/compiler", "ImportPath": "github.com/googleapis/gnostic/compiler",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/extensions", "ImportPath": "github.com/googleapis/gnostic/extensions",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/hashicorp/golang-lru", "ImportPath": "github.com/hashicorp/golang-lru",

View File

@ -176,15 +176,15 @@
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/OpenAPIv2", "ImportPath": "github.com/googleapis/gnostic/OpenAPIv2",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/compiler", "ImportPath": "github.com/googleapis/gnostic/compiler",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/extensions", "ImportPath": "github.com/googleapis/gnostic/extensions",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/grpc-ecosystem/go-grpc-prometheus", "ImportPath": "github.com/grpc-ecosystem/go-grpc-prometheus",

View File

@ -180,15 +180,15 @@
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/OpenAPIv2", "ImportPath": "github.com/googleapis/gnostic/OpenAPIv2",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/compiler", "ImportPath": "github.com/googleapis/gnostic/compiler",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/extensions", "ImportPath": "github.com/googleapis/gnostic/extensions",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/juju/ratelimit", "ImportPath": "github.com/juju/ratelimit",

View File

@ -88,15 +88,15 @@
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/OpenAPIv2", "ImportPath": "github.com/googleapis/gnostic/OpenAPIv2",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/compiler", "ImportPath": "github.com/googleapis/gnostic/compiler",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/extensions", "ImportPath": "github.com/googleapis/gnostic/extensions",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/juju/ratelimit", "ImportPath": "github.com/juju/ratelimit",

View File

@ -168,15 +168,15 @@
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/OpenAPIv2", "ImportPath": "github.com/googleapis/gnostic/OpenAPIv2",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/compiler", "ImportPath": "github.com/googleapis/gnostic/compiler",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/googleapis/gnostic/extensions", "ImportPath": "github.com/googleapis/gnostic/extensions",
"Rev": "68f4ded48ba9414dab2ae69b3f0d69971da73aa5" "Rev": "0c5108395e2debce0d731cf0287ddf7242066aba"
}, },
{ {
"ImportPath": "github.com/grpc-ecosystem/go-grpc-prometheus", "ImportPath": "github.com/grpc-ecosystem/go-grpc-prometheus",

File diff suppressed because it is too large Load Diff

View File

@ -1376,7 +1376,7 @@ func (m *ItemsItem) GetSchema() []*Schema {
} }
type JsonReference struct { type JsonReference struct {
XRef string `protobuf:"bytes,1,opt,name=_ref,json=ref" json:"_ref,omitempty"` XRef string `protobuf:"bytes,1,opt,name=_ref,json=Ref" json:"_ref,omitempty"`
Description string `protobuf:"bytes,2,opt,name=description" json:"description,omitempty"` Description string `protobuf:"bytes,2,opt,name=description" json:"description,omitempty"`
} }
@ -2513,7 +2513,7 @@ func _ParametersItem_OneofSizer(msg proto.Message) (n int) {
} }
type PathItem struct { type PathItem struct {
XRef string `protobuf:"bytes,1,opt,name=_ref,json=ref" json:"_ref,omitempty"` XRef string `protobuf:"bytes,1,opt,name=_ref,json=Ref" json:"_ref,omitempty"`
Get *Operation `protobuf:"bytes,2,opt,name=get" json:"get,omitempty"` Get *Operation `protobuf:"bytes,2,opt,name=get" json:"get,omitempty"`
Put *Operation `protobuf:"bytes,3,opt,name=put" json:"put,omitempty"` Put *Operation `protobuf:"bytes,3,opt,name=put" json:"put,omitempty"`
Post *Operation `protobuf:"bytes,4,opt,name=post" json:"post,omitempty"` Post *Operation `protobuf:"bytes,4,opt,name=post" json:"post,omitempty"`
@ -3392,7 +3392,7 @@ func (m *Responses) GetVendorExtension() []*NamedAny {
// A deterministic version of a JSON Schema object. // A deterministic version of a JSON Schema object.
type Schema struct { type Schema struct {
XRef string `protobuf:"bytes,1,opt,name=_ref,json=ref" json:"_ref,omitempty"` XRef string `protobuf:"bytes,1,opt,name=_ref,json=Ref" json:"_ref,omitempty"`
Format string `protobuf:"bytes,2,opt,name=format" json:"format,omitempty"` Format string `protobuf:"bytes,2,opt,name=format" json:"format,omitempty"`
Title string `protobuf:"bytes,3,opt,name=title" json:"title,omitempty"` Title string `protobuf:"bytes,3,opt,name=title" json:"title,omitempty"`
Description string `protobuf:"bytes,4,opt,name=description" json:"description,omitempty"` Description string `protobuf:"bytes,4,opt,name=description" json:"description,omitempty"`
@ -4351,7 +4351,7 @@ var fileDescriptor0 = []byte{
0xfe, 0x90, 0x83, 0x0c, 0x89, 0xa3, 0x14, 0x7e, 0x7d, 0x1e, 0xe1, 0xbf, 0x05, 0x4d, 0xa6, 0x0c, 0xfe, 0x90, 0x83, 0x0c, 0x89, 0xa3, 0x14, 0x7e, 0x7d, 0x1e, 0xe1, 0xbf, 0x05, 0x4d, 0xa6, 0x0c,
0xac, 0x56, 0x77, 0x23, 0x51, 0xab, 0x2b, 0x4f, 0x2e, 0xac, 0x6c, 0xdd, 0x85, 0xd6, 0x37, 0x02, 0xac, 0x56, 0x77, 0x23, 0x51, 0xab, 0x2b, 0x4f, 0x2e, 0xac, 0x6c, 0xdd, 0x85, 0xd6, 0x37, 0x02,
0xe2, 0x1a, 0x78, 0x80, 0x7d, 0xec, 0xf6, 0xb0, 0xb6, 0x0c, 0x15, 0xd3, 0xc7, 0x03, 0x21, 0xe3, 0xe2, 0x1a, 0x78, 0x80, 0x7d, 0xec, 0xf6, 0xb0, 0xb6, 0x0c, 0x15, 0xd3, 0xc7, 0x03, 0x21, 0xe3,
0xb2, 0x8f, 0x07, 0xd3, 0xeb, 0x4f, 0x5b, 0x1e, 0xd4, 0xc5, 0x33, 0xcd, 0x58, 0x5c, 0x39, 0xf3, 0xb2, 0x81, 0x07, 0xd3, 0xeb, 0x4f, 0x5b, 0x1e, 0xd4, 0xc5, 0x33, 0xcd, 0x58, 0x5c, 0x39, 0xf3,
0x59, 0xe6, 0x1e, 0x34, 0x24, 0x50, 0xb9, 0xe5, 0x2b, 0xb2, 0xaa, 0x58, 0x52, 0x3b, 0x20, 0x0e, 0x59, 0xe6, 0x1e, 0x34, 0x24, 0x50, 0xb9, 0xe5, 0x2b, 0xb2, 0xaa, 0x58, 0x52, 0x3b, 0x20, 0x0e,
0xdd, 0x7a, 0x17, 0x16, 0x12, 0x0a, 0xa8, 0xa4, 0x74, 0x2d, 0x4d, 0x29, 0x25, 0x4c, 0xa1, 0xb7, 0xdd, 0x7a, 0x17, 0x16, 0x12, 0x0a, 0xa8, 0xa4, 0x74, 0x2d, 0x4d, 0x29, 0x25, 0x4c, 0xa1, 0xb7,
0x82, 0xd8, 0xfb, 0xd0, 0x66, 0xc4, 0xe2, 0x22, 0x9a, 0x8a, 0xde, 0xeb, 0x69, 0x7a, 0x17, 0x94, 0x82, 0xd8, 0xfb, 0xd0, 0x66, 0xc4, 0xe2, 0x22, 0x9a, 0x8a, 0xde, 0xeb, 0x69, 0x7a, 0x17, 0x94,
@ -4452,5 +4452,5 @@ var fileDescriptor0 = []byte{
0xf3, 0x70, 0x5f, 0x1c, 0xc1, 0xe5, 0xf0, 0xcc, 0x7d, 0xcc, 0xdb, 0xaf, 0x42, 0x9b, 0xf8, 0x47, 0xf3, 0x70, 0x5f, 0x1c, 0xc1, 0xe5, 0xf0, 0xcc, 0x7d, 0xcc, 0xdb, 0xaf, 0x42, 0x9b, 0xf8, 0x47,
0x12, 0xd7, 0x3c, 0xd9, 0xb9, 0xbd, 0x28, 0xbe, 0x5d, 0xdd, 0xf7, 0x49, 0x48, 0xf6, 0x8b, 0xbf, 0x12, 0xd7, 0x3c, 0xd9, 0xb9, 0xbd, 0x28, 0xbe, 0x5d, 0xdd, 0xf7, 0x49, 0x48, 0xf6, 0x8b, 0xbf,
0x28, 0x95, 0xf7, 0x76, 0x0f, 0x0e, 0x6b, 0xec, 0x63, 0xd0, 0x37, 0xff, 0x19, 0x00, 0x00, 0xff, 0x28, 0x95, 0xf7, 0x76, 0x0f, 0x0e, 0x6b, 0xec, 0x63, 0xd0, 0x37, 0xff, 0x19, 0x00, 0x00, 0xff,
0xff, 0x3c, 0x01, 0x3f, 0x38, 0xe4, 0x3a, 0x00, 0x00, 0xff, 0xd4, 0x0a, 0xef, 0xca, 0xe4, 0x3a, 0x00, 0x00,
} }

View File

@ -14,28 +14,30 @@
package compiler package compiler
// Context contains state of the compiler as it traverses a document.
type Context struct { type Context struct {
Parent *Context Parent *Context
Name string Name string
ExtensionHandlers *[]ExtensionHandler ExtensionHandlers *[]ExtensionHandler
} }
// NewContextWithExtensions returns a new object representing the compiler state
func NewContextWithExtensions(name string, parent *Context, extensionHandlers *[]ExtensionHandler) *Context { func NewContextWithExtensions(name string, parent *Context, extensionHandlers *[]ExtensionHandler) *Context {
return &Context{Name: name, Parent: parent, ExtensionHandlers: extensionHandlers} return &Context{Name: name, Parent: parent, ExtensionHandlers: extensionHandlers}
} }
// NewContext returns a new object representing the compiler state
func NewContext(name string, parent *Context) *Context { func NewContext(name string, parent *Context) *Context {
if parent != nil { if parent != nil {
return &Context{Name: name, Parent: parent, ExtensionHandlers: parent.ExtensionHandlers} return &Context{Name: name, Parent: parent, ExtensionHandlers: parent.ExtensionHandlers}
} else {
return &Context{Name: name, Parent: parent, ExtensionHandlers: nil}
} }
return &Context{Name: name, Parent: parent, ExtensionHandlers: nil}
} }
// Description returns a text description of the compiler state
func (context *Context) Description() string { func (context *Context) Description() string {
if context.Parent != nil { if context.Parent != nil {
return context.Parent.Description() + "." + context.Name return context.Parent.Description() + "." + context.Name
} else {
return context.Name
} }
return context.Name
} }

View File

@ -14,29 +14,31 @@
package compiler package compiler
// basic error type // Error represents compiler errors and their location in the document.
type Error struct { type Error struct {
Context *Context Context *Context
Message string Message string
} }
// NewError creates an Error.
func NewError(context *Context, message string) *Error { func NewError(context *Context, message string) *Error {
return &Error{Context: context, Message: message} return &Error{Context: context, Message: message}
} }
// Error returns the string value of an Error.
func (err *Error) Error() string { func (err *Error) Error() string {
if err.Context != nil { if err.Context == nil {
return "ERROR " + err.Context.Description() + " " + err.Message
} else {
return "ERROR " + err.Message return "ERROR " + err.Message
} }
return "ERROR " + err.Context.Description() + " " + err.Message
} }
// container for groups of errors // ErrorGroup is a container for groups of Error values.
type ErrorGroup struct { type ErrorGroup struct {
Errors []error Errors []error
} }
// NewErrorGroupOrNil returns a new ErrorGroup for a slice of errors or nil if the slice is empty.
func NewErrorGroupOrNil(errors []error) error { func NewErrorGroupOrNil(errors []error) error {
if len(errors) == 0 { if len(errors) == 0 {
return nil return nil

View File

@ -29,16 +29,18 @@ import (
yaml "gopkg.in/yaml.v2" yaml "gopkg.in/yaml.v2"
) )
// ExtensionHandler describes a binary that is called by the compiler to handle specification extensions.
type ExtensionHandler struct { type ExtensionHandler struct {
Name string Name string
} }
// HandleExtension calls a binary extension handler.
func HandleExtension(context *Context, in interface{}, extensionName string) (bool, *any.Any, error) { func HandleExtension(context *Context, in interface{}, extensionName string) (bool, *any.Any, error) {
handled := false handled := false
var errFromPlugin error var errFromPlugin error
var outFromPlugin *any.Any var outFromPlugin *any.Any
if context.ExtensionHandlers != nil && len(*(context.ExtensionHandlers)) != 0 { if context != nil && context.ExtensionHandlers != nil && len(*(context.ExtensionHandlers)) != 0 {
for _, customAnyProtoGenerator := range *(context.ExtensionHandlers) { for _, customAnyProtoGenerator := range *(context.ExtensionHandlers) {
outFromPlugin, errFromPlugin = customAnyProtoGenerator.handle(in, extensionName) outFromPlugin, errFromPlugin = customAnyProtoGenerator.handle(in, extensionName)
if outFromPlugin == nil { if outFromPlugin == nil {

View File

@ -19,27 +19,27 @@ import (
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
"regexp" "regexp"
"sort" "sort"
"strings" "strconv"
) )
// compiler helper functions, usually called from generated code // compiler helper functions, usually called from generated code
// UnpackMap gets a yaml.MapSlice if possible.
func UnpackMap(in interface{}) (yaml.MapSlice, bool) { func UnpackMap(in interface{}) (yaml.MapSlice, bool) {
m, ok := in.(yaml.MapSlice) m, ok := in.(yaml.MapSlice)
if ok { if ok {
return m, ok return m, true
} else {
// do we have an empty array?
a, ok := in.([]interface{})
if ok && len(a) == 0 {
// if so, return an empty map
return yaml.MapSlice{}, ok
} else {
return nil, ok
}
} }
// do we have an empty array?
a, ok := in.([]interface{})
if ok && len(a) == 0 {
// if so, return an empty map
return yaml.MapSlice{}, true
}
return nil, false
} }
// SortedKeysForMap returns the sorted keys of a yaml.MapSlice.
func SortedKeysForMap(m yaml.MapSlice) []string { func SortedKeysForMap(m yaml.MapSlice) []string {
keys := make([]string, 0) keys := make([]string, 0)
for _, item := range m { for _, item := range m {
@ -49,6 +49,7 @@ func SortedKeysForMap(m yaml.MapSlice) []string {
return keys return keys
} }
// MapHasKey returns true if a yaml.MapSlice contains a specified key.
func MapHasKey(m yaml.MapSlice, key string) bool { func MapHasKey(m yaml.MapSlice, key string) bool {
for _, item := range m { for _, item := range m {
itemKey, ok := item.Key.(string) itemKey, ok := item.Key.(string)
@ -59,6 +60,7 @@ func MapHasKey(m yaml.MapSlice, key string) bool {
return false return false
} }
// MapValueForKey gets the value of a map value for a specified key.
func MapValueForKey(m yaml.MapSlice, key string) interface{} { func MapValueForKey(m yaml.MapSlice, key string) interface{} {
for _, item := range m { for _, item := range m {
itemKey, ok := item.Key.(string) itemKey, ok := item.Key.(string)
@ -69,6 +71,7 @@ func MapValueForKey(m yaml.MapSlice, key string) interface{} {
return nil return nil
} }
// ConvertInterfaceArrayToStringArray converts an array of interfaces to an array of strings, if possible.
func ConvertInterfaceArrayToStringArray(interfaceArray []interface{}) []string { func ConvertInterfaceArrayToStringArray(interfaceArray []interface{}) []string {
stringArray := make([]string, 0) stringArray := make([]string, 0)
for _, item := range interfaceArray { for _, item := range interfaceArray {
@ -80,22 +83,7 @@ func ConvertInterfaceArrayToStringArray(interfaceArray []interface{}) []string {
return stringArray return stringArray
} }
func PatternMatches(pattern string, value string) bool { // MissingKeysInMap identifies which keys from a list of required keys are not in a map.
// if pattern contains a subpattern like "{path}", replace it with ".*"
if pattern[0] != '^' {
subpatternPattern := regexp.MustCompile("^.*(\\{.*\\}).*$")
if matches := subpatternPattern.FindSubmatch([]byte(pattern)); matches != nil {
match := string(matches[1])
pattern = strings.Replace(pattern, match, ".*", -1)
}
}
matched, err := regexp.Match(pattern, []byte(value))
if err != nil {
panic(err)
}
return matched
}
func MissingKeysInMap(m yaml.MapSlice, requiredKeys []string) []string { func MissingKeysInMap(m yaml.MapSlice, requiredKeys []string) []string {
missingKeys := make([]string, 0) missingKeys := make([]string, 0)
for _, k := range requiredKeys { for _, k := range requiredKeys {
@ -106,7 +94,8 @@ func MissingKeysInMap(m yaml.MapSlice, requiredKeys []string) []string {
return missingKeys return missingKeys
} }
func InvalidKeysInMap(m yaml.MapSlice, allowedKeys []string, allowedPatterns []string) []string { // InvalidKeysInMap returns keys in a map that don't match a list of allowed keys and patterns.
func InvalidKeysInMap(m yaml.MapSlice, allowedKeys []string, allowedPatterns []*regexp.Regexp) []string {
invalidKeys := make([]string, 0) invalidKeys := make([]string, 0)
for _, item := range m { for _, item := range m {
itemKey, ok := item.Key.(string) itemKey, ok := item.Key.(string)
@ -123,7 +112,7 @@ func InvalidKeysInMap(m yaml.MapSlice, allowedKeys []string, allowedPatterns []s
if !found { if !found {
// does the key match an allowed pattern? // does the key match an allowed pattern?
for _, allowedPattern := range allowedPatterns { for _, allowedPattern := range allowedPatterns {
if PatternMatches(allowedPattern, key) { if allowedPattern.MatchString(key) {
found = true found = true
break break
} }
@ -137,13 +126,13 @@ func InvalidKeysInMap(m yaml.MapSlice, allowedKeys []string, allowedPatterns []s
return invalidKeys return invalidKeys
} }
// describe a map (for debugging purposes) // DescribeMap describes a map (for debugging purposes).
func DescribeMap(in interface{}, indent string) string { func DescribeMap(in interface{}, indent string) string {
description := "" description := ""
m, ok := in.(map[string]interface{}) m, ok := in.(map[string]interface{})
if ok { if ok {
keys := make([]string, 0) keys := make([]string, 0)
for k, _ := range m { for k := range m {
keys = append(keys, k) keys = append(keys, k)
} }
sort.Strings(keys) sort.Strings(keys)
@ -166,14 +155,15 @@ func DescribeMap(in interface{}, indent string) string {
return description return description
} }
// PluralProperties returns the string "properties" pluralized.
func PluralProperties(count int) string { func PluralProperties(count int) string {
if count == 1 { if count == 1 {
return "property" return "property"
} else {
return "properties"
} }
return "properties"
} }
// StringArrayContainsValue returns true if a string array contains a specified value.
func StringArrayContainsValue(array []string, value string) bool { func StringArrayContainsValue(array []string, value string) bool {
for _, item := range array { for _, item := range array {
if item == value { if item == value {
@ -183,6 +173,7 @@ func StringArrayContainsValue(array []string, value string) bool {
return false return false
} }
// StringArrayContainsValues returns true if a string array contains all of a list of specified values.
func StringArrayContainsValues(array []string, values []string) bool { func StringArrayContainsValues(array []string, values []string) bool {
for _, value := range values { for _, value := range values {
if !StringArrayContainsValue(array, value) { if !StringArrayContainsValue(array, value) {
@ -191,3 +182,16 @@ func StringArrayContainsValues(array []string, values []string) bool {
} }
return true return true
} }
// StringValue returns the string value of an item.
func StringValue(item interface{}) (value string, ok bool) {
value, ok = item.(string)
if ok {
return value, ok
}
intValue, ok := item.(int)
if ok {
return strconv.Itoa(intValue), true
}
return "", false
}

View File

@ -25,29 +25,30 @@ import (
"strings" "strings"
) )
var file_cache map[string][]byte var fileCache map[string][]byte
var info_cache map[string]interface{} var infoCache map[string]interface{}
var count int64 var count int64
var VERBOSE_READER = false var verboseReader = false
func initializeFileCache() { func initializeFileCache() {
if file_cache == nil { if fileCache == nil {
file_cache = make(map[string][]byte, 0) fileCache = make(map[string][]byte, 0)
} }
} }
func initializeInfoCache() { func initializeInfoCache() {
if info_cache == nil { if infoCache == nil {
info_cache = make(map[string]interface{}, 0) infoCache = make(map[string]interface{}, 0)
} }
} }
// FetchFile gets a specified file from the local filesystem or a remote location.
func FetchFile(fileurl string) ([]byte, error) { func FetchFile(fileurl string) ([]byte, error) {
initializeFileCache() initializeFileCache()
bytes, ok := file_cache[fileurl] bytes, ok := fileCache[fileurl]
if ok { if ok {
if VERBOSE_READER { if verboseReader {
log.Printf("Cache hit %s", fileurl) log.Printf("Cache hit %s", fileurl)
} }
return bytes, nil return bytes, nil
@ -56,30 +57,17 @@ func FetchFile(fileurl string) ([]byte, error) {
response, err := http.Get(fileurl) response, err := http.Get(fileurl)
if err != nil { if err != nil {
return nil, err return nil, err
} else {
defer response.Body.Close()
bytes, err := ioutil.ReadAll(response.Body)
if err == nil {
file_cache[fileurl] = bytes
}
return bytes, err
} }
defer response.Body.Close()
bytes, err = ioutil.ReadAll(response.Body)
if err == nil {
fileCache[fileurl] = bytes
}
return bytes, err
} }
// read a file and unmarshal it as a yaml.MapSlice // ReadBytesForFile reads the bytes of a file.
func ReadInfoForFile(filename string) (interface{}, error) { func ReadBytesForFile(filename string) ([]byte, error) {
initializeInfoCache()
info, ok := info_cache[filename]
if ok {
if VERBOSE_READER {
log.Printf("Cache hit info for file %s", filename)
}
return info, nil
}
if VERBOSE_READER {
log.Printf("Reading info for file %s", filename)
}
// is the filename a url? // is the filename a url?
fileurl, _ := url.Parse(filename) fileurl, _ := url.Parse(filename)
if fileurl.Scheme != "" { if fileurl.Scheme != "" {
@ -88,43 +76,51 @@ func ReadInfoForFile(filename string) (interface{}, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
var info yaml.MapSlice return bytes, nil
err = yaml.Unmarshal(bytes, &info)
if err != nil {
return nil, err
}
info_cache[filename] = info
return info, nil
} else {
// no, it's a local filename
bytes, err := ioutil.ReadFile(filename)
if err != nil {
log.Printf("File error: %v\n", err)
return nil, err
}
var info yaml.MapSlice
err = yaml.Unmarshal(bytes, &info)
if err != nil {
return nil, err
}
info_cache[filename] = info
return info, nil
} }
// no, it's a local filename
bytes, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
return bytes, nil
} }
// read a file and return the fragment needed to resolve a $ref // ReadInfoFromBytes unmarshals a file as a yaml.MapSlice.
func ReadInfoFromBytes(filename string, bytes []byte) (interface{}, error) {
initializeInfoCache()
cachedInfo, ok := infoCache[filename]
if ok {
if verboseReader {
log.Printf("Cache hit info for file %s", filename)
}
return cachedInfo, nil
}
if verboseReader {
log.Printf("Reading info for file %s", filename)
}
var info yaml.MapSlice
err := yaml.Unmarshal(bytes, &info)
if err != nil {
return nil, err
}
infoCache[filename] = info
return info, nil
}
// ReadInfoForRef reads a file and return the fragment needed to resolve a $ref.
func ReadInfoForRef(basefile string, ref string) (interface{}, error) { func ReadInfoForRef(basefile string, ref string) (interface{}, error) {
initializeInfoCache() initializeInfoCache()
{ {
info, ok := info_cache[ref] info, ok := infoCache[ref]
if ok { if ok {
if VERBOSE_READER { if verboseReader {
log.Printf("Cache hit for ref %s#%s", basefile, ref) log.Printf("Cache hit for ref %s#%s", basefile, ref)
} }
return info, nil return info, nil
} }
} }
if VERBOSE_READER { if verboseReader {
log.Printf("Reading info for ref %s#%s", basefile, ref) log.Printf("Reading info for ref %s#%s", basefile, ref)
} }
count = count + 1 count = count + 1
@ -136,7 +132,11 @@ func ReadInfoForRef(basefile string, ref string) (interface{}, error) {
} else { } else {
filename = basefile filename = basefile
} }
info, err := ReadInfoForFile(filename) bytes, err := ReadBytesForFile(filename)
if err != nil {
return nil, err
}
info, err := ReadInfoFromBytes(filename, bytes)
if err != nil { if err != nil {
log.Printf("File error: %v\n", err) log.Printf("File error: %v\n", err)
} else { } else {
@ -154,7 +154,7 @@ func ReadInfoForRef(basefile string, ref string) (interface{}, error) {
} }
} }
if !found { if !found {
info_cache[ref] = nil infoCache[ref] = nil
return nil, NewError(nil, fmt.Sprintf("could not resolve %s", ref)) return nil, NewError(nil, fmt.Sprintf("could not resolve %s", ref))
} }
} }
@ -162,6 +162,6 @@ func ReadInfoForRef(basefile string, ref string) (interface{}, error) {
} }
} }
} }
info_cache[ref] = info infoCache[ref] = info
return info, nil return info, nil
} }

View File

@ -18,7 +18,6 @@ go_library(
"//vendor/github.com/golang/protobuf/proto:go_default_library", "//vendor/github.com/golang/protobuf/proto:go_default_library",
"//vendor/github.com/golang/protobuf/ptypes:go_default_library", "//vendor/github.com/golang/protobuf/ptypes:go_default_library",
"//vendor/github.com/golang/protobuf/ptypes/any:go_default_library", "//vendor/github.com/golang/protobuf/ptypes/any:go_default_library",
"//vendor/gopkg.in/yaml.v2:go_default_library",
], ],
) )

View File

@ -3,5 +3,3 @@ go get github.com/golang/protobuf/protoc-gen-go
protoc \ protoc \
--go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. *.proto --go_out=Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. *.proto
go build
go install

View File

@ -21,40 +21,39 @@ import (
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes" "github.com/golang/protobuf/ptypes"
"gopkg.in/yaml.v2"
) )
type documentHandler func(version string, extensionName string, document string) type documentHandler func(version string, extensionName string, document string)
type extensionHandler func(name string, info yaml.MapSlice) (bool, proto.Message, error) type extensionHandler func(name string, yamlInput string) (bool, proto.Message, error)
func forInputYamlFromOpenapic(handler documentHandler) { func forInputYamlFromOpenapic(handler documentHandler) {
data, err := ioutil.ReadAll(os.Stdin) data, err := ioutil.ReadAll(os.Stdin)
if err != nil { if err != nil {
fmt.Println("File error:", err.Error()) fmt.Println("File error:", err.Error())
os.Exit(1) os.Exit(1)
} }
if len(data) == 0 {
fmt.Println("No input data.")
os.Exit(1)
}
request := &ExtensionHandlerRequest{} request := &ExtensionHandlerRequest{}
err = proto.Unmarshal(data, request) err = proto.Unmarshal(data, request)
if err != nil {
fmt.Println("Input error:", err.Error())
os.Exit(1)
}
handler(request.Wrapper.Version, request.Wrapper.ExtensionName, request.Wrapper.Yaml) handler(request.Wrapper.Version, request.Wrapper.ExtensionName, request.Wrapper.Yaml)
} }
// ProcessExtension calles the handler for a specified extension.
func ProcessExtension(handleExtension extensionHandler) { func ProcessExtension(handleExtension extensionHandler) {
response := &ExtensionHandlerResponse{} response := &ExtensionHandlerResponse{}
forInputYamlFromOpenapic( forInputYamlFromOpenapic(
func(version string, extensionName string, yamlInput string) { func(version string, extensionName string, yamlInput string) {
var info yaml.MapSlice
var newObject proto.Message var newObject proto.Message
var err error var err error
err = yaml.Unmarshal([]byte(yamlInput), &info)
if err != nil {
response.Error = append(response.Error, err.Error())
responseBytes, _ := proto.Marshal(response)
os.Stdout.Write(responseBytes)
os.Exit(0)
}
handled, newObject, err := handleExtension(extensionName, info) handled, newObject, err := handleExtension(extensionName, yamlInput)
if !handled { if !handled {
responseBytes, _ := proto.Marshal(response) responseBytes, _ := proto.Marshal(response)
os.Stdout.Write(responseBytes) os.Stdout.Write(responseBytes)