diff --git a/internal/span/uri.go b/internal/span/uri.go index 3263437440..a273c01e91 100644 --- a/internal/span/uri.go +++ b/internal/span/uri.go @@ -8,6 +8,7 @@ import ( "fmt" "net/url" "os" + "path" "path/filepath" "runtime" "strings" @@ -30,6 +31,9 @@ func (uri URI) Filename() string { } func filename(uri URI) (string, error) { + if uri == "" { + return "", nil + } u, err := url.ParseRequestURI(string(uri)) if err != nil { return "", err @@ -56,28 +60,49 @@ func NewURI(s string) URI { } func CompareURI(a, b URI) int { - if a == b { + if equalURI(a, b) { return 0 } - // If we have the same URI basename, we may still have the same file URIs. - fa := a.Filename() - fb := b.Filename() - if strings.EqualFold(filepath.Base(fa), filepath.Base(fb)) { - // Stat the files to check if they are equal. - if infoa, err := os.Stat(fa); err == nil { - if infob, err := os.Stat(fb); err == nil { - if os.SameFile(infoa, infob) { - return 0 - } - } - } + if a < b { + return -1 } - return strings.Compare(fa, fb) + return 1 +} + +func equalURI(a, b URI) bool { + if a == b { + return true + } + // If we have the same URI basename, we may still have the same file URIs. + if !strings.EqualFold(path.Base(string(a)), path.Base(string(b))) { + return false + } + fa, err := filename(a) + if err != nil { + return false + } + fb, err := filename(b) + if err != nil { + return false + } + // Stat the files to check if they are equal. + infoa, err := os.Stat(filepath.FromSlash(fa)) + if err != nil { + return false + } + infob, err := os.Stat(filepath.FromSlash(fb)) + if err != nil { + return false + } + return os.SameFile(infoa, infob) } // FileURI returns a span URI for the supplied file path. // It will always have the file scheme. func FileURI(path string) URI { + if path == "" { + return "" + } // Handle standard library paths that contain the literal "$GOROOT". // TODO(rstambler): The go/packages API should allow one to determine a user's $GOROOT. const prefix = "$GOROOT" diff --git a/internal/span/uri_test.go b/internal/span/uri_test.go index 7b7c8b9011..36dd1997e2 100644 --- a/internal/span/uri_test.go +++ b/internal/span/uri_test.go @@ -17,6 +17,7 @@ import ( // functions filepath.ToSlash and filepath.FromSlash do not need testing. func TestURI(t *testing.T) { for _, test := range []string{ + ``, `C:/Windows/System32`, `C:/Go/src/bob.go`, `c:/Go/src/bob.go`, @@ -25,16 +26,18 @@ func TestURI(t *testing.T) { } { testPath := filepath.FromSlash(test) expectPath := testPath - if test[0] == '/' { + if len(test) > 0 && test[0] == '/' { if abs, err := filepath.Abs(expectPath); err == nil { expectPath = abs } } expectURI := filepath.ToSlash(expectPath) - if expectURI[0] != '/' { - expectURI = "/" + expectURI + if len(expectURI) > 0 { + if expectURI[0] != '/' { + expectURI = "/" + expectURI + } + expectURI = "file://" + expectURI } - expectURI = "file://" + expectURI uri := span.FileURI(testPath) if expectURI != string(uri) { t.Errorf("ToURI: expected %s, got %s", expectURI, uri)