Платформа ЦРНП "Мирокод" для разработки проектов
https://git.mirocod.ru
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
152 lines
4.7 KiB
152 lines
4.7 KiB
// Copyright 2015 go-swagger maintainers |
|
// |
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
|
// you may not use this file except in compliance with the License. |
|
// You may obtain a copy of the License at |
|
// |
|
// http://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, |
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
// See the License for the specific language governing permissions and |
|
// limitations under the License. |
|
|
|
package spec |
|
|
|
import ( |
|
"fmt" |
|
"net/url" |
|
"os" |
|
"path" |
|
"path/filepath" |
|
"strings" |
|
) |
|
|
|
// 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 |
|
// 2) if refPath is relative, join it with basePath keeping the scheme, hosts, and ports if exists |
|
// base could be a directory or a full file path |
|
func normalizePaths(refPath, base string) string { |
|
refURL, _ := url.Parse(refPath) |
|
if path.IsAbs(refURL.Path) || filepath.IsAbs(refPath) { |
|
// refPath is actually absolute |
|
if refURL.Host != "" { |
|
return refPath |
|
} |
|
parts := strings.Split(refPath, "#") |
|
result := filepath.FromSlash(parts[0]) |
|
if len(parts) == 2 { |
|
result += "#" + parts[1] |
|
} |
|
return result |
|
} |
|
|
|
// relative refPath |
|
baseURL, _ := url.Parse(base) |
|
if !strings.HasPrefix(refPath, "#") { |
|
// combining paths |
|
if baseURL.Host != "" { |
|
baseURL.Path = path.Join(path.Dir(baseURL.Path), refURL.Path) |
|
} else { // base is a file |
|
newBase := fmt.Sprintf("%s#%s", filepath.Join(filepath.Dir(base), filepath.FromSlash(refURL.Path)), refURL.Fragment) |
|
return newBase |
|
} |
|
|
|
} |
|
// copying fragment from ref to base |
|
baseURL.Fragment = refURL.Fragment |
|
return baseURL.String() |
|
} |
|
|
|
// denormalizePaths returns to simplest notation on file $ref, |
|
// i.e. strips the absolute path and sets a path relative to the base path. |
|
// |
|
// This is currently used when we rewrite ref after a circular ref has been detected |
|
func denormalizeFileRef(ref *Ref, relativeBase, originalRelativeBase string) *Ref { |
|
debugLog("denormalizeFileRef for: %s", ref.String()) |
|
|
|
if ref.String() == "" || ref.IsRoot() || ref.HasFragmentOnly { |
|
return ref |
|
} |
|
// strip relativeBase from URI |
|
relativeBaseURL, _ := url.Parse(relativeBase) |
|
relativeBaseURL.Fragment = "" |
|
|
|
if relativeBaseURL.IsAbs() && strings.HasPrefix(ref.String(), relativeBase) { |
|
// this should work for absolute URI (e.g. http://...): we have an exact match, just trim prefix |
|
r, _ := NewRef(strings.TrimPrefix(ref.String(), relativeBase)) |
|
return &r |
|
} |
|
|
|
if relativeBaseURL.IsAbs() { |
|
// other absolute URL get unchanged (i.e. with a non-empty scheme) |
|
return ref |
|
} |
|
|
|
// for relative file URIs: |
|
originalRelativeBaseURL, _ := url.Parse(originalRelativeBase) |
|
originalRelativeBaseURL.Fragment = "" |
|
if strings.HasPrefix(ref.String(), originalRelativeBaseURL.String()) { |
|
// the resulting ref is in the expanded spec: return a local ref |
|
r, _ := NewRef(strings.TrimPrefix(ref.String(), originalRelativeBaseURL.String())) |
|
return &r |
|
} |
|
|
|
// check if we may set a relative path, considering the original base path for this spec. |
|
// Example: |
|
// spec is located at /mypath/spec.json |
|
// my normalized ref points to: /mypath/item.json#/target |
|
// expected result: item.json#/target |
|
parts := strings.Split(ref.String(), "#") |
|
relativePath, err := filepath.Rel(path.Dir(originalRelativeBaseURL.String()), parts[0]) |
|
if err != nil { |
|
// there is no common ancestor (e.g. different drives on windows) |
|
// leaves the ref unchanged |
|
return ref |
|
} |
|
if len(parts) == 2 { |
|
relativePath += "#" + parts[1] |
|
} |
|
r, _ := NewRef(relativePath) |
|
return &r |
|
} |
|
|
|
// relativeBase could be an ABSOLUTE file path or an ABSOLUTE URL |
|
func normalizeFileRef(ref *Ref, relativeBase string) *Ref { |
|
// This is important for when the reference is pointing to the root schema |
|
if ref.String() == "" { |
|
r, _ := NewRef(relativeBase) |
|
return &r |
|
} |
|
|
|
debugLog("normalizing %s against %s", ref.String(), relativeBase) |
|
|
|
s := normalizePaths(ref.String(), relativeBase) |
|
r, _ := NewRef(s) |
|
return &r |
|
} |
|
|
|
// 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 |
|
} |
|
wd, err := os.Getwd() |
|
return filepath.Join(wd, fname), err |
|
}
|
|
|