Update go dep (#1560)

This fix updates go dep with `dep ensure --update` as well as the following:
- Removed github.com/ugorji/go restriction in Gopkg.toml (fixes  #1557)
- Added github.com/flynn/go-shlex in Makefile (neede by Caddy, maybe removed later)

This fix fixes #1557

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
This commit is contained in:
Yong Tang
2018-02-23 12:10:34 -08:00
committed by Miek Gieben
parent 9047bdf3a0
commit 604c0045e7
563 changed files with 107278 additions and 95314 deletions

View File

@@ -16,9 +16,7 @@ package spec
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"log"
"net/url"
"os"
@@ -320,6 +318,17 @@ func debugLog(msg string, args ...interface{}) {
}
}
// normalize absolute path for cache.
// on Windows, drive letters should be converted to lower as scheme in net/url.URL
func normalizeAbsPath(path string) string {
u, err := url.Parse(path)
if err != nil {
debugLog("normalize absolute path failed: %s", err)
return path
}
return u.String()
}
// base or refPath could be a file path or a URL
// given a base absolute path and a ref path, return the absolute path of refPath
// 1) if refPath is absolute, return it
@@ -379,32 +388,29 @@ func (r *schemaLoader) resolveRef(ref *Ref, target interface{}, basePath string)
return nil
}
// if no basePath is provided, we attempt to resolve the reference against root
if basePath == "" {
var b []byte
switch rr := r.root.(type) {
case *Schema:
b, _ = rr.MarshalJSON()
case *Swagger:
b, _ = rr.MarshalJSON()
var res interface{}
var data interface{}
var err error
// Resolve against the root if it isn't nil, and if ref is pointing at the root, or has a fragment only which means
// it is pointing somewhere in the root.
root := r.root
if (ref.IsRoot() || ref.HasFragmentOnly) && root == nil && basePath != "" {
if baseRef, err := NewRef(basePath); err == nil {
root, _, _, _ = r.load(baseRef.GetURL())
}
f, err := ioutil.TempFile(os.TempDir(), "tmproot")
}
if (ref.IsRoot() || ref.HasFragmentOnly) && root != nil {
data = root
} else {
baseRef := normalizeFileRef(ref, basePath)
debugLog("current ref is: %s", ref.String())
debugLog("current ref normalized file: %s", baseRef.String())
data, _, _, err = r.load(baseRef.GetURL())
if err != nil {
return err
}
f.Write(b)
f.Close()
basePath = f.Name()
}
baseRef := normalizeFileRef(ref, basePath)
debugLog("current ref normalized file: %s", baseRef.String())
data, _, _, err := r.load(baseRef.GetURL())
if err != nil {
return err
}
var res interface{}
res = data
if ref.String() != "" {
res, _, err = ref.GetPointer().Get(data)
@@ -415,6 +421,7 @@ func (r *schemaLoader) resolveRef(ref *Ref, target interface{}, basePath string)
if err := swag.DynamicJSONToStruct(res, target); err != nil {
return err
}
return nil
}
@@ -449,6 +456,9 @@ func (r *schemaLoader) Resolve(ref *Ref, target interface{}, basePath string) er
// absPath returns the absolute path of a file
func absPath(fname string) (string, error) {
if strings.HasPrefix(fname, "http") {
return fname, nil
}
if filepath.IsAbs(fname) {
return fname, nil
}
@@ -471,11 +481,10 @@ func ExpandSpec(spec *Swagger, options *ExpandOptions) error {
}
if options == nil || !options.SkipSchemas {
rt := fmt.Sprintf("%s#/definitions/", specBasePath)
for key, definition := range spec.Definitions {
var def *Schema
var err error
if def, err = expandSchema(definition, []string{rt + key}, resolver, specBasePath); shouldStopOnError(err, resolver.options) {
if def, err = expandSchema(definition, []string{fmt.Sprintf("#/defintions/%s", key)}, resolver, specBasePath); shouldStopOnError(err, resolver.options) {
return err
}
if def != nil {
@@ -526,29 +535,19 @@ func shouldStopOnError(err error, opts *ExpandOptions) bool {
// go-openapi/validate uses this function
// notice that it is impossible to reference a json scema in a different file other than root
func ExpandSchema(schema *Schema, root interface{}, cache ResolutionCache) error {
// if root is passed as nil, assume root is the same as schema
if root == nil {
root = schema
// Only save the root to a tmp file if it isn't nil.
var base string
if root != nil {
base, _ = absPath("root")
if cache == nil {
cache = resCache
}
cache.Set(normalizeAbsPath(base), root)
base = "root"
}
file, err := ioutil.TempFile(os.TempDir(), "root")
if err != nil {
return err
}
defer os.Remove(file.Name())
switch r := root.(type) {
case *Schema:
b, _ := r.MarshalJSON()
file.Write(b)
case *Swagger:
b, _ := r.MarshalJSON()
file.Write(b)
}
file.Close()
opts := &ExpandOptions{
RelativeBase: file.Name(),
RelativeBase: base,
SkipSchemas: false,
ContinueOnError: false,
}
@@ -561,14 +560,10 @@ func ExpandSchemaWithBasePath(schema *Schema, cache ResolutionCache, opts *Expan
return nil
}
if opts == nil {
return errors.New("cannot expand schema without a base path")
var basePath string
if opts.RelativeBase != "" {
basePath, _ = absPath(opts.RelativeBase)
}
if opts.RelativeBase == "" {
return errors.New("cannot expand schema with empty base path")
}
basePath, _ := absPath(opts.RelativeBase)
resolver, err := defaultSchemaLoader(nil, opts, cache)
if err != nil {
@@ -622,6 +617,10 @@ func basePathFromSchemaID(oldBasePath, id string) string {
return u.String()
}
func isCircular(ref *Ref, basePath string, parentRefs ...string) bool {
return basePath != "" && swag.ContainsStringsCI(parentRefs, ref.String())
}
func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, basePath string) (*Schema, error) {
if target.Ref.String() == "" && target.Ref.IsRoot() {
// normalizing is important
@@ -657,14 +656,16 @@ func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, ba
/* this means there is a circle in the recursion tree */
/* return the Ref */
if basePath != "" && swag.ContainsStringsCI(parentRefs, normalizedRef.String()) {
if isCircular(normalizedRef, basePath, parentRefs...) {
target.Ref = *normalizedRef
return &target, nil
}
debugLog("\nbasePath: %s", basePath)
b, _ := json.Marshal(target)
debugLog("calling Resolve with target: %s", string(b))
if Debug {
b, _ := json.Marshal(target)
debugLog("calling Resolve with target: %s", string(b))
}
if err := resolver.Resolve(&target.Ref, &t, basePath); shouldStopOnError(err, resolver.options) {
return nil, err
}
@@ -774,17 +775,41 @@ func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader, ba
return &target, nil
}
func derefPathItem(pathItem *PathItem, parentRefs []string, resolver *schemaLoader, basePath string) error {
curRef := pathItem.Ref.String()
if curRef != "" {
normalizedRef := normalizeFileRef(&pathItem.Ref, basePath)
normalizedBasePath := normalizedRef.RemoteURI()
if isCircular(normalizedRef, basePath, parentRefs...) {
return nil
}
if err := resolver.Resolve(&pathItem.Ref, pathItem, basePath); shouldStopOnError(err, resolver.options) {
return err
}
if pathItem.Ref.String() != "" && pathItem.Ref.String() != curRef && basePath != normalizedBasePath {
parentRefs = append(parentRefs, normalizedRef.String())
return derefPathItem(pathItem, parentRefs, resolver, normalizedBasePath)
}
}
return nil
}
func expandPathItem(pathItem *PathItem, resolver *schemaLoader, basePath string) error {
if pathItem == nil {
return nil
}
if pathItem.Ref.String() != "" {
if err := resolver.Resolve(&pathItem.Ref, &pathItem, basePath); err != nil {
return err
}
pathItem.Ref = Ref{}
parentRefs := []string{}
if err := derefPathItem(pathItem, parentRefs, resolver, basePath); shouldStopOnError(err, resolver.options) {
return err
}
pathItem.Ref = Ref{}
parentRefs = parentRefs[0:]
for idx := range pathItem.Parameters {
if err := expandParameter(&(pathItem.Parameters[idx]), resolver, basePath); shouldStopOnError(err, resolver.options) {
@@ -842,36 +867,104 @@ func expandOperation(op *Operation, resolver *schemaLoader, basePath string) err
return nil
}
// ExpandResponse expands a response based on a basepath
// This is the exported version of expandResponse
// all refs inside response will be resolved relative to basePath
func ExpandResponse(response *Response, basePath string) error {
opts := &ExpandOptions{
RelativeBase: basePath,
}
resolver, err := defaultSchemaLoader(nil, opts, nil)
if err != nil {
return err
}
return expandResponse(response, resolver, basePath)
}
func derefResponse(response *Response, parentRefs []string, resolver *schemaLoader, basePath string) error {
curRef := response.Ref.String()
if curRef != "" {
/* Here the resolution scope is changed because a $ref was encountered */
normalizedRef := normalizeFileRef(&response.Ref, basePath)
normalizedBasePath := normalizedRef.RemoteURI()
if isCircular(normalizedRef, basePath, parentRefs...) {
return nil
}
if err := resolver.Resolve(&response.Ref, response, basePath); shouldStopOnError(err, resolver.options) {
return err
}
if response.Ref.String() != "" && response.Ref.String() != curRef && basePath != normalizedBasePath {
parentRefs = append(parentRefs, normalizedRef.String())
return derefResponse(response, parentRefs, resolver, normalizedBasePath)
}
}
return nil
}
func expandResponse(response *Response, resolver *schemaLoader, basePath string) error {
if response == nil {
return nil
}
var parentRefs []string
if response.Ref.String() != "" {
parentRefs = append(parentRefs, response.Ref.String())
sch := new(Schema)
b, _ := response.MarshalJSON()
json.Unmarshal(b, sch)
s, _ := expandSchema(*sch, parentRefs, resolver, basePath)
// if err := resolver.Resolve(&response.Ref, response, basePath); shouldStopOnError(err, resolver.options) {
// return err
// }
b, _ = s.MarshalJSON()
json.Unmarshal(b, response)
response.Ref = Ref{}
parentRefs := []string{}
if err := derefResponse(response, parentRefs, resolver, basePath); shouldStopOnError(err, resolver.options) {
return err
}
response.Ref = Ref{}
parentRefs = parentRefs[0:]
if !resolver.options.SkipSchemas && response.Schema != nil {
parentRefs = append(parentRefs, response.Schema.Ref.String())
debugLog("response ref: %s", response.Schema.Ref)
s, err := expandSchema(*response.Schema, parentRefs, resolver, basePath)
if shouldStopOnError(err, resolver.options) {
return err
}
*response.Schema = *s
}
return nil
}
// ExpandParameter expands a parameter based on a basepath
// This is the exported version of expandParameter
// all refs inside parameter will be resolved relative to basePath
func ExpandParameter(parameter *Parameter, basePath string) error {
opts := &ExpandOptions{
RelativeBase: basePath,
}
resolver, err := defaultSchemaLoader(nil, opts, nil)
if err != nil {
return err
}
return expandParameter(parameter, resolver, basePath)
}
func derefParameter(parameter *Parameter, parentRefs []string, resolver *schemaLoader, basePath string) error {
curRef := parameter.Ref.String()
if curRef != "" {
normalizedRef := normalizeFileRef(&parameter.Ref, basePath)
normalizedBasePath := normalizedRef.RemoteURI()
if isCircular(normalizedRef, basePath, parentRefs...) {
return nil
}
if err := resolver.Resolve(&parameter.Ref, parameter, basePath); shouldStopOnError(err, resolver.options) {
return err
}
if parameter.Ref.String() != "" && parameter.Ref.String() != curRef && basePath != normalizedBasePath {
parentRefs = append(parentRefs, normalizedRef.String())
return derefParameter(parameter, parentRefs, resolver, normalizedBasePath)
}
}
return nil
}
@@ -880,15 +973,13 @@ func expandParameter(parameter *Parameter, resolver *schemaLoader, basePath stri
return nil
}
var parentRefs []string
if parameter.Ref.String() != "" {
parentRefs = append(parentRefs, parameter.Ref.String())
if err := resolver.Resolve(&parameter.Ref, parameter, basePath); shouldStopOnError(err, resolver.options) {
return err
}
parameter.Ref = Ref{}
parentRefs := []string{}
if err := derefParameter(parameter, parentRefs, resolver, basePath); shouldStopOnError(err, resolver.options) {
return err
}
parameter.Ref = Ref{}
parentRefs = parentRefs[0:]
if !resolver.options.SkipSchemas && parameter.Schema != nil {
parentRefs = append(parentRefs, parameter.Schema.Ref.String())
s, err := expandSchema(*parameter.Schema, parentRefs, resolver, basePath)

View File

@@ -206,6 +206,47 @@ func TestResponseExpansion(t *testing.T) {
// assert.Equal(t, expected, resp)
}
// test the exported version of ExpandResponse
func TestExportedResponseExpansion(t *testing.T) {
specDoc, err := jsonDoc("fixtures/expansion/all-the-things.json")
assert.NoError(t, err)
basePath, err := absPath("fixtures/expansion/all-the-things.json")
assert.NoError(t, err)
spec := new(Swagger)
err = json.Unmarshal(specDoc, spec)
assert.NoError(t, err)
resp := spec.Responses["anotherPet"]
r := spec.Responses["petResponse"]
err = ExpandResponse(&r, basePath)
assert.NoError(t, err)
expected := r
err = ExpandResponse(&resp, basePath)
b, _ := resp.MarshalJSON()
log.Printf(string(b))
b, _ = expected.MarshalJSON()
log.Printf(string(b))
assert.NoError(t, err)
assert.Equal(t, expected, resp)
resp2 := spec.Paths.Paths["/"].Get.Responses.Default
expected = spec.Responses["stringResponse"]
err = ExpandResponse(resp2, basePath)
assert.NoError(t, err)
assert.Equal(t, expected, *resp2)
resp = spec.Paths.Paths["/"].Get.Responses.StatusCodeResponses[200]
expected = spec.Responses["petResponse"]
err = ExpandResponse(&resp, basePath)
assert.NoError(t, err)
// assert.Equal(t, expected, resp)
}
func TestIssue3(t *testing.T) {
spec := new(Swagger)
specDoc, err := jsonDoc("fixtures/expansion/overflow.json")
@@ -254,6 +295,32 @@ func TestParameterExpansion(t *testing.T) {
assert.Equal(t, expected, param)
}
func TestExportedParameterExpansion(t *testing.T) {
paramDoc, err := jsonDoc("fixtures/expansion/params.json")
assert.NoError(t, err)
spec := new(Swagger)
err = json.Unmarshal(paramDoc, spec)
assert.NoError(t, err)
basePath, err := absPath("fixtures/expansion/params.json")
assert.NoError(t, err)
param := spec.Parameters["query"]
expected := spec.Parameters["tag"]
err = ExpandParameter(&param, basePath)
assert.NoError(t, err)
assert.Equal(t, expected, param)
param = spec.Paths.Paths["/cars/{id}"].Parameters[0]
expected = spec.Parameters["id"]
err = ExpandParameter(&param, basePath)
assert.NoError(t, err)
assert.Equal(t, expected, param)
}
func TestCircularRefsExpansion(t *testing.T) {
carsDoc, err := jsonDoc("fixtures/expansion/circularRefs.json")
assert.NoError(t, err)
@@ -626,6 +693,71 @@ func TestDefaultResolutionCache(t *testing.T) {
assert.Equal(t, "here", sch)
}
func TestRelativeBaseURI(t *testing.T) {
server := httptest.NewServer(http.FileServer(http.Dir("fixtures/remote")))
defer server.Close()
spec := new(Swagger)
// resolver, err := defaultSchemaLoader(spec, nil, nil)
// assert.NoError(t, err)
err := ExpandSpec(spec, nil)
assert.NoError(t, err)
specDoc, err := jsonDoc("fixtures/remote/all-the-things.json")
assert.NoError(t, err)
opts := &ExpandOptions{
RelativeBase: server.URL + "/all-the-things.json",
}
spec = new(Swagger)
err = json.Unmarshal(specDoc, spec)
assert.NoError(t, err)
pet := spec.Definitions["pet"]
errorModel := spec.Definitions["errorModel"]
petResponse := spec.Responses["petResponse"]
petResponse.Schema = &pet
stringResponse := spec.Responses["stringResponse"]
tagParam := spec.Parameters["tag"]
idParam := spec.Parameters["idParam"]
anotherPet := spec.Responses["anotherPet"]
anotherPet.Ref = MustCreateRef(server.URL + "/" + anotherPet.Ref.String())
err = ExpandResponse(&anotherPet, opts.RelativeBase)
assert.NoError(t, err)
spec.Responses["anotherPet"] = anotherPet
circularA := spec.Responses["circularA"]
circularA.Ref = MustCreateRef(server.URL + "/" + circularA.Ref.String())
err = ExpandResponse(&circularA, opts.RelativeBase)
assert.NoError(t, err)
spec.Responses["circularA"] = circularA
err = ExpandSpec(spec, opts)
assert.NoError(t, err)
assert.Equal(t, tagParam, spec.Parameters["query"])
assert.Equal(t, petResponse, spec.Responses["petResponse"])
assert.Equal(t, petResponse, spec.Responses["anotherPet"])
assert.Equal(t, pet, *spec.Responses["petResponse"].Schema)
assert.Equal(t, stringResponse, *spec.Paths.Paths["/"].Get.Responses.Default)
assert.Equal(t, petResponse, spec.Paths.Paths["/"].Get.Responses.StatusCodeResponses[200])
assert.Equal(t, pet, *spec.Paths.Paths["/pets"].Get.Responses.StatusCodeResponses[200].Schema.Items.Schema)
assert.Equal(t, errorModel, *spec.Paths.Paths["/pets"].Get.Responses.Default.Schema)
assert.Equal(t, pet, spec.Definitions["petInput"].AllOf[0])
assert.Equal(t, spec.Definitions["petInput"], *spec.Paths.Paths["/pets"].Post.Parameters[0].Schema)
assert.Equal(t, petResponse, spec.Paths.Paths["/pets"].Post.Responses.StatusCodeResponses[200])
assert.Equal(t, errorModel, *spec.Paths.Paths["/pets"].Post.Responses.Default.Schema)
pi := spec.Paths.Paths["/pets/{id}"]
assert.Equal(t, idParam, pi.Get.Parameters[0])
assert.Equal(t, petResponse, pi.Get.Responses.StatusCodeResponses[200])
assert.Equal(t, errorModel, *pi.Get.Responses.Default.Schema)
assert.Equal(t, idParam, pi.Delete.Parameters[0])
assert.Equal(t, errorModel, *pi.Delete.Responses.Default.Schema)
}
func resolutionContextServer() *httptest.Server {
var servedAt string
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {

View File

@@ -145,7 +145,10 @@ func (r *Ref) UnmarshalJSON(d []byte) error {
if err := json.Unmarshal(d, &v); err != nil {
return err
}
return r.fromMap(v)
}
func (r *Ref) fromMap(v map[string]interface{}) error {
if v == nil {
return nil
}

View File

@@ -135,6 +135,10 @@ func (r *SchemaURL) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &v); err != nil {
return err
}
return r.fromMap(v)
}
func (r *SchemaURL) fromMap(v map[string]interface{}) error {
if v == nil {
return nil
}
@@ -582,18 +586,17 @@ func (s Schema) MarshalJSON() ([]byte, error) {
// UnmarshalJSON marshal this from JSON
func (s *Schema) UnmarshalJSON(data []byte) error {
var sch Schema
if err := json.Unmarshal(data, &sch.SchemaProps); err != nil {
props := struct {
SchemaProps
SwaggerSchemaProps
}{}
if err := json.Unmarshal(data, &props); err != nil {
return err
}
if err := json.Unmarshal(data, &sch.Ref); err != nil {
return err
}
if err := json.Unmarshal(data, &sch.Schema); err != nil {
return err
}
if err := json.Unmarshal(data, &sch.SwaggerSchemaProps); err != nil {
return err
sch := Schema{
SchemaProps: props.SchemaProps,
SwaggerSchemaProps: props.SwaggerSchemaProps,
}
var d map[string]interface{}
@@ -601,6 +604,9 @@ func (s *Schema) UnmarshalJSON(data []byte) error {
return err
}
sch.Ref.fromMap(d)
sch.Schema.fromMap(d)
delete(d, "$ref")
delete(d, "$schema")
for _, pn := range swag.DefaultJSONNameProvider.GetJSONNames(s) {

View File

@@ -203,3 +203,10 @@ func TestSchema(t *testing.T) {
}
}
func BenchmarkSchemaUnmarshal(b *testing.B) {
for i := 0; i < b.N; i++ {
sch := &Schema{}
sch.UnmarshalJSON([]byte(schemaJSON))
}
}

View File

@@ -19,6 +19,7 @@ import (
"io/ioutil"
"log"
"net/http"
"net/url"
"path/filepath"
"strings"
"time"
@@ -43,7 +44,10 @@ func LoadStrategy(path string, local, remote func(string) ([]byte, error)) func(
if strings.HasPrefix(path, "http") {
return remote
}
return func(pth string) ([]byte, error) { return local(filepath.FromSlash(pth)) }
return func(pth string) ([]byte, error) {
upth, _ := url.PathUnescape(pth)
return local(filepath.FromSlash(upth))
}
}
func loadHTTPBytes(timeout time.Duration) func(path string) ([]byte, error) {