Skip to content

Commit

Permalink
Fix URI parsing for Windows paths
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko committed Apr 29, 2020
1 parent 2ef54dd commit de774d3
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 17 deletions.
4 changes: 1 addition & 3 deletions internal/filesystem/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ func NewFile(fullPath string, content []byte) *file {
return &file{fullPath: fullPath, content: content}
}

const uriPrefix = "file://"

func (f *file) FullPath() string {
return f.fullPath
}
Expand All @@ -39,7 +37,7 @@ func (f *file) Filename() string {
}

func (f *file) URI() string {
return uriPrefix + f.fullPath
return URIFromPath(f.fullPath)
}

func (f *file) Lines() source.Lines {
Expand Down
17 changes: 17 additions & 0 deletions internal/filesystem/uri.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package filesystem

import (
"net/url"
"path/filepath"
)

func URIFromPath(path string) string {
p := filepath.ToSlash(path)
p = wrapPath(p)

u := &url.URL{
Scheme: "file",
Path: p,
}
return u.String()
}
8 changes: 8 additions & 0 deletions internal/filesystem/uri_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// +build !windows

package filesystem

// wrapPath is no-op for unix-style paths
func wrapPath(path string) string {
return path
}
18 changes: 18 additions & 0 deletions internal/filesystem/uri_unix_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// +build !windows

package filesystem

import (
"testing"
)

func TestURIFromPath(t *testing.T) {
path := "/random/path"
uri := URIFromPath(path)

expectedURI := "file:///random/path"
if uri != expectedURI {
t.Fatalf("URI doesn't match.\nExpected: %q\nGiven: %q",
expectedURI, uri)
}
}
8 changes: 8 additions & 0 deletions internal/filesystem/uri_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package filesystem

// wrapPath prepends Windows-style paths (C:\path)
// with an additional slash to account for an empty hostname
// in a valid file-scheme URI per RFC 8089
func wrapPath(path string) string {
return "/" + path
}
16 changes: 16 additions & 0 deletions internal/filesystem/uri_windows_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package filesystem

import (
"testing"
)

func TestURIFromPath(t *testing.T) {
path := `C:\Users\With Space\file.tf`
uri := URIFromPath(path)

expectedURI := "file:///C:/Users/With%20Space/file.tf"
if uri != expectedURI {
t.Fatalf("URI doesn't match.\nExpected: %q\nGiven: %q",
expectedURI, uri)
}
}
28 changes: 16 additions & 12 deletions internal/lsp/file_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,40 @@ package lsp
import (
"net/url"
"path/filepath"
"strings"

"github.com/hashicorp/terraform-ls/internal/filesystem"
"github.com/sourcegraph/go-lsp"
)

const uriPrefix = "file://"

type FileHandler string

func (fh FileHandler) Valid() bool {
if !strings.HasPrefix(string(fh), uriPrefix) {
return false
}
p := string(fh[len(uriPrefix):])
_, err := url.PathUnescape(p)
_, err := fh.parsePath()
if err != nil {
return false
}

return true
}

func (fh FileHandler) FullPath() string {
if !fh.Valid() {
p, err := fh.parsePath()
if err != nil {
panic("invalid uri")
}
p := string(fh[len(uriPrefix):])
p, _ = url.PathUnescape(p)

return filepath.FromSlash(p)
}

func (fh FileHandler) parsePath() (string, error) {
u, err := url.ParseRequestURI(string(fh))
if err != nil {
return "", err
}

return url.PathUnescape(u.Path)
}

func (fh FileHandler) Dir() string {
return filepath.Dir(fh.FullPath())
}
Expand Down Expand Up @@ -66,5 +70,5 @@ func (fh *versionedFileHandler) Version() int {
}

func FileHandlerFromPath(path string) FileHandler {
return FileHandler(uriPrefix + filepath.ToSlash(path))
return FileHandler(filesystem.URIFromPath(path))
}
4 changes: 2 additions & 2 deletions internal/lsp/file_handler_windows_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ func TestFileHandler_valid_windows(t *testing.T) {
t.Fatalf("Expected %q to be valid", path)
}

expectedDir := `\C:\Users\With Space\tf-test`
expectedDir := `C:\Users\With Space\tf-test`
if fh.Dir() != expectedDir {
t.Fatalf("Expected dir: %q, given: %q",
expectedDir, fh.Dir())
Expand All @@ -23,7 +23,7 @@ func TestFileHandler_valid_windows(t *testing.T) {
expectedFilename, fh.Filename())
}

expectedFullPath := `\C:\Users\With Space\tf-test\file.tf`
expectedFullPath := `C:\Users\With Space\tf-test\file.tf`
if fh.FullPath() != expectedFullPath {
t.Fatalf("Expected full path: %q, given: %q",
expectedFullPath, fh.FullPath())
Expand Down

0 comments on commit de774d3

Please sign in to comment.