1 // Copyright 2015 go-swagger maintainers
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
26 // normalize absolute path for cache.
27 // on Windows, drive letters should be converted to lower as scheme in net/url.URL
28 func normalizeAbsPath(path string) string {
29 u, err := url.Parse(path)
31 debugLog("normalize absolute path failed: %s", err)
37 // base or refPath could be a file path or a URL
38 // given a base absolute path and a ref path, return the absolute path of refPath
39 // 1) if refPath is absolute, return it
40 // 2) if refPath is relative, join it with basePath keeping the scheme, hosts, and ports if exists
41 // base could be a directory or a full file path
42 func normalizePaths(refPath, base string) string {
43 refURL, _ := url.Parse(refPath)
44 if path.IsAbs(refURL.Path) || filepath.IsAbs(refPath) {
45 // refPath is actually absolute
46 if refURL.Host != "" {
49 parts := strings.Split(refPath, "#")
50 result := filepath.FromSlash(parts[0])
52 result += "#" + parts[1]
58 baseURL, _ := url.Parse(base)
59 if !strings.HasPrefix(refPath, "#") {
61 if baseURL.Host != "" {
62 baseURL.Path = path.Join(path.Dir(baseURL.Path), refURL.Path)
63 } else { // base is a file
64 newBase := fmt.Sprintf("%s#%s", filepath.Join(filepath.Dir(base), filepath.FromSlash(refURL.Path)), refURL.Fragment)
69 // copying fragment from ref to base
70 baseURL.Fragment = refURL.Fragment
71 return baseURL.String()
74 // denormalizePaths returns to simplest notation on file $ref,
75 // i.e. strips the absolute path and sets a path relative to the base path.
77 // This is currently used when we rewrite ref after a circular ref has been detected
78 func denormalizeFileRef(ref *Ref, relativeBase, originalRelativeBase string) *Ref {
79 debugLog("denormalizeFileRef for: %s", ref.String())
81 if ref.String() == "" || ref.IsRoot() || ref.HasFragmentOnly {
84 // strip relativeBase from URI
85 relativeBaseURL, _ := url.Parse(relativeBase)
86 relativeBaseURL.Fragment = ""
88 if relativeBaseURL.IsAbs() && strings.HasPrefix(ref.String(), relativeBase) {
89 // this should work for absolute URI (e.g. http://...): we have an exact match, just trim prefix
90 r, _ := NewRef(strings.TrimPrefix(ref.String(), relativeBase))
94 if relativeBaseURL.IsAbs() {
95 // other absolute URL get unchanged (i.e. with a non-empty scheme)
99 // for relative file URIs:
100 originalRelativeBaseURL, _ := url.Parse(originalRelativeBase)
101 originalRelativeBaseURL.Fragment = ""
102 if strings.HasPrefix(ref.String(), originalRelativeBaseURL.String()) {
103 // the resulting ref is in the expanded spec: return a local ref
104 r, _ := NewRef(strings.TrimPrefix(ref.String(), originalRelativeBaseURL.String()))
108 // check if we may set a relative path, considering the original base path for this spec.
110 // spec is located at /mypath/spec.json
111 // my normalized ref points to: /mypath/item.json#/target
112 // expected result: item.json#/target
113 parts := strings.Split(ref.String(), "#")
114 relativePath, err := filepath.Rel(path.Dir(originalRelativeBaseURL.String()), parts[0])
116 // there is no common ancestor (e.g. different drives on windows)
117 // leaves the ref unchanged
121 relativePath += "#" + parts[1]
123 r, _ := NewRef(relativePath)
127 // relativeBase could be an ABSOLUTE file path or an ABSOLUTE URL
128 func normalizeFileRef(ref *Ref, relativeBase string) *Ref {
129 // This is important for when the reference is pointing to the root schema
130 if ref.String() == "" {
131 r, _ := NewRef(relativeBase)
135 debugLog("normalizing %s against %s", ref.String(), relativeBase)
137 s := normalizePaths(ref.String(), relativeBase)
142 // absPath returns the absolute path of a file
143 func absPath(fname string) (string, error) {
144 if strings.HasPrefix(fname, "http") {
147 if filepath.IsAbs(fname) {
150 wd, err := os.Getwd()
151 return filepath.Join(wd, fname), err