diff --git a/config/module/detect_file.go b/config/module/detect_file.go index 68ff43913..4aa21ffa2 100644 --- a/config/module/detect_file.go +++ b/config/module/detect_file.go @@ -21,13 +21,5 @@ func (d *FileDetector) Detect(src, pwd string) (string, bool, error) { src = filepath.Join(pwd, src) } - // Make sure we're using "/" even on Windows. URLs are "/"-based. - src = filepath.ToSlash(src) - - // Make sure that we don't start with "/" since we add that below - if src[0] == '/' { - src = src[1:] - } - - return fmt.Sprintf("file:///%s", src), true, nil + return fmtFileURL(src), true, nil } diff --git a/config/module/get.go b/config/module/get.go index bf7cf1acc..abc724b58 100644 --- a/config/module/get.go +++ b/config/module/get.go @@ -72,7 +72,7 @@ func Get(dst, src string) error { dst = tmpDir } - u, err := url.Parse(src) + u, err := urlParse(src) if err != nil { return err } diff --git a/config/module/module_test.go b/config/module/module_test.go index c63fa0201..88a595cd3 100644 --- a/config/module/module_test.go +++ b/config/module/module_test.go @@ -39,15 +39,11 @@ func testModule(n string) string { if err != nil { panic(err) } - - var url url.URL - url.Scheme = "file" - url.Path = filepath.ToSlash(p) - return url.String() + return fmtFileURL(p) } func testModuleURL(n string) *url.URL { - u, err := url.Parse(testModule(n)) + u, err := urlParse(testModule(n)) if err != nil { panic(err) } diff --git a/config/module/url_helper.go b/config/module/url_helper.go new file mode 100644 index 000000000..061496270 --- /dev/null +++ b/config/module/url_helper.go @@ -0,0 +1,50 @@ +package module + +import ( + "fmt" + "net/url" + "path/filepath" + "runtime" +) + +func urlParse(rawURL string) (*url.URL, error) { + if runtime.GOOS == "windows" { + // Make sure we're using "/" on Windows. URLs are "/"-based. + rawURL = filepath.ToSlash(rawURL) + } + u, err := url.Parse(rawURL) + if err != nil { + return nil, err + } + + if runtime.GOOS != "windows" { + return u, err + } + + if u.Scheme != "file" { + return u, err + } + + // Remove leading slash for absolute file paths on Windows. + // For example, url.Parse yields u.Path = "/C:/Users/user" for + // rawurl = "file:///C:/Users/user", which is an incorrect syntax. + if len(u.Path) > 2 && u.Path[0] == '/' && u.Path[2] == ':' { + u.Path = u.Path[1:] + } + + return u, err +} + +func fmtFileURL(path string) string { + if runtime.GOOS == "windows" { + // Make sure we're using "/" on Windows. URLs are "/"-based. + path = filepath.ToSlash(path) + } + + // Make sure that we don't start with "/" since we add that below. + if path[0] == '/' { + path = path[1:] + } + + return fmt.Sprintf("file:///%s", path) +}