podman
134 строки · 2.9 Кб
1package loads
2
3import (
4"encoding/json"
5"errors"
6"net/url"
7
8"github.com/go-openapi/spec"
9"github.com/go-openapi/swag"
10)
11
12var (
13// Default chain of loaders, defined at the package level.
14//
15// By default this matches json and yaml documents.
16//
17// May be altered with AddLoader().
18loaders *loader
19)
20
21func init() {
22jsonLoader := &loader{
23DocLoaderWithMatch: DocLoaderWithMatch{
24Match: func(pth string) bool {
25return true
26},
27Fn: JSONDoc,
28},
29}
30
31loaders = jsonLoader.WithHead(&loader{
32DocLoaderWithMatch: DocLoaderWithMatch{
33Match: swag.YAMLMatcher,
34Fn: swag.YAMLDoc,
35},
36})
37
38// sets the global default loader for go-openapi/spec
39spec.PathLoader = loaders.Load
40}
41
42// DocLoader represents a doc loader type
43type DocLoader func(string) (json.RawMessage, error)
44
45// DocMatcher represents a predicate to check if a loader matches
46type DocMatcher func(string) bool
47
48// DocLoaderWithMatch describes a loading function for a given extension match.
49type DocLoaderWithMatch struct {
50Fn DocLoader
51Match DocMatcher
52}
53
54// NewDocLoaderWithMatch builds a DocLoaderWithMatch to be used in load options
55func NewDocLoaderWithMatch(fn DocLoader, matcher DocMatcher) DocLoaderWithMatch {
56return DocLoaderWithMatch{
57Fn: fn,
58Match: matcher,
59}
60}
61
62type loader struct {
63DocLoaderWithMatch
64Next *loader
65}
66
67// WithHead adds a loader at the head of the current stack
68func (l *loader) WithHead(head *loader) *loader {
69if head == nil {
70return l
71}
72head.Next = l
73return head
74}
75
76// WithNext adds a loader at the trail of the current stack
77func (l *loader) WithNext(next *loader) *loader {
78l.Next = next
79return next
80}
81
82// Load the raw document from path
83func (l *loader) Load(path string) (json.RawMessage, error) {
84_, erp := url.Parse(path)
85if erp != nil {
86return nil, erp
87}
88
89var lastErr error = errors.New("no loader matched") // default error if no match was found
90for ldr := l; ldr != nil; ldr = ldr.Next {
91if ldr.Match != nil && !ldr.Match(path) {
92continue
93}
94
95// try then move to next one if there is an error
96b, err := ldr.Fn(path)
97if err == nil {
98return b, nil
99}
100
101lastErr = err
102}
103
104return nil, lastErr
105}
106
107// JSONDoc loads a json document from either a file or a remote url
108func JSONDoc(path string) (json.RawMessage, error) {
109data, err := swag.LoadFromFileOrHTTP(path)
110if err != nil {
111return nil, err
112}
113return json.RawMessage(data), nil
114}
115
116// AddLoader for a document, executed before other previously set loaders.
117//
118// This sets the configuration at the package level.
119//
120// NOTE:
121// * this updates the default loader used by github.com/go-openapi/spec
122// * since this sets package level globals, you shouln't call this concurrently
123//
124func AddLoader(predicate DocMatcher, load DocLoader) {
125loaders = loaders.WithHead(&loader{
126DocLoaderWithMatch: DocLoaderWithMatch{
127Match: predicate,
128Fn: load,
129},
130})
131
132// sets the global default loader for go-openapi/spec
133spec.PathLoader = loaders.Load
134}
135