Code refactoring for bpa operator
[icn.git] / cmd / bpa-operator / vendor / github.com / googleapis / gnostic / compiler / reader.go
1 // Copyright 2017 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package compiler
16
17 import (
18         "errors"
19         "fmt"
20         "gopkg.in/yaml.v2"
21         "io/ioutil"
22         "log"
23         "net/http"
24         "net/url"
25         "path/filepath"
26         "strings"
27 )
28
29 var fileCache map[string][]byte
30 var infoCache map[string]interface{}
31 var count int64
32
33 var verboseReader = false
34
35 func initializeFileCache() {
36         if fileCache == nil {
37                 fileCache = make(map[string][]byte, 0)
38         }
39 }
40
41 func initializeInfoCache() {
42         if infoCache == nil {
43                 infoCache = make(map[string]interface{}, 0)
44         }
45 }
46
47 // FetchFile gets a specified file from the local filesystem or a remote location.
48 func FetchFile(fileurl string) ([]byte, error) {
49         initializeFileCache()
50         bytes, ok := fileCache[fileurl]
51         if ok {
52                 if verboseReader {
53                         log.Printf("Cache hit %s", fileurl)
54                 }
55                 return bytes, nil
56         }
57         if verboseReader {
58                 log.Printf("Fetching %s", fileurl)
59         }
60         response, err := http.Get(fileurl)
61         if err != nil {
62                 return nil, err
63         }
64         if response.StatusCode != 200 {
65                 return nil, errors.New(fmt.Sprintf("Error downloading %s: %s", fileurl, response.Status))
66         }
67         defer response.Body.Close()
68         bytes, err = ioutil.ReadAll(response.Body)
69         if err == nil {
70                 fileCache[fileurl] = bytes
71         }
72         return bytes, err
73 }
74
75 // ReadBytesForFile reads the bytes of a file.
76 func ReadBytesForFile(filename string) ([]byte, error) {
77         // is the filename a url?
78         fileurl, _ := url.Parse(filename)
79         if fileurl.Scheme != "" {
80                 // yes, fetch it
81                 bytes, err := FetchFile(filename)
82                 if err != nil {
83                         return nil, err
84                 }
85                 return bytes, nil
86         }
87         // no, it's a local filename
88         bytes, err := ioutil.ReadFile(filename)
89         if err != nil {
90                 return nil, err
91         }
92         return bytes, nil
93 }
94
95 // ReadInfoFromBytes unmarshals a file as a yaml.MapSlice.
96 func ReadInfoFromBytes(filename string, bytes []byte) (interface{}, error) {
97         initializeInfoCache()
98         cachedInfo, ok := infoCache[filename]
99         if ok {
100                 if verboseReader {
101                         log.Printf("Cache hit info for file %s", filename)
102                 }
103                 return cachedInfo, nil
104         }
105         if verboseReader {
106                 log.Printf("Reading info for file %s", filename)
107         }
108         var info yaml.MapSlice
109         err := yaml.Unmarshal(bytes, &info)
110         if err != nil {
111                 return nil, err
112         }
113         if len(filename) > 0 {
114                 infoCache[filename] = info
115         }
116         return info, nil
117 }
118
119 // ReadInfoForRef reads a file and return the fragment needed to resolve a $ref.
120 func ReadInfoForRef(basefile string, ref string) (interface{}, error) {
121         initializeInfoCache()
122         {
123                 info, ok := infoCache[ref]
124                 if ok {
125                         if verboseReader {
126                                 log.Printf("Cache hit for ref %s#%s", basefile, ref)
127                         }
128                         return info, nil
129                 }
130         }
131         if verboseReader {
132                 log.Printf("Reading info for ref %s#%s", basefile, ref)
133         }
134         count = count + 1
135         basedir, _ := filepath.Split(basefile)
136         parts := strings.Split(ref, "#")
137         var filename string
138         if parts[0] != "" {
139                 filename = basedir + parts[0]
140         } else {
141                 filename = basefile
142         }
143         bytes, err := ReadBytesForFile(filename)
144         if err != nil {
145                 return nil, err
146         }
147         info, err := ReadInfoFromBytes(filename, bytes)
148         if err != nil {
149                 log.Printf("File error: %v\n", err)
150         } else {
151                 if len(parts) > 1 {
152                         path := strings.Split(parts[1], "/")
153                         for i, key := range path {
154                                 if i > 0 {
155                                         m, ok := info.(yaml.MapSlice)
156                                         if ok {
157                                                 found := false
158                                                 for _, section := range m {
159                                                         if section.Key == key {
160                                                                 info = section.Value
161                                                                 found = true
162                                                         }
163                                                 }
164                                                 if !found {
165                                                         infoCache[ref] = nil
166                                                         return nil, NewError(nil, fmt.Sprintf("could not resolve %s", ref))
167                                                 }
168                                         }
169                                 }
170                         }
171                 }
172         }
173         infoCache[ref] = info
174         return info, nil
175 }