diff --git a/client.go b/client.go index 4f72ad37..7dcb2ab2 100644 --- a/client.go +++ b/client.go @@ -15,7 +15,7 @@ import ( "path/filepath" "strings" - urlhelper "github.com/hashicorp/terraform/helper/url" + urlhelper "github.com/hashicorp/go-getter/helper/url" ) // Client is a client for downloading things. diff --git a/detect.go b/detect.go index 84844cae..481b737c 100644 --- a/detect.go +++ b/detect.go @@ -4,7 +4,7 @@ import ( "fmt" "path/filepath" - "github.com/hashicorp/terraform/helper/url" + "github.com/hashicorp/go-getter/helper/url" ) // Detector defines the interface that an invalid URL or a URL with a blank diff --git a/get_git.go b/get_git.go index 73aae8a6..1bf0dc7e 100644 --- a/get_git.go +++ b/get_git.go @@ -8,7 +8,7 @@ import ( "os/exec" "path/filepath" - urlhelper "github.com/hashicorp/terraform/helper/url" + urlhelper "github.com/hashicorp/go-getter/helper/url" ) // GitGetter is a Getter implementation that will download a module from diff --git a/get_hg.go b/get_hg.go index 08b59b63..eb170d10 100644 --- a/get_hg.go +++ b/get_hg.go @@ -9,7 +9,7 @@ import ( "path/filepath" "runtime" - urlhelper "github.com/hashicorp/terraform/helper/url" + urlhelper "github.com/hashicorp/go-getter/helper/url" ) // HgGetter is a Getter implementation that will download a module from diff --git a/helper/url/url.go b/helper/url/url.go new file mode 100644 index 00000000..02497c25 --- /dev/null +++ b/helper/url/url.go @@ -0,0 +1,14 @@ +package url + +import ( + "net/url" +) + +// Parse parses rawURL into a URL structure. +// The rawURL may be relative or absolute. +// +// Parse is a wrapper for the Go stdlib net/url Parse function, but returns +// Windows "safe" URLs on Windows platforms. +func Parse(rawURL string) (*url.URL, error) { + return parse(rawURL) +} diff --git a/helper/url/url_test.go b/helper/url/url_test.go new file mode 100644 index 00000000..ce3226b4 --- /dev/null +++ b/helper/url/url_test.go @@ -0,0 +1,88 @@ +package url + +import ( + "runtime" + "testing" +) + +type parseTest struct { + rawURL string + scheme string + host string + path string + str string + err bool +} + +var parseTests = []parseTest{ + { + rawURL: "/foo/bar", + scheme: "", + host: "", + path: "/foo/bar", + str: "/foo/bar", + err: false, + }, + { + rawURL: "file:///dir/", + scheme: "file", + host: "", + path: "/dir/", + str: "file:///dir/", + err: false, + }, +} + +var winParseTests = []parseTest{ + { + rawURL: `C:\`, + scheme: ``, + host: ``, + path: `C:/`, + str: `C:/`, + err: false, + }, + { + rawURL: `file://C:\`, + scheme: `file`, + host: ``, + path: `C:/`, + str: `file://C:/`, + err: false, + }, + { + rawURL: `file:///C:\`, + scheme: `file`, + host: ``, + path: `C:/`, + str: `file://C:/`, + err: false, + }, +} + +func TestParse(t *testing.T) { + if runtime.GOOS == "windows" { + parseTests = append(parseTests, winParseTests...) + } + for i, pt := range parseTests { + url, err := Parse(pt.rawURL) + if err != nil && !pt.err { + t.Errorf("test %d: unexpected error: %s", i, err) + } + if err == nil && pt.err { + t.Errorf("test %d: expected an error", i) + } + if url.Scheme != pt.scheme { + t.Errorf("test %d: expected Scheme = %q, got %q", i, pt.scheme, url.Scheme) + } + if url.Host != pt.host { + t.Errorf("test %d: expected Host = %q, got %q", i, pt.host, url.Host) + } + if url.Path != pt.path { + t.Errorf("test %d: expected Path = %q, got %q", i, pt.path, url.Path) + } + if url.String() != pt.str { + t.Errorf("test %d: expected url.String() = %q, got %q", i, pt.str, url.String()) + } + } +} diff --git a/helper/url/url_unix.go b/helper/url/url_unix.go new file mode 100644 index 00000000..ed1352a9 --- /dev/null +++ b/helper/url/url_unix.go @@ -0,0 +1,11 @@ +// +build !windows + +package url + +import ( + "net/url" +) + +func parse(rawURL string) (*url.URL, error) { + return url.Parse(rawURL) +} diff --git a/helper/url/url_windows.go b/helper/url/url_windows.go new file mode 100644 index 00000000..4655226f --- /dev/null +++ b/helper/url/url_windows.go @@ -0,0 +1,40 @@ +package url + +import ( + "fmt" + "net/url" + "path/filepath" + "strings" +) + +func parse(rawURL string) (*url.URL, error) { + // Make sure we're using "/" since URLs are "/"-based. + rawURL = filepath.ToSlash(rawURL) + + u, err := url.Parse(rawURL) + if err != nil { + return nil, err + } + + if len(rawURL) > 1 && rawURL[1] == ':' { + // Assume we're dealing with a drive letter file path where the drive + // letter has been parsed into the URL Scheme, and the rest of the path + // has been parsed into the URL Path without the leading ':' character. + u.Path = fmt.Sprintf("%s:%s", string(rawURL[0]), u.Path) + u.Scheme = "" + } + + if len(u.Host) > 1 && u.Host[1] == ':' && strings.HasPrefix(rawURL, "file://") { + // Assume we're dealing with a drive letter file path where the drive + // letter has been parsed into the URL Host. + u.Path = fmt.Sprintf("%s%s", u.Host, u.Path) + u.Host = "" + } + + // Remove leading slash for absolute file paths. + if len(u.Path) > 2 && u.Path[0] == '/' && u.Path[2] == ':' { + u.Path = u.Path[1:] + } + + return u, err +} diff --git a/module_test.go b/module_test.go index baf8d7f7..332f34ef 100644 --- a/module_test.go +++ b/module_test.go @@ -8,8 +8,8 @@ import ( "reflect" "testing" + urlhelper "github.com/hashicorp/go-getter/helper/url" "github.com/hashicorp/terraform/config" - urlhelper "github.com/hashicorp/terraform/helper/url" ) const fixtureDir = "./test-fixtures"